stack.go 11 KB

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