apm_stack_dispatch.go 11 KB

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