apm_stack_dispatch.go 13 KB

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