jvm.go 5.5 KB

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