jvm.go 6.9 KB

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