apm_stack_dispatch.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. package containers
  2. import (
  3. "debug/dwarf"
  4. "debug/elf"
  5. debugelf "debug/elf"
  6. "fmt"
  7. "github.com/coroot/coroot-node-agent/common"
  8. "github.com/coroot/coroot-node-agent/ebpftracer"
  9. "github.com/coroot/coroot-node-agent/ebpftracer/tracer"
  10. tracerelf "github.com/coroot/coroot-node-agent/ebpftracer/tracer"
  11. "github.com/coroot/coroot-node-agent/proc"
  12. "github.com/coroot/coroot-node-agent/utils"
  13. . "github.com/coroot/coroot-node-agent/utils/modelse"
  14. klog "github.com/sirupsen/logrus"
  15. "golang.org/x/arch/arm64/arm64asm"
  16. "golang.org/x/arch/x86/x86asm"
  17. "io"
  18. "log"
  19. "os"
  20. "regexp"
  21. "sort"
  22. )
  23. type uprobesDef struct {
  24. Name string
  25. Offset uint64
  26. EntAddress uint64
  27. RetAddress uint64
  28. }
  29. func (c *Container) AttachStack(tracer *ebpftracer.Tracer, pid uint32) error {
  30. //// 禁用stack
  31. //if tracer.DisableStackTracing() {
  32. // klog.Warnf("StackTrace tracing is disabled")
  33. // return nil
  34. //}
  35. if common.IsOpenFilter() && !common.IsFilterPid(pid) {
  36. klog.Warnf("StackTrace %d tracing is filter", pid)
  37. return nil
  38. }
  39. codeType := c.GetCodeTypeFromCache(pid)
  40. if codeType.IsUnknownCode() {
  41. klog.Warnf("StackTrace %d tracing is IsUnknownCode", pid)
  42. return nil
  43. }
  44. p := c.processes[pid]
  45. if p == nil {
  46. return fmt.Errorf("unknown process %d", pid)
  47. }
  48. if p.stackAttachOnce {
  49. return nil
  50. }
  51. p.stackAttachOnce = true
  52. switch codeType {
  53. case CodeTypeJava:
  54. return c.jvmStackTrace(tracer, pid)
  55. default:
  56. return c.stackTrace(tracer, pid)
  57. }
  58. }
  59. func (c *Container) stackTrace(tracer *ebpftracer.Tracer, pid uint32) error {
  60. p := c.processes[pid]
  61. if p == nil {
  62. return fmt.Errorf("unknown process %d", pid)
  63. }
  64. //if p.stackAttachOnce {
  65. // return nil
  66. //}
  67. binType := "dotnet"
  68. MatchString := ".*HandleFunc|.*main.*|testfun.*|.*serverHandler.*|.*ServeHTTP.*"
  69. dbgpath := ""
  70. WHITE_LIST := os.Getenv("WHITE_LIST")
  71. BIN_TYPE := os.Getenv("BIN_TYPE")
  72. DBG_PATH := os.Getenv("DBG_PATH")
  73. if WHITE_LIST != "" {
  74. MatchString = WHITE_LIST
  75. }
  76. if DBG_PATH != "" {
  77. dbgpath = DBG_PATH
  78. }
  79. if BIN_TYPE != "" {
  80. binType = BIN_TYPE
  81. }
  82. klog.Infoln("[stack] UprobesMatchString:::init", MatchString)
  83. path := proc.Path(uint32(pid), "exe")
  84. var err error
  85. if dbgpath != "" {
  86. c.Uprobes, err = c.getJavaAOTUprobes(binType, path, dbgpath, MatchString)
  87. } else {
  88. c.Uprobes, err = c.getUprobes(path, MatchString)
  89. }
  90. if err != nil {
  91. return err
  92. }
  93. c.UprobesMap = map[string]tracerelf.Uprobe{}
  94. klog.Infoln("[stack] UprobesMap start")
  95. for _, up := range c.Uprobes {
  96. klog.Debugf("[stack] UprobesMap %s %d %d", up.Funcname, up.Address, up.AbsOffset)
  97. c.UprobesMap[fmt.Sprintf("%s-%s", up.Funcname, up.Address+up.AbsOffset)] = up
  98. }
  99. //codeType := c.GetCodeTypeFromCache(pid)
  100. //tracer.InitKProcInfo(pid, c.instanceID, uint16(codeType))
  101. p.stackUprobes = append(p.stackUprobes, tracer.AttachStackUprobes(path, c.Uprobes)...)
  102. p.stackAttachOnce = true
  103. return nil
  104. }
  105. func (c *Container) jvmStackTrace(tracer *ebpftracer.Tracer, pid uint32) error {
  106. p := c.processes[pid]
  107. // check version
  108. libjavaso, err := utils.GetSoPath(pid, "libjava.so", c.getRootfs())
  109. if err != nil {
  110. p.versionFailed = true
  111. klog.WithError(err).Errorf("[jvmStackTrace] Failed get so path")
  112. return err
  113. }
  114. v, err := ebpftracer.GetJvmVersion(libjavaso)
  115. if err != nil {
  116. p.versionFailed = true
  117. klog.WithError(err).Errorf("[jvmStackTrace] Failed get Java version")
  118. return err
  119. }
  120. c.AppInfo.Version = v
  121. major, minor, patch, err := ebpftracer.ParseVersion(v)
  122. klog.Infof("[jvmStackTrace] version: %s (Major: %d, Minor: %d, Patch: %d)", v, major, minor, patch)
  123. if major != 1 || minor != 8 {
  124. p.versionFailed = true
  125. return fmt.Errorf("[jvmStackTrace] Unsupported Java version")
  126. }
  127. err = tracer.JattachJvm(pid, c.AppInfo, c.WhiteSettingInfo.WhiteStackSettingInfo.WhiteList, c.WhiteSettingInfo.WhiteStackSettingInfo.BlackList)
  128. if err != nil {
  129. p.stackStatus.JattachFailure()
  130. return err
  131. } else {
  132. p.stackStatus.JattachSuccess()
  133. }
  134. jvmStackProbes, err := tracer.AttachJVMStackUprobes(pid, c.AppInfo)
  135. if err != nil {
  136. p.stackStatus.StackUprobesFailure()
  137. klog.WithError(err).Errorf("[jvmStackTrace] Failed attach jvm stack.")
  138. return err
  139. }
  140. p.stackUprobes = append(p.stackUprobes, jvmStackProbes...)
  141. p.stackStatus.StackUprobesSuccess()
  142. return nil
  143. }
  144. func (c *Container) getJavaAOTUprobes(binType, path string, dbgpath string, MatchString string) ([]tracer.Uprobe, error) {
  145. uprobes := []tracer.Uprobe{}
  146. elfFile, err := elf.Open(path)
  147. if err != nil {
  148. return nil, err
  149. }
  150. funSection := ".text"
  151. if binType == "dotnet" {
  152. funSection = "__managedcode"
  153. }
  154. textSection := elfFile.Section(funSection)
  155. if textSection == nil {
  156. fmt.Println("no text section", nil)
  157. return nil, nil
  158. }
  159. textSectionData, err := textSection.Data()
  160. if err != nil {
  161. fmt.Println("failed to read text section", err)
  162. return nil, err
  163. }
  164. textSectionLen := uint64(len(textSectionData) - 1)
  165. dwarfFile, err := elf.Open(dbgpath)
  166. if err != nil {
  167. return nil, err
  168. }
  169. dwarfData, err := dwarfFile.DWARF()
  170. if err != nil {
  171. return nil, err
  172. }
  173. entryReader := dwarfData.Reader()
  174. // var targetAddress uint64
  175. listEntry := make(map[dwarf.Offset]uprobesDef)
  176. SpecListEntry := []dwarf.Entry{}
  177. for {
  178. entry, err := entryReader.Next()
  179. if err == io.EOF {
  180. // We've reached the end of DWARF entries
  181. break
  182. }
  183. if err != nil {
  184. log.Fatalf("Error reading entry: %v", err)
  185. }
  186. if entry == nil {
  187. log.Println("Warning: a nil entry was returned with no error")
  188. break
  189. }
  190. if entry.Tag == dwarf.TagSubprogram {
  191. // fmt.Printf("entry address: %x, %d\n", entry.Offset, entry.Children)
  192. funName, _ := entry.Val(dwarf.AttrName).(string)
  193. found, _ := regexp.MatchString(MatchString, funName)
  194. if found {
  195. entAddress, _ := entry.Val(dwarf.AttrLowpc).(uint64)
  196. retAddress, _ := entry.Val(dwarf.AttrHighpc).(uint64)
  197. // fmt.Printf("Function %s address: %x, %x\n", funName, address, entry.Offset)
  198. uprobes := uprobesDef{}
  199. uprobes.EntAddress = entAddress
  200. uprobes.RetAddress = retAddress
  201. uprobes.Offset = uint64(entry.Offset)
  202. uprobes.Name = funName
  203. listEntry[entry.Offset] = uprobes
  204. }
  205. specAddr, _ := entry.Val(dwarf.AttrSpecification).(dwarf.Offset)
  206. lowpc := entry.Val(dwarf.AttrLowpc)
  207. if lowpc != nil && specAddr > 0 && lowpc.(uint64) > 0 {
  208. // fmt.Printf("AttrSpecification address: %x, %x\n", specAddr, entry.Offset)
  209. SpecListEntry = append(SpecListEntry, *entry)
  210. }
  211. }
  212. }
  213. for _, v := range SpecListEntry {
  214. specAddr, _ := v.Val(dwarf.AttrSpecification).(dwarf.Offset)
  215. // fmt.Printf("SpecListEntrySpecListEntrySpecListEntry Attach Function: %x\n", specAddr)
  216. _, ok := listEntry[specAddr]
  217. if ok {
  218. vv := listEntry[specAddr]
  219. entAddr := v.Val(dwarf.AttrLowpc)
  220. if entAddr != nil {
  221. vv.EntAddress = entAddr.(uint64)
  222. }
  223. retAddr := v.Val(dwarf.AttrHighpc)
  224. if retAddr != nil {
  225. switch retAddr.(type) {
  226. case uint64:
  227. vv.RetAddress = uint64(retAddr.(uint64))
  228. case int64:
  229. vv.RetAddress = uint64(retAddr.(int64))
  230. default:
  231. fmt.Println("Unknown type")
  232. }
  233. }
  234. listEntry[specAddr] = vv
  235. }
  236. }
  237. for _, v := range listEntry {
  238. fmt.Printf("Need Attach Function %s address: %x, %x\n", v.Name, v.EntAddress, v.RetAddress)
  239. sStart := v.EntAddress - textSection.Addr
  240. sSize := v.RetAddress
  241. if v.RetAddress > v.EntAddress {
  242. sSize = v.RetAddress - v.EntAddress
  243. }
  244. sEnd := sStart + sSize
  245. if sEnd > textSectionLen {
  246. continue
  247. }
  248. sBytes := textSectionData[sStart:sEnd]
  249. rbpOffsets := getRbpEnterOffsets(elfFile.Machine, sBytes)
  250. returnOffsets := getReturnOffsets(elfFile.Machine, sBytes)
  251. if rbpOffsets != 0 {
  252. uprobes = append(uprobes, tracer.Uprobe{
  253. Funcname: v.Name, // 函数名
  254. Location: tracer.AtDotNetEntry, // 入口
  255. Address: v.EntAddress, // 函数地址
  256. AbsOffset: uint64(rbpOffsets), // 函数相对 ELF 偏移
  257. RelOffset: 0, // 函数真实偏移
  258. })
  259. } else {
  260. // 函数入口加入待 attach 列表
  261. uprobes = append(uprobes, tracer.Uprobe{
  262. Funcname: v.Name, // 函数名
  263. Location: tracer.AtEntry, // 入口
  264. Address: v.EntAddress, // 函数地址
  265. AbsOffset: 0, // 函数相对 ELF 偏移
  266. RelOffset: 0, // 函数真实偏移
  267. })
  268. }
  269. for _, offset := range returnOffsets {
  270. uprobes = append(uprobes, tracer.Uprobe{
  271. Funcname: v.Name,
  272. Location: tracer.AtRet,
  273. Address: v.EntAddress,
  274. AbsOffset: uint64(offset),
  275. RelOffset: 0,
  276. })
  277. }
  278. }
  279. return uprobes, nil
  280. }
  281. func (c *Container) getUprobes(path string, MatchString string) ([]tracer.Uprobe, error) {
  282. uprobes := []tracer.Uprobe{}
  283. binFile, err := os.Open(path)
  284. if err != nil {
  285. return nil, err
  286. }
  287. // cache := map[string]interface{}{}
  288. // 解析 elf 文件
  289. elfFile, err := debugelf.NewFile(binFile)
  290. if err != nil {
  291. return nil, err
  292. }
  293. // 获取所有符号表
  294. symbols, err := elfFile.Symbols()
  295. if err != nil {
  296. return nil, err
  297. }
  298. sort.Slice(symbols, func(i, j int) bool { return symbols[i].Value < symbols[j].Value })
  299. c.Symbols = symbols
  300. // 符号表组装成键值 map,方便使用
  301. symnames := map[string]debugelf.Symbol{}
  302. for _, symbol := range symbols {
  303. klog.Debugf("[stack] %v %v", symbol.Name, symbol)
  304. symnames[symbol.Name] = symbol
  305. }
  306. textSection := elfFile.Section(".text")
  307. if textSection == nil {
  308. klog.Infoln("[stack] no text section")
  309. return nil, nil
  310. }
  311. textSectionData, err := textSection.Data()
  312. if err != nil {
  313. klog.WithError(err).Errorf("[stack] Failed to read text section")
  314. return nil, nil
  315. }
  316. textSectionLen := uint64(len(textSectionData) - 1)
  317. // 遍历符号表
  318. for _, symbol := range symbols {
  319. if debugelf.ST_TYPE(symbol.Info) != debugelf.STT_FUNC {
  320. continue
  321. }
  322. // fmt.Println("Hello FunName: ", symbol.Name)
  323. // 使用正则表达式匹配函数白名单列表
  324. found, err := regexp.MatchString(MatchString, symbol.Name)
  325. // found, err := regexp.MatchString("main.*", symbol.Name)
  326. if err != nil {
  327. klog.WithError(err).Errorln("[stack] found error")
  328. return nil, err
  329. }
  330. if found {
  331. // 匹配到了加入 attachFuncs 列表
  332. klog.Debugf("[stack] Fuck This: %s, %x", symbol.Name, symbol.Value)
  333. // attachFuncs = append(attachFuncs, symbol.Name)
  334. // 根据函数名拿到当前函数的符号结构体
  335. sym := symnames[symbol.Name]
  336. //if err != nil {
  337. // klog.WithError(err).Errorf("symnames[symbol.Name] %s", symbol.Name)
  338. // return nil, err
  339. //}
  340. address := sym.Value
  341. for _, p := range elfFile.Progs {
  342. if p.Type != elf.PT_LOAD || (p.Flags&elf.PF_X) == 0 {
  343. continue
  344. }
  345. if p.Vaddr <= sym.Value && sym.Value < (p.Vaddr+p.Memsz) {
  346. address = sym.Value - p.Vaddr + p.Off
  347. break
  348. }
  349. }
  350. // 函数入口加入待 attach 列表
  351. uprobes = append(uprobes, tracer.Uprobe{
  352. Funcname: symbol.Name, // 函数名
  353. Location: tracer.AtEntry, // 入口
  354. Address: address, // 函数地址
  355. AbsOffset: 0, // 函数相对 ELF 偏移
  356. RelOffset: 0, // 函数真实偏移
  357. Wanted: true,
  358. })
  359. sStart := sym.Value - textSection.Addr
  360. sEnd := sStart + sym.Size
  361. if sEnd > textSectionLen {
  362. continue
  363. }
  364. sBytes := textSectionData[sStart:sEnd]
  365. returnOffsets := getReturnOffsets(elfFile.Machine, sBytes)
  366. for _, offset := range returnOffsets {
  367. uprobes = append(uprobes, tracer.Uprobe{
  368. Funcname: symbol.Name,
  369. Location: tracer.AtRet,
  370. Address: address,
  371. AbsOffset: uint64(offset),
  372. RelOffset: 0,
  373. })
  374. }
  375. }
  376. }
  377. return uprobes, nil
  378. }
  379. func getRbpEnterOffsets(machine elf.Machine, instructions []byte) int {
  380. switch machine {
  381. case elf.EM_X86_64:
  382. for i := 0; i < len(instructions); {
  383. ins, err := x86asm.Decode(instructions[i:], 64)
  384. if err == nil && ins.Op == x86asm.LEA && ins.Args[0].String() == "RBP" {
  385. klog.Infof("[stack] getRbpEnterOffsets: %v, %s, %s", ins, ins.Args[0].String(), ins.Args[1].String())
  386. return i
  387. }
  388. i += ins.Len
  389. }
  390. case elf.EM_AARCH64:
  391. for i := 0; i < len(instructions); {
  392. ins, err := arm64asm.Decode(instructions[i:])
  393. if err == nil && ins.Op == arm64asm.RET {
  394. return i
  395. }
  396. i += 4
  397. }
  398. }
  399. return 0
  400. }
  401. func getReturnOffsets(machine elf.Machine, instructions []byte) []int {
  402. var res []int
  403. switch machine {
  404. case elf.EM_X86_64:
  405. for i := 0; i < len(instructions); {
  406. ins, err := x86asm.Decode(instructions[i:], 64)
  407. if err == nil && ins.Op == x86asm.RET {
  408. res = append(res, i)
  409. }
  410. i += ins.Len
  411. }
  412. case elf.EM_AARCH64:
  413. for i := 0; i < len(instructions); {
  414. ins, err := arm64asm.Decode(instructions[i:])
  415. if err == nil && ins.Op == arm64asm.RET {
  416. res = append(res, i)
  417. }
  418. i += 4
  419. }
  420. }
  421. return res
  422. }