package tracer import ( "debug/dwarf" "debug/elf" "errors" "fmt" "github.com/cilium/ebpf" "io" "k8s.io/klog/v2" "net" "os" "strings" ) const ( offsetInferServerAddr = "127.0.0.1" offsetInferServerPort = 54583 bufferSize = 16 ) type ID struct { // ModPath is the module path containing the struct field package. // // If set to "std", the struct field belongs to the standard Go library. ModPath string // PkgPath package import path containing the struct field. PkgPath string // Struct is the name of the struct containing the field. Struct string // Field is the field name. Field string } func kernelOffsetInferServer(listener net.Listener) error { klog.Info("[eBPF Kernel Adapt] kernel_offset_infer_server started.") //cpuOnlineCount := runtime.NumCPU() go func() { for { conn, err := listener.Accept() if err != nil { klog.Errorf("[eBPF Kernel Adapt] Fail to accept client request: %v", err) return } go handleConnection(conn) } }() return nil } func handleConnection(conn net.Conn) { defer conn.Close() buffer := make([]byte, bufferSize) for { n, err := conn.Read(buffer) if err != nil { if err == io.EOF { klog.Errorf("[eBPF Kernel Adapt] client connection closed: %v", err) return } klog.Errorf("[eBPF Kernel Adapt] Error reading from connection: %v", err) return } //if n == 0 { // *clientCount++ // break //} request := strings.TrimSpace(string(buffer[:n])) fmt.Println(request) if request == "hello" { _, err := conn.Write([]byte("OK")) if err != nil { klog.Errorf("[eBPF Kernel Adapt] Error writing response: %v", err) break } } } } func kernelOffsetInferClient() error { conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", offsetInferServerAddr, offsetInferServerPort)) if err != nil { return fmt.Errorf("failed to connect to server: %v", err) } defer conn.Close() klog.Infoln("[eBPF Kernel Adapt] kernel_offset_infer_client started.") request := "hello" _, err = conn.Write([]byte(request)) if err != nil { return fmt.Errorf("failed to send request to server: %v", err) } buffer := make([]byte, bufferSize) for { n, err := conn.Read(buffer) if err != nil { fmt.Printf("[eBPF Kernel Adapt] Error reading response from server: %v\n", err) break } if n == 0 { break } response := strings.TrimSpace(string(buffer[:n])) klog.Infoln(response) if response == "OK" { break } } klog.Infoln("[eBPF Kernel Adapt] kernel_offset_infer_client finished.") return nil } func NewID(mod, pkg, strct, field string) ID { return ID{ModPath: mod, PkgPath: pkg, Struct: strct, Field: field} } func gotoEntry(r *dwarf.Reader, tag dwarf.Tag, name string) bool { _, err := findEntry(r, tag, name) return err == nil } // findEntry returns the DWARF entry with a tag equal to name read from r. An // error is returned if the entry cannot be found. func findEntry(r *dwarf.Reader, tag dwarf.Tag, name string) (*dwarf.Entry, error) { for { entry, err := r.Next() if err == io.EOF || entry == nil { break } if entry.Tag == tag { if f, ok := entryField(entry, dwarf.AttrName); ok { if name == f.Val.(string) { return entry, nil } } } } return nil, errors.New("not found") } // entryField returns the DWARF field from DWARF entry e that has the passed // DWARF attribute a. func entryField(e *dwarf.Entry, a dwarf.Attr) (dwarf.Field, bool) { for _, f := range e.Field { if f.Attr == a { return f, true } } return dwarf.Field{}, false } func GetOffset(id ID, path string) (uint64, bool) { strct := fmt.Sprintf("%s.%s", id.PkgPath, id.Struct) elfF, err := elf.Open(path) if err != nil { os.Exit(1) } defer elfF.Close() data, err := elfF.DWARF() fmt.Println(err) r := data.Reader() if !gotoEntry(r, dwarf.TagStructType, strct) { return 0, false } e, err := findEntry(r, dwarf.TagMember, id.Field) if err != nil { return 0, false } f, ok := entryField(e, dwarf.AttrDataMemberLoc) if !ok { return 0, false } return uint64(f.Val.(int64)), true } func UpdateProcInfoToMap(collection *ebpf.Collection, pid uint32, proc any) (int, error) { return bpf_table_set_value(collection, MAP_PROC_INFO_MAP_NAME, pid, proc) }