| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- package ebpftracer
- import (
- "bufio"
- "fmt"
- "github.com/cilium/ebpf"
- "github.com/cilium/ebpf/link"
- "github.com/coroot/coroot-node-agent/ebpftracer/tracer"
- "github.com/coroot/coroot-node-agent/ebpftracer/tracer/jattach"
- "github.com/coroot/coroot-node-agent/utils"
- . "github.com/coroot/coroot-node-agent/utils/modelse"
- klog "github.com/sirupsen/logrus"
- "os"
- "path/filepath"
- "strconv"
- "strings"
- "syscall"
- )
- // AttachStackUprobes
- // default process stack
- func (t *Tracer) AttachStackUprobes(path string, uprobes []tracer.Uprobe) []link.Link {
- var links []link.Link
- ex, err := link.OpenExecutable(path)
- if err != nil {
- return nil
- }
- klog.Infoln("[stack] Attach Start", path)
- for i, up := range uprobes {
- 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)
- var prog *ebpf.Program
- switch up.Location {
- case tracer.AtEntry:
- prog = t.uprobes["ent"]
- case tracer.AtRet:
- prog = t.uprobes["ret"]
- case tracer.AtDotNetEntry:
- prog = t.uprobes["dotnetent"]
- }
- uplink, err := ex.Uprobe(up.Funcname, prog, &link.UprobeOptions{Address: up.Address, Offset: up.AbsOffset})
- if err != nil {
- klog.Errorf("[stack] attachingERROR:%v, %v, %v", err, up, uplink)
- // return nil
- } else {
- links = append(links, uplink)
- }
- }
- return links
- }
- // JVM process stack
- func (t *Tracer) JattachJvm(pid uint32, appInfo AppInfo, whiteList, blackList, rootfs string) error {
- klog.Infoln("[Jvm stack uprobe] Attach Start AttachJVMStackUprobes", pid)
- // TODO tiny Agent 注入
- // TODO copy agent到 jre conf/lib/plugins
- //argkv := "/opt/github/euspace/dist/package_dir/agents/NativeAgent/lib/apmAgent.jar=/opt/github/euspace/dist/package_dir/agents/NativeAgent"
- if whiteList == "" && blackList == "" {
- return fmt.Errorf("no stack rule")
- }
- whiteList = strings.ReplaceAll(whiteList, ",", "")
- blackList = strings.ReplaceAll(blackList, ",", "")
- var stackRule string
- if whiteList == "" {
- stackRule = fmt.Sprintf("blackStack=%s", blackList) // 仅保留黑名单
- } else if blackList == "" {
- stackRule = fmt.Sprintf("whiteStack=%s", whiteList) // 仅保留白名单
- } else {
- stackRule = fmt.Sprintf("whiteStack=%s,blackStack=%s", whiteList, blackList)
- }
- //nativeBasePath := utils.GetDefaultAgentsPath("NativeAgent")
- nativeBasePath := "/tmp/NativeAgent"
- kvPairs := []string{
- fmt.Sprintf("%s=%s", filepath.Join(nativeBasePath, "lib", "apmAgent.jar"), nativeBasePath),
- fmt.Sprintf("%s=%d", "appId", appInfo.AppIdHash.IntVal),
- fmt.Sprintf("%s=%d", "agentId", appInfo.AgentId),
- fmt.Sprintf("%s=%d", "hostId", utils.GetHostID()),
- fmt.Sprintf("%s=%d", "accountId", utils.GetAccountID()),
- stackRule,
- }
- argkv := strings.Join(kvPairs, ",")
- klog.Infof("[Jvm stack uprobe] params:[%s]", argkv)
- args := []string{"load", "instrument", "false", argkv}
- jattacher := jattach.JvmJattacher{
- Pid: pid,
- Args: args,
- PrintOutput: 1,
- }
- res, err := jattacher.JAttach()
- klog.Infof("[Jvm stack uprobe] JAttach Result: %d", res)
- if err != nil {
- return err
- }
- return nil
- }
- func (t *Tracer) AttachJVMStackUprobes(pid uint32, appInfo AppInfo, rootfs string) ([]link.Link, error) {
- //path = utils.GetDefaultAgentsPath("NativeAgent", "libnativeAgent.so")
- //tmp/NativeAgentSo2297066477572820801.tmp
- path, err := FindNativeSoFromMapped(pid, "NativeAgentSo", ".tmp")
- if err != nil {
- klog.Error(err)
- return nil, err
- }
- path = filepath.Join(rootfs, path)
- setNodeEnter := "Java_com_cloudwise_agent_common_natives_TraceNative_setNodeEnter"
- setNodeReturn := "Java_com_cloudwise_agent_common_natives_TraceNative_setNodeReturn"
- klog.Infoln("[Jvm stack uprobe] Attach Start AttachJVMStackUprobes", path)
- var links []link.Link
- ex, err := link.OpenExecutable(path)
- if err != nil {
- klog.Error(err)
- return nil, err
- }
- klog.Infof("[Jvm stack uprobe] Attach Start [%s] [%s] ", setNodeEnter, setNodeReturn)
- uplink, err := ex.Uprobe(setNodeEnter, t.uprobes["setNodeEnter"], &link.UprobeOptions{Offset: 0x0, PID: int(pid)})
- if err != nil {
- klog.Errorf("[Jvm stack uprobe] Attaching ERROR: %v, %v, %v\n", err, setNodeEnter, uplink)
- return nil, err
- } else {
- links = append(links, uplink)
- }
- klog.Infoln("Attach Start " + setNodeReturn)
- uplink, err = ex.Uprobe(setNodeReturn, t.uprobes["setNodeReturn"], &link.UprobeOptions{Offset: 0x0})
- if err != nil {
- klog.Errorf("[Jvm stack uprobe] Attaching ERROR: %v, %v, %v\n", err, setNodeReturn, uplink)
- return nil, err
- } else {
- links = append(links, uplink)
- }
- return links, nil
- }
- func FindNativeSoFromMapped(pid uint32, prefix, suffix string) (string, error) {
- mapsFile := fmt.Sprintf("/proc/%d/maps", pid)
- tmpFile, err := os.Open(mapsFile)
- if err != nil {
- return "", fmt.Errorf("error opening maps file: %v", err)
- }
- defer tmpFile.Close()
- var selectedPath string
- var maxTimestamp int64
- fallbackPaths := make(map[string]struct{}) // 使用 map 去重
- scanner := bufio.NewScanner(tmpFile)
- for scanner.Scan() {
- line := scanner.Text()
- if strings.Contains(line, prefix) && strings.HasSuffix(line, suffix) {
- parts := strings.Fields(line)
- if len(parts) > 5 {
- path := parts[len(parts)-1]
- baseName := filepath.Base(path)
- if strings.HasPrefix(baseName, prefix) && strings.HasSuffix(baseName, suffix) {
- middle := strings.TrimSuffix(strings.TrimPrefix(baseName, prefix), suffix)
- segments := strings.Split(middle, ".")
- if len(segments) >= 2 {
- timestampStr := segments[len(segments)-1]
- timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
- if err == nil && timestamp > maxTimestamp {
- maxTimestamp = timestamp
- selectedPath = path
- }
- } else {
- fallbackPaths[path] = struct{}{}
- }
- }
- }
- }
- }
- if err = scanner.Err(); err != nil {
- return "", fmt.Errorf("error reading maps file: %v", err)
- }
- if selectedPath != "" {
- return selectedPath, nil
- }
- var latestPath string
- var latestModTime int64
- for path := range fallbackPaths {
- info, err := os.Stat(path)
- if err != nil {
- continue
- }
- stat, ok := info.Sys().(*syscall.Stat_t)
- if !ok {
- continue
- }
- modTime := stat.Mtim.Sec
- if modTime > latestModTime {
- latestModTime = modTime
- latestPath = path
- }
- }
- if latestPath != "" {
- return latestPath, nil
- }
- return "", fmt.Errorf("no matching path found")
- }
|