stack.go 11 KB

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