jvm.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package ebpftracer
  2. import (
  3. "errors"
  4. "io/ioutil"
  5. "strings"
  6. "debug/elf"
  7. "fmt"
  8. "path/filepath"
  9. "github.com/coroot/coroot-node-agent/proc"
  10. "github.com/coroot/coroot-node-agent/utils"
  11. "github.com/cilium/ebpf/link"
  12. "golang.org/x/arch/arm64/arm64asm"
  13. "golang.org/x/arch/x86/x86asm"
  14. )
  15. const (
  16. // goServeHTTP = "net/http.serverHandler.ServeHTTP"
  17. // binPath = "/root/code/jdk8u/build/linux-x86_64-normal-server-release/jdk/lib/amd64/libnio.so"
  18. symbolsocketRead0 = "Java_sun_nio_ch_FileDispatcherImpl_read0"
  19. )
  20. func (t *Tracer) AttachJavaNioReadUprobes(pid uint32, insID utils.ID, codeType int32) []link.Link {
  21. if t.disableL7Tracing {
  22. return nil
  23. }
  24. var links []link.Link
  25. var bpath = ""
  26. // JavaAOT 逻辑
  27. if codeType == 1003 {
  28. bpath = proc.Path(uint32(pid), "exe")
  29. } else {
  30. version := UsePIDToGetJDKVersion(pid)
  31. fmt.Println("java version is ", version)
  32. bpath = getSoPath(pid, "libnio.so")
  33. if bpath == "" {
  34. fmt.Println("can,t find the nio.so")
  35. return nil
  36. }
  37. }
  38. fmt.Println("find the nio.so path is ", bpath)
  39. ex, err := link.OpenExecutable(bpath)
  40. if err != nil {
  41. return nil
  42. }
  43. ef, err := elf.Open(bpath)
  44. if err != nil {
  45. return nil
  46. //PID: int(pid),
  47. }
  48. defer ef.Close()
  49. symbols, err := ef.Symbols()
  50. if err != nil {
  51. if errors.Is(err, elf.ErrNoSymbols) {
  52. return nil
  53. }
  54. return nil
  55. }
  56. textSection := ef.Section(".text")
  57. if textSection == nil {
  58. return nil
  59. }
  60. textSectionData, err := textSection.Data()
  61. if err != nil {
  62. return nil
  63. }
  64. textSectionLen := uint64(len(textSectionData) - 1)
  65. // opt := link.UprobeOptions{
  66. // Offset: 61,
  67. // }
  68. // upread02, err := ex.Uprobe(symbolsocketRead0, t.uprobes["uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0"], &opt)
  69. // if err != nil {
  70. // return nil
  71. // }
  72. // links = append(links, upread01)
  73. for _, s := range symbols {
  74. if elf.ST_TYPE(s.Info) != elf.STT_FUNC || s.Size == 0 {
  75. continue
  76. }
  77. switch s.Name {
  78. case symbolsocketRead0:
  79. default:
  80. continue
  81. }
  82. address := s.Value
  83. for _, p := range ef.Progs {
  84. if p.Type != elf.PT_LOAD || (p.Flags&elf.PF_X) == 0 {
  85. continue
  86. }
  87. if p.Vaddr <= s.Value && s.Value < (p.Vaddr+p.Memsz) {
  88. address = s.Value - p.Vaddr + p.Off
  89. break
  90. }
  91. }
  92. fmt.Println("s.Name-----:", s.Name)
  93. switch s.Name {
  94. case symbolsocketRead0:
  95. sStart := s.Value - textSection.Addr
  96. sEnd := sStart + s.Size
  97. if sEnd > textSectionLen {
  98. continue
  99. }
  100. sBytes := textSectionData[sStart:sEnd]
  101. returnOffsets := getCallNextMoveOffsets(ef.Machine, sBytes)
  102. if len(returnOffsets) == 0 {
  103. return nil
  104. }
  105. for _, offset := range returnOffsets {
  106. 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)})
  107. if err != nil {
  108. fmt.Println("failed to attach uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0 uprobe")
  109. return nil
  110. }
  111. links = append(links, l)
  112. }
  113. }
  114. }
  115. if len(links) == 0 {
  116. return nil
  117. }
  118. fmt.Println("jvm uprobes attached, pid is ", pid)
  119. return links
  120. }
  121. func (t *Tracer) AttachJavaNetWriteUprobes(pid uint32, insID utils.ID) []link.Link {
  122. if t.disableL7Tracing {
  123. return nil
  124. }
  125. //
  126. //if pid != 251719 {
  127. // return nil
  128. //}
  129. var libnetSo = "/data/roger/graalvm/lib/libnet.so"
  130. var sys = "Java_java_net_SocketOutputStream_socketWrite0"
  131. var links []link.Link
  132. ex, err := link.OpenExecutable(libnetSo)
  133. if err != nil {
  134. return nil
  135. }
  136. opt := link.UprobeOptions{
  137. Offset: 53,
  138. PID: int(pid),
  139. }
  140. upread02, err := ex.Uprobe(sys, t.uprobes["uprobe_Java_java_net_SocketOutputStream_socketWrite0"], &opt)
  141. if err != nil {
  142. return nil
  143. }
  144. links = append(links, upread02)
  145. if len(links) == 0 {
  146. return nil
  147. }
  148. fmt.Println("jvm client uprobes attached", pid)
  149. return links
  150. }
  151. func getCallNextMoveOffsets(machine elf.Machine, instructions []byte) []int {
  152. var res []int
  153. firstCall := 0
  154. switch machine {
  155. case elf.EM_X86_64:
  156. for i := 0; i < len(instructions); {
  157. ins, err := x86asm.Decode(instructions[i:], 64)
  158. if err == nil && ins.Op == x86asm.CALL {
  159. if firstCall == 0 {
  160. firstCall = 1
  161. } else {
  162. i += ins.Len
  163. res = append(res, i)
  164. return res
  165. }
  166. }
  167. i += ins.Len
  168. }
  169. case elf.EM_AARCH64:
  170. for i := 0; i < len(instructions); {
  171. ins, err := arm64asm.Decode(instructions[i:])
  172. if err == nil && ins.Op == arm64asm.BL {
  173. if firstCall == 0 {
  174. firstCall = 1
  175. } else {
  176. i += 4
  177. res = append(res, i)
  178. return res
  179. }
  180. }
  181. i += 4
  182. }
  183. }
  184. return res
  185. }
  186. func getSoPath(pid uint32, soname string) string {
  187. // 获取进程的maps文件路径
  188. mapsPath := fmt.Sprintf("/proc/%d/maps", pid)
  189. // 读取maps文件内容
  190. mapsData, err := ioutil.ReadFile(mapsPath)
  191. if err != nil {
  192. fmt.Println("无法读取maps文件")
  193. return ""
  194. }
  195. lines := strings.Split(string(mapsData), "\n")
  196. for _, line := range lines {
  197. fields := strings.Fields(line)
  198. if len(fields) >= 6 {
  199. perms := fields[1]
  200. path := fields[len(fields)-1]
  201. if strings.Contains(perms, "x") && filepath.Ext(path) == ".so" {
  202. if strings.Contains(path, soname) {
  203. return path
  204. }
  205. }
  206. }
  207. }
  208. return ""
  209. }