stack.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package ebpftracer
  2. import (
  3. "bufio"
  4. "fmt"
  5. "github.com/cilium/ebpf"
  6. "github.com/cilium/ebpf/link"
  7. "github.com/coroot/coroot-node-agent/ebpftracer/tracer"
  8. "github.com/coroot/coroot-node-agent/ebpftracer/tracer/jattach"
  9. "github.com/coroot/coroot-node-agent/utils"
  10. . "github.com/coroot/coroot-node-agent/utils/modelse"
  11. klog "github.com/sirupsen/logrus"
  12. "os"
  13. "path/filepath"
  14. "strconv"
  15. "strings"
  16. "syscall"
  17. )
  18. // AttachStackUprobes
  19. // default process stack
  20. func (t *Tracer) AttachStackUprobes(path string, uprobes []tracer.Uprobe) []link.Link {
  21. var links []link.Link
  22. ex, err := link.OpenExecutable(path)
  23. if err != nil {
  24. return nil
  25. }
  26. klog.Infoln("[stack] Attach Start", path)
  27. for i, up := range uprobes {
  28. klog.Debugf("[stack] attaching %d -> %d -> %s -> 0x%x -> 0x%x -> 0x%x", i, len(uprobes), up.Funcname, up.AbsOffset, up.Address, up.AbsOffset+up.Address)
  29. var prog *ebpf.Program
  30. switch up.Location {
  31. case tracer.AtEntry:
  32. prog = t.uprobes["ent"]
  33. case tracer.AtRet:
  34. prog = t.uprobes["ret"]
  35. case tracer.AtDotNetEntry:
  36. prog = t.uprobes["dotnetent"]
  37. }
  38. uplink, err := ex.Uprobe(up.Funcname, prog, &link.UprobeOptions{Address: up.Address, Offset: up.AbsOffset})
  39. if err != nil {
  40. klog.Errorf("[stack] attachingERROR:%v, %v, %v", err, up, uplink)
  41. // return nil
  42. } else {
  43. links = append(links, uplink)
  44. }
  45. }
  46. return links
  47. }
  48. // JVM process stack
  49. func (t *Tracer) JattachJvm(pid uint32, appInfo AppInfo, whiteList, blackList, rootfs string) error {
  50. klog.Infoln("[Jvm stack uprobe] Attach Start AttachJVMStackUprobes", pid)
  51. // TODO tiny Agent 注入
  52. // TODO copy agent到 jre conf/lib/plugins
  53. //argkv := "/opt/github/euspace/dist/package_dir/agents/NativeAgent/lib/apmAgent.jar=/opt/github/euspace/dist/package_dir/agents/NativeAgent"
  54. if whiteList == "" && blackList == "" {
  55. return fmt.Errorf("no stack rule")
  56. }
  57. whiteList = strings.ReplaceAll(whiteList, ",", "")
  58. blackList = strings.ReplaceAll(blackList, ",", "")
  59. var stackRule string
  60. if whiteList == "" {
  61. stackRule = fmt.Sprintf("blackStack=%s", blackList) // 仅保留黑名单
  62. } else if blackList == "" {
  63. stackRule = fmt.Sprintf("whiteStack=%s", whiteList) // 仅保留白名单
  64. } else {
  65. stackRule = fmt.Sprintf("whiteStack=%s,blackStack=%s", whiteList, blackList)
  66. }
  67. //nativeBasePath := utils.GetDefaultAgentsPath("NativeAgent")
  68. nativeBasePath := "/tmp/NativeAgent"
  69. kvPairs := []string{
  70. fmt.Sprintf("%s=%s", filepath.Join(nativeBasePath, "lib", "apmAgent.jar"), nativeBasePath),
  71. fmt.Sprintf("%s=%d", "appId", appInfo.AppIdHash.IntVal),
  72. fmt.Sprintf("%s=%d", "agentId", appInfo.AgentId),
  73. fmt.Sprintf("%s=%d", "hostId", utils.GetHostID()),
  74. fmt.Sprintf("%s=%d", "accountId", utils.GetAccountID()),
  75. stackRule,
  76. }
  77. argkv := strings.Join(kvPairs, ",")
  78. klog.Infof("[Jvm stack uprobe] params:[%s]", argkv)
  79. args := []string{"load", "instrument", "false", argkv}
  80. jattacher := jattach.JvmJattacher{
  81. Pid: pid,
  82. Args: args,
  83. PrintOutput: 1,
  84. }
  85. res, err := jattacher.JAttach()
  86. klog.Infof("[Jvm stack uprobe] JAttach Result: %d", res)
  87. if err != nil {
  88. return err
  89. }
  90. return nil
  91. }
  92. func (t *Tracer) AttachJVMStackUprobes(pid uint32, appInfo AppInfo, rootfs string) ([]link.Link, error) {
  93. //path = utils.GetDefaultAgentsPath("NativeAgent", "libnativeAgent.so")
  94. //tmp/NativeAgentSo2297066477572820801.tmp
  95. path, err := FindNativeSoFromMapped(pid, "NativeAgentSo", ".tmp")
  96. if err != nil {
  97. klog.Error(err)
  98. return nil, err
  99. }
  100. path = filepath.Join(rootfs, path)
  101. setNodeEnter := "Java_com_cloudwise_agent_common_natives_TraceNative_setNodeEnter"
  102. setNodeReturn := "Java_com_cloudwise_agent_common_natives_TraceNative_setNodeReturn"
  103. klog.Infoln("[Jvm stack uprobe] Attach Start AttachJVMStackUprobes", path)
  104. var links []link.Link
  105. ex, err := link.OpenExecutable(path)
  106. if err != nil {
  107. klog.Error(err)
  108. return nil, err
  109. }
  110. klog.Infof("[Jvm stack uprobe] Attach Start [%s] [%s] ", setNodeEnter, setNodeReturn)
  111. uplink, err := ex.Uprobe(setNodeEnter, t.uprobes["setNodeEnter"], &link.UprobeOptions{Offset: 0x0, PID: int(pid)})
  112. if err != nil {
  113. klog.Errorf("[Jvm stack uprobe] Attaching ERROR: %v, %v, %v\n", err, setNodeEnter, uplink)
  114. return nil, err
  115. } else {
  116. links = append(links, uplink)
  117. }
  118. klog.Infoln("Attach Start " + setNodeReturn)
  119. uplink, err = ex.Uprobe(setNodeReturn, t.uprobes["setNodeReturn"], &link.UprobeOptions{Offset: 0x0})
  120. if err != nil {
  121. klog.Errorf("[Jvm stack uprobe] Attaching ERROR: %v, %v, %v\n", err, setNodeReturn, uplink)
  122. return nil, err
  123. } else {
  124. links = append(links, uplink)
  125. }
  126. return links, nil
  127. }
  128. func FindNativeSoFromMapped(pid uint32, prefix, suffix string) (string, error) {
  129. mapsFile := fmt.Sprintf("/proc/%d/maps", pid)
  130. tmpFile, err := os.Open(mapsFile)
  131. if err != nil {
  132. return "", fmt.Errorf("error opening maps file: %v", err)
  133. }
  134. defer tmpFile.Close()
  135. var selectedPath string
  136. var maxTimestamp int64
  137. fallbackPaths := make(map[string]struct{}) // 使用 map 去重
  138. scanner := bufio.NewScanner(tmpFile)
  139. for scanner.Scan() {
  140. line := scanner.Text()
  141. if strings.Contains(line, prefix) && strings.HasSuffix(line, suffix) {
  142. parts := strings.Fields(line)
  143. if len(parts) > 5 {
  144. path := parts[len(parts)-1]
  145. baseName := filepath.Base(path)
  146. if strings.HasPrefix(baseName, prefix) && strings.HasSuffix(baseName, suffix) {
  147. middle := strings.TrimSuffix(strings.TrimPrefix(baseName, prefix), suffix)
  148. segments := strings.Split(middle, ".")
  149. if len(segments) >= 2 {
  150. timestampStr := segments[len(segments)-1]
  151. timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
  152. if err == nil && timestamp > maxTimestamp {
  153. maxTimestamp = timestamp
  154. selectedPath = path
  155. }
  156. } else {
  157. fallbackPaths[path] = struct{}{}
  158. }
  159. }
  160. }
  161. }
  162. }
  163. if err = scanner.Err(); err != nil {
  164. return "", fmt.Errorf("error reading maps file: %v", err)
  165. }
  166. if selectedPath != "" {
  167. return selectedPath, nil
  168. }
  169. var latestPath string
  170. var latestModTime int64
  171. for path := range fallbackPaths {
  172. info, err := os.Stat(path)
  173. if err != nil {
  174. continue
  175. }
  176. stat, ok := info.Sys().(*syscall.Stat_t)
  177. if !ok {
  178. continue
  179. }
  180. modTime := stat.Mtim.Sec
  181. if modTime > latestModTime {
  182. latestModTime = modTime
  183. latestPath = path
  184. }
  185. }
  186. if latestPath != "" {
  187. return latestPath, nil
  188. }
  189. return "", fmt.Errorf("no matching path found")
  190. }