stack.go 11 KB

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