jvm.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package ebpftracer
  2. import (
  3. "errors"
  4. "github.com/coroot/coroot-node-agent/common"
  5. "github.com/coroot/coroot-node-agent/ebpftracer/tracer/inject"
  6. "io/ioutil"
  7. "runtime"
  8. "strings"
  9. "debug/elf"
  10. "fmt"
  11. "path/filepath"
  12. "github.com/cilium/ebpf/link"
  13. "github.com/coroot/coroot-node-agent/proc"
  14. "golang.org/x/arch/arm64/arm64asm"
  15. "golang.org/x/arch/x86/x86asm"
  16. )
  17. const (
  18. // goServeHTTP = "net/http.serverHandler.ServeHTTP"
  19. // binPath = "/root/code/jdk8u/build/linux-x86_64-normal-server-release/jdk/lib/amd64/libnio.so"
  20. symbolsocketRead0 = "Java_sun_nio_ch_FileDispatcherImpl_read0"
  21. )
  22. func (t *Tracer) AttachJavaNioReadUprobes(pid uint32, codeType common.CodeType) ([]link.Link, error) {
  23. if t.DisableL7Tracing() {
  24. return nil, nil
  25. }
  26. var links []link.Link
  27. var bpath = ""
  28. // JavaAOT 逻辑
  29. if codeType.IsJavaAotCode() {
  30. bpath = proc.Path(uint32(pid), "exe")
  31. } else {
  32. version := UsePIDToGetJDKVersion(pid)
  33. fmt.Println("java version is ", version)
  34. bpath = getSoPath(pid, "libnio.so")
  35. if bpath == "" {
  36. return nil, errors.New("can not find nio.so")
  37. }
  38. }
  39. fmt.Println("find the nio.so path is ", bpath)
  40. ex, err := link.OpenExecutable(bpath)
  41. if err != nil {
  42. return nil, err
  43. }
  44. ef, err := elf.Open(bpath)
  45. if err != nil {
  46. return nil, err
  47. //PID: int(pid),
  48. }
  49. defer ef.Close()
  50. symbols, err := ef.DynamicSymbols()
  51. if err != nil {
  52. if errors.Is(err, elf.ErrNoSymbols) {
  53. return nil, err
  54. }
  55. return nil, err
  56. }
  57. textSection := ef.Section(".text")
  58. if textSection == nil {
  59. return nil, errors.New("can not find .text section")
  60. }
  61. textSectionData, err := textSection.Data()
  62. if err != nil {
  63. return nil, err
  64. }
  65. textSectionLen := uint64(len(textSectionData) - 1)
  66. // opt := link.UprobeOptions{
  67. // Offset: 61,
  68. // }
  69. // upread02, err := ex.Uprobe(symbolsocketRead0, t.uprobes["uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0"], &opt)
  70. // if err != nil {
  71. // return nil
  72. // }
  73. // links = append(links, upread01)
  74. for _, s := range symbols {
  75. if elf.ST_TYPE(s.Info) != elf.STT_FUNC || s.Size == 0 {
  76. continue
  77. }
  78. switch s.Name {
  79. case symbolsocketRead0:
  80. default:
  81. continue
  82. }
  83. address := s.Value
  84. for _, p := range ef.Progs {
  85. if p.Type != elf.PT_LOAD || (p.Flags&elf.PF_X) == 0 {
  86. continue
  87. }
  88. if p.Vaddr <= s.Value && s.Value < (p.Vaddr+p.Memsz) {
  89. address = s.Value - p.Vaddr + p.Off
  90. break
  91. }
  92. }
  93. fmt.Println("s.Name-----:", s.Name)
  94. switch s.Name {
  95. case symbolsocketRead0:
  96. sStart := s.Value - textSection.Addr
  97. sEnd := sStart + s.Size
  98. if sEnd > textSectionLen {
  99. continue
  100. }
  101. sBytes := textSectionData[sStart:sEnd]
  102. returnOffsets := getCallNextMoveOffsets(ef.Machine, sBytes)
  103. if len(returnOffsets) == 0 {
  104. return nil, fmt.Errorf("failed to attach uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0 uprobe")
  105. }
  106. for _, offset := range returnOffsets {
  107. l, err := ex.Uprobe(s.Name, t.uprobes["uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0"], &link.UprobeOptions{Address: address, Offset: uint64(offset), PID: int(pid)})
  108. if err != nil {
  109. return nil, fmt.Errorf("failed to attach uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0 uprobe")
  110. }
  111. links = append(links, l)
  112. }
  113. }
  114. }
  115. if len(links) == 0 {
  116. return nil, fmt.Errorf("no links found for %s", bpath)
  117. }
  118. fmt.Println("[jvm] libnio attached, pid is ", pid)
  119. return links, nil
  120. }
  121. func (t *Tracer) AttachJavaNetWriteUprobes(pid uint32) ([]link.Link, error) {
  122. if t.DisableL7Tracing() {
  123. return nil, nil
  124. }
  125. // 关闭横向串联
  126. if t.DisableE2ETracing() {
  127. return nil, nil
  128. }
  129. //inject
  130. originFunc := "Java_java_net_SocketOutputStream_socketWrite0"
  131. uProbeData := inject.UprobeData{
  132. Offset: 53,
  133. Func: originFunc,
  134. ELFPath: "/root/cwlibnet.so",
  135. }
  136. if runtime.GOARCH == "arm64" {
  137. uProbeData = inject.UprobeData{
  138. Offset: 8,
  139. Func: "CW_" + originFunc,
  140. ELFPath: "/root/cwlibnet.so",
  141. }
  142. }
  143. jvmInjector := &inject.JvmInjector{
  144. Pid: int(pid),
  145. ReleaseLibNetInfo: inject.LibNetInfo{
  146. LibName: "libnet.so",
  147. FuncSymbol: inject.InstInfo{
  148. SymName: originFunc,
  149. },
  150. },
  151. DebugLibNetInfo: inject.LibNetInfo{
  152. // TODO 根据版本设置
  153. LibName: filepath.Base(uProbeData.ELFPath),
  154. // TODO 根据版本设置
  155. LibPath: uProbeData.ELFPath,
  156. FuncSymbol: inject.InstInfo{
  157. SymName: uProbeData.Func,
  158. },
  159. },
  160. RecodeInfo: inject.LibNetInfo{FuncSymbol: inject.InstInfo{SymName: "CW_RECODE_" + originFunc}},
  161. Uprobe: uProbeData,
  162. }
  163. err := inject.JvmInject(jvmInjector)
  164. fmt.Println("AttachJavaNetWriteUprobes:", err)
  165. if err != nil {
  166. return nil, err
  167. }
  168. var links []link.Link
  169. ex, err := link.OpenExecutable(jvmInjector.Uprobe.ELFPath)
  170. if err != nil {
  171. return nil, err
  172. }
  173. opt := link.UprobeOptions{
  174. Offset: uint64(jvmInjector.Uprobe.Offset),
  175. PID: int(pid),
  176. }
  177. upread02, err := ex.Uprobe(jvmInjector.Uprobe.Func, t.uprobes["uprobe_Java_java_net_SocketOutputStream_socketWrite0"], &opt)
  178. if err != nil {
  179. return nil, err
  180. }
  181. links = append(links, upread02)
  182. if len(links) == 0 {
  183. return nil, errors.New("can not find uprobe_Java_net_SocketOutputStream_socketWrite0")
  184. }
  185. fmt.Println("[jvm] libnet attached", pid)
  186. return links, nil
  187. }
  188. func getCallNextMoveOffsets(machine elf.Machine, instructions []byte) []int {
  189. var res []int
  190. firstCall := 0
  191. switch machine {
  192. case elf.EM_X86_64:
  193. for i := 0; i < len(instructions); {
  194. ins, err := x86asm.Decode(instructions[i:], 64)
  195. if err == nil && ins.Op == x86asm.CALL {
  196. if firstCall == 0 {
  197. firstCall = 1
  198. } else {
  199. i += ins.Len
  200. res = append(res, i)
  201. return res
  202. }
  203. }
  204. i += ins.Len
  205. }
  206. case elf.EM_AARCH64:
  207. for i := 0; i < len(instructions); {
  208. ins, err := arm64asm.Decode(instructions[i:])
  209. if err == nil && ins.Op == arm64asm.BL {
  210. if firstCall == 0 {
  211. firstCall = 1
  212. } else {
  213. i += 4
  214. res = append(res, i)
  215. return res
  216. }
  217. }
  218. i += 4
  219. }
  220. }
  221. return res
  222. }
  223. func getSoPath(pid uint32, soname string) string {
  224. // 获取进程的maps文件路径
  225. mapsPath := fmt.Sprintf("/proc/%d/maps", pid)
  226. // 读取maps文件内容
  227. mapsData, err := ioutil.ReadFile(mapsPath)
  228. if err != nil {
  229. fmt.Println("lookup so error.")
  230. return ""
  231. }
  232. lines := strings.Split(string(mapsData), "\n")
  233. for _, line := range lines {
  234. fields := strings.Fields(line)
  235. if len(fields) >= 6 {
  236. perms := fields[1]
  237. path := fields[len(fields)-1]
  238. if strings.Contains(perms, "x") && filepath.Ext(path) == ".so" {
  239. if strings.Contains(path, soname) {
  240. return path
  241. }
  242. }
  243. }
  244. }
  245. return ""
  246. }