stack.go 10.0 KB

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