apm_stack_dispatch.go 12 KB

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