stack.go 10 KB

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