package ebpftracer import ( "errors" "io/ioutil" "strings" "debug/elf" "fmt" "path/filepath" "github.com/coroot/coroot-node-agent/utils" "github.com/cilium/ebpf/link" "golang.org/x/arch/x86/x86asm" ) const ( // goServeHTTP = "net/http.serverHandler.ServeHTTP" // binPath = "/root/code/jdk8u/build/linux-x86_64-normal-server-release/jdk/lib/amd64/libnio.so" symbolsocketRead0 = "Java_sun_nio_ch_FileDispatcherImpl_read0" ) func (t *Tracer) AttachJavaNioReadUprobes(pid uint32, insID utils.ID) []link.Link { if t.disableL7Tracing { return nil } version := UsePIDToGetJDKVersion(pid) fmt.Println("java version is ", version) var links []link.Link bpath := getSoPath(pid, "nio.so") if bpath == "" { fmt.Println("can,t find the nio.so") return nil } fmt.Println("find the nio.so path is ", bpath) ex, err := link.OpenExecutable(bpath) if err != nil { fmt.Println("link.OpenExecutable error", err) return nil } fmt.Println("=============") l, err := ex.Uprobe("Java_sun_nio_ch_FileDispatcherImpl_read0", t.uprobes["uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0"], &link.UprobeOptions{Offset: uint64(47)}) fmt.Println(err) links = append(links, l) fmt.Println("=============") //return links ef, err := elf.Open(bpath) fmt.Println("open the elf file ", err) if err != nil { return nil //PID: int(pid), } defer ef.Close() symbols, err := ef.Symbols() fmt.Println("ef.Symbols error", err) if err != nil { if errors.Is(err, elf.ErrNoSymbols) { return nil } return nil } textSection := ef.Section(".text") if textSection == nil { fmt.Println("textSection is null") return nil } textSectionData, err := textSection.Data() if err != nil { fmt.Println("textSectionData error is", err) return nil } textSectionLen := uint64(len(textSectionData) - 1) // opt := link.UprobeOptions{ // Offset: 61, // } // upread02, err := ex.Uprobe(symbolsocketRead0, t.uprobes["uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0"], &opt) // if err != nil { // return nil // } // links = append(links, upread01) for _, s := range symbols { if elf.ST_TYPE(s.Info) != elf.STT_FUNC || s.Size == 0 { continue } switch s.Name { case symbolsocketRead0: default: continue } address := s.Value for _, p := range ef.Progs { if p.Type != elf.PT_LOAD || (p.Flags&elf.PF_X) == 0 { continue } if p.Vaddr <= s.Value && s.Value < (p.Vaddr+p.Memsz) { address = s.Value - p.Vaddr + p.Off break } } fmt.Println("s.Name-----:", s.Name) switch s.Name { case symbolsocketRead0: sStart := s.Value - textSection.Addr sEnd := sStart + s.Size if sEnd > textSectionLen { continue } sBytes := textSectionData[sStart:sEnd] returnOffsets := getCallNextMoveOffsets(ef.Machine, sBytes) if len(returnOffsets) == 0 { return nil } for _, offset := range returnOffsets { l, err := ex.Uprobe(s.Name, t.uprobes["uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0"], &link.UprobeOptions{Address: address, Offset: uint64(offset)}) if err != nil { fmt.Println("failed to attach uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0 uprobe") return nil } links = append(links, l) } } } if len(links) == 0 { return nil } fmt.Println("jvm uprobes attached, pid is ", pid) return links } func (t *Tracer) AttachJavaNetReadUprobes(pid uint32, insID utils.ID) []link.Link { if t.disableL7Tracing { return nil } // //if pid != 251719 { // return nil //} var libnetSo = "/root/carl/libnet.so" var sys = "Java_java_net_SocketOutputStream_socketWrite0" var links []link.Link ex, err := link.OpenExecutable(libnetSo) if err != nil { return nil } opt := link.UprobeOptions{ Offset: 66, PID: int(pid), } upread02, err := ex.Uprobe(sys, t.uprobes["uprobe_Java_java_net_SocketOutputStream_socketWrite0"], &opt) if err != nil { return nil } links = append(links, upread02) if len(links) == 0 { return nil } fmt.Println("jvm client uprobes attached", pid) return links } func getCallNextMoveOffsets(machine elf.Machine, instructions []byte) []int { var res []int firstCall := 0 switch machine { case elf.EM_X86_64: for i := 0; i < len(instructions); { ins, err := x86asm.Decode(instructions[i:], 64) if err == nil && ins.Op == x86asm.CALL { if firstCall == 0 { firstCall = 1 } else { i += ins.Len res = append(res, i) return res } } i += ins.Len } } return res } func getSoPath(pid uint32, soname string) string { // 获取进程的maps文件路径 mapsPath := fmt.Sprintf("/proc/%d/maps", pid) // 读取maps文件内容 mapsData, err := ioutil.ReadFile(mapsPath) if err != nil { fmt.Println("无法读取maps文件") return "" } lines := strings.Split(string(mapsData), "\n") for _, line := range lines { fields := strings.Fields(line) if len(fields) >= 6 { perms := fields[1] path := fields[len(fields)-1] if strings.Contains(perms, "x") && filepath.Ext(path) == ".so" { if strings.Contains(path, soname) { return path } } } } return "" }