stack.go 10 KB

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