Skip to content

Commit

Permalink
Fix support for missing .text section (#1597)
Browse files Browse the repository at this point in the history
  • Loading branch information
grcevski authored Jan 31, 2025
1 parent f7b77e6 commit d2aa90a
Showing 1 changed file with 29 additions and 9 deletions.
38 changes: 29 additions & 9 deletions pkg/internal/goexec/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package goexec
import (
"debug/elf"
"debug/gosym"
"encoding/binary"
"fmt"
"log/slog"
"strings"
Expand Down Expand Up @@ -31,6 +32,7 @@ func instrumentationPoints(elfF *elf.File, funcNames []string) (map[string]FuncO
for _, fn := range funcNames {
functions[fn] = struct{}{}
}

symTab, err := findGoSymbolTable(elfF)
if err != nil {
return nil, err
Expand All @@ -47,10 +49,7 @@ func instrumentationPoints(elfF *elf.File, funcNames []string) (map[string]FuncO
// no go symbols in the executable, maybe it's statically linked
// find regular elf symbols
if gosyms == nil {
allSyms, err = exec.FindExeSymbols(elfF, funcNames)
if err != nil {
return nil, err
}
allSyms, _ = exec.FindExeSymbols(elfF, funcNames)
}

// check which functions in the symbol table correspond to any of the functions
Expand All @@ -67,7 +66,7 @@ func instrumentationPoints(elfF *elf.File, funcNames []string) (map[string]FuncO
// when we don't have a Go symbol table, the executable is statically linked, we don't look for offsets
// using the gosym tab, we lookup offsets just like a regular elf file.
// we still need to find the return statements, since go linkage is non-standard we can't use uretprobe
if gosyms == nil {
if gosyms == nil && len(allSyms) > 0 {
handleStaticSymbol(fName, allOffsets, allSyms, ilog)
continue
}
Expand Down Expand Up @@ -146,12 +145,33 @@ func findGoSymbolTable(elfF *elf.File) (*gosym.Table, error) {
return nil, fmt.Errorf("acquiring .gopclntab data: %w", err)
}
}
txtSection := elfF.Section(".text")
if txtSection == nil {
return nil, fmt.Errorf("can't find .text section in ELF file")

// Borrowed from OpenTelemetry Go Auto-Instrumentation
// we extract the `textStart` value based on the header of the pclntab,
// this is used to parse the line number table, and is not necessarily the start of the `.text` section.
// when a binary is built with C code, the value of `textStart` is not the same as the start of the `.text` section.
// https://github.com/golang/go/blob/master/src/runtime/symtab.go#L374
var runtimeText uint64

if len(pclndat) > 8*2*8 {
ptrSize := uint32(pclndat[7])
switch ptrSize {
case 4:
runtimeText = uint64(binary.LittleEndian.Uint32(pclndat[8+2*ptrSize:]))
case 8:
runtimeText = binary.LittleEndian.Uint64(pclndat[8+2*ptrSize:])
default:
return nil, fmt.Errorf("unknown .gopclntab text ptr size")
}
} else {
txtSection := elfF.Section(".text")
if txtSection == nil {
return nil, fmt.Errorf("can't find .text section in ELF file")
}
runtimeText = txtSection.Addr
}

pcln := gosym.NewLineTable(pclndat, txtSection.Addr)
pcln := gosym.NewLineTable(pclndat, runtimeText)
// First argument accepts the .gosymtab ELF section.
// Since Go 1.3, .gosymtab is empty so we just pass an nil slice
symTab, err := gosym.NewTable(nil, pcln)
Expand Down

0 comments on commit d2aa90a

Please sign in to comment.