diff --git a/interpreter/apmint/apmint.go b/interpreter/apmint/apmint.go index 5e9967ffa..8420889b5 100644 --- a/interpreter/apmint/apmint.go +++ b/interpreter/apmint/apmint.go @@ -20,7 +20,6 @@ import ( "go.opentelemetry.io/ebpf-profiler/host" "go.opentelemetry.io/ebpf-profiler/interpreter" "go.opentelemetry.io/ebpf-profiler/libpf" - "go.opentelemetry.io/ebpf-profiler/libpf/pfelf" "go.opentelemetry.io/ebpf-profiler/remotememory" "go.opentelemetry.io/ebpf-profiler/support" ) @@ -66,7 +65,7 @@ func Loader(_ interpreter.EbpfHandler, info *interpreter.LoaderInfo) (interprete // Resolve process storage symbol. procStorageSym, err := ef.LookupSymbol(procStorageExport) if err != nil { - if errors.Is(err, pfelf.ErrSymbolNotFound) { + if errors.Is(err, libpf.ErrSymbolNotFound) { // APM<->profiling integration not supported by agent. return nil, nil } diff --git a/interpreter/golabels/tls_amd64.go b/interpreter/golabels/tls_amd64.go index f5de769a8..2d4e88d36 100644 --- a/interpreter/golabels/tls_amd64.go +++ b/interpreter/golabels/tls_amd64.go @@ -8,6 +8,7 @@ package golabels // import "go.opentelemetry.io/ebpf-profiler/interpreter/golabe import ( log "github.com/sirupsen/logrus" "go.opentelemetry.io/ebpf-profiler/libpf/pfelf" + "go.opentelemetry.io/ebpf-profiler/nativeunwind/elfunwindinfo" "golang.org/x/arch/x86/x86asm" ) @@ -16,17 +17,17 @@ import ( // may be dynamic relocating going on so just read it from a known // symbol if possible. func extractTLSGOffset(f *pfelf.File) (int32, error) { - syms, err := f.ReadSymbols() + pclntab, err := elfunwindinfo.NewGopclntab(f) if err != nil { return 0, err } + defer pclntab.Close() + // Dump of assembler code for function runtime.stackcheck: // 0x0000000000470080 <+0>: mov %fs:0xfffffffffffffff8,%rax - sym, err := syms.LookupSymbol("runtime.stackcheck.abi0") + sym, err := pclntab.LookupSymbol("runtime.stackcheck") if err != nil { - // Binary must be stripped, hope default is correct and warn. - log.Warnf("Failed to find stackcheck symbol, Go labels might not work: %v", err) - return -8, nil + return 0, err } b, err := f.VirtualMemory(int64(sym.Address), 10, 10) if err != nil { diff --git a/libpf/pfelf/file.go b/libpf/pfelf/file.go index b75c60429..34e56b299 100644 --- a/libpf/pfelf/file.go +++ b/libpf/pfelf/file.go @@ -51,9 +51,6 @@ const ( // List of public errors. var ( - // ErrSymbolNotFound is returned when the requested symbol was not found. - ErrSymbolNotFound = errors.New("symbol not found") - // ErrNotELF is returned when the file is not an ELF file. ErrNotELF = errors.New("not an ELF file") ) @@ -955,7 +952,7 @@ func (f *File) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { mask := uint(1)<<(h%ptrSizeBits) | uint(1)<<((h>>hdr.bloomShift)%ptrSizeBits) if bloom&mask != mask { - return nil, ErrSymbolNotFound + return nil, libpf.ErrSymbolNotFound } // Read the initial symbol index to start looking from @@ -966,7 +963,7 @@ func (f *File) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { return nil, err } if i == 0 { - return nil, ErrSymbolNotFound + return nil, libpf.ErrSymbolNotFound } // Search the hash bucket @@ -1021,7 +1018,7 @@ func (f *File) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { return nil, errors.New("symbol hash not present") } - return nil, ErrSymbolNotFound + return nil, libpf.ErrSymbolNotFound } // LookupSymbol searches for a given symbol in the ELF diff --git a/libpf/symbol.go b/libpf/symbol.go index dd3c490ae..fd338589e 100644 --- a/libpf/symbol.go +++ b/libpf/symbol.go @@ -4,11 +4,18 @@ package libpf // import "go.opentelemetry.io/ebpf-profiler/libpf" import ( + "errors" "fmt" "sort" "strings" ) +// List of public errors. +var ( + // ErrSymbolNotFound is returned when the requested symbol was not found. + ErrSymbolNotFound = errors.New("symbol not found") +) + // SymbolValue represents the value associated with a symbol, e.g. either an // offset or an absolute address type SymbolValue uint64 diff --git a/nativeunwind/elfunwindinfo/elfgopclntab.go b/nativeunwind/elfunwindinfo/elfgopclntab.go index 03cf1727d..4d82a104e 100644 --- a/nativeunwind/elfunwindinfo/elfgopclntab.go +++ b/nativeunwind/elfunwindinfo/elfgopclntab.go @@ -17,6 +17,7 @@ import ( "strings" "unsafe" + "go.opentelemetry.io/ebpf-profiler/libpf" "go.opentelemetry.io/ebpf-profiler/libpf/pfelf" sdtypes "go.opentelemetry.io/ebpf-profiler/nativeunwind/stackdeltatypes" "go.opentelemetry.io/ebpf-profiler/support" @@ -351,6 +352,30 @@ type Gopclntab struct { functab, funcdata, funcnametab, filetab, pctab, cutab []byte } +// LookupSymbol searches for a given symbol in .gopclntab. +func (g *Gopclntab) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { + symString := string(symbol) + for i := 0; i < g.numFuncs; i++ { + _, funcOff := g.getFuncMapEntry(i) + pc, fun := g.getFunc(funcOff) + if fun == nil { + continue + } + name := getString(g.funcnametab, int(fun.nameOff)) + if name == symString { + nextPc, _ := g.getFuncMapEntry(i + 1) + size := uint64(nextPc - pc) + + return &libpf.Symbol{ + Name: symbol, + Address: libpf.SymbolValue(pc), + Size: size, + }, nil + } + } + return nil, libpf.ErrSymbolNotFound +} + // NewGopclntab parses and returns the parsed data for further operations. func NewGopclntab(ef *pfelf.File) (*Gopclntab, error) { data, err := extractGoPclntab(ef)