Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion ebpf/symtab/elf/go_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,67 @@ var (
errGoSymbolsNotFound = errors.New("gosymtab: no go symbols found")
)

// findRuntimeTextSymbol looks up the "runtime.text" symbol from .symtab.
// Since Go 1.26, pcHeader.textStart is always zero: the linker no longer
// stores the text base in pclntab (the field required the only relocation
// in that section and was otherwise unused).
// See: https://github.com/golang/go/commit/0e1bd8b5f17e337df0ffb57af03419b96c695fe4
func (f *MMapedElfFile) findRuntimeTextSymbol() uint64 {
symtabSection := f.sectionByType(elf.SHT_SYMTAB)
if symtabSection == nil {
return 0
}
// Find the linked string table section.
if int(symtabSection.Link) >= len(f.Sections) {
return 0
}
strtabSection := &f.Sections[symtabSection.Link]

symData, err := f.SectionData(symtabSection)
if err != nil {
return 0
}
strData, err := f.SectionData(strtabSection)
if err != nil {
return 0
}

var symSize int
var getValue func([]byte) uint64
switch f.Class {
case elf.ELFCLASS64:
symSize = elf.Sym64Size
getValue = func(b []byte) uint64 { return f.ByteOrder.Uint64(b[8:16]) }
case elf.ELFCLASS32:
symSize = elf.Sym32Size
getValue = func(b []byte) uint64 { return uint64(f.ByteOrder.Uint32(b[4:8])) }
default:
return 0
}

// Skip first (null) entry.
if len(symData) < symSize {
return 0
}
symData = symData[symSize:]

target := "runtime.text\x00"
for len(symData) >= symSize {
entry := symData[:symSize]
symData = symData[symSize:]

nameIdx := int(f.ByteOrder.Uint32(entry[:4]))
end := nameIdx + len(target)
if nameIdx < 0 || end > len(strData) {
continue
}
if string(strData[nameIdx:end]) == target {
return getValue(entry)
}
}
return 0
}

func (f *MMapedElfFile) NewGoTable() (*GoTable, error) {
obj := f
var err error
Expand All @@ -90,7 +151,12 @@ func (f *MMapedElfFile) NewGoTable() (*GoTable, error) {
textStart := gosym2.ParseRuntimeTextFromPclntab18(pclntabHeader)

if textStart == 0 {
// for older versions text.Addr is enough
// pcHeader.textStart is zero (Go 1.26+), fall back to .symtab.
textStart = f.findRuntimeTextSymbol()
}
if textStart == 0 {
// Fallback: use the .text section virtual address.
// For non-PIE pure-Go binaries, runtime.text == .text section address.
// https://github.com/golang/go/commit/b38ab0ac5f78ac03a38052018ff629c03e36b864
textStart = text.Addr
}
Expand Down
2 changes: 2 additions & 0 deletions ebpf/symtab/elf/go_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ func TestSelfGoSymbolComparison(t *testing.T) {
{"./testdata/elfs/go16-static", false}, // this one switches from 32 to 64 in the middle
{"./testdata/elfs/go18-static", false}, // this one starts with 64
{"./testdata/elfs/go20-static", true},
{"./testdata/elfs/go26", true}, // Go 1.26: pcHeader.textStart is always zero
{"./testdata/elfs/go26-static", true}, // Go 1.26: static build
}
for _, testcase := range ts {
t.Run(testcase.f, func(t *testing.T) {
Expand Down
7 changes: 7 additions & 0 deletions ebpf/symtab/elf/testdata/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,21 @@ ADD hello.go hello.go
RUN go build hello.go
RUN go build -ldflags="-extldflags=-static" -o hello-static hello.go

FROM --platform=linux/amd64 golang:1.26 as go126
ADD hello.go hello.go
RUN go build hello.go
RUN go build -ldflags="-extldflags=-static" -o hello-static hello.go

FROM scratch
COPY --from=builder elf elf.debug elf.stripped elf.debuglink elf.nopie elf.nobuildid libexample.so ./elfs/
COPY --from=builder /usr/lib/debug/ ./usr/lib/debug/
COPY --from=go12 /go/hello ./elfs/go12
COPY --from=go116 /go/hello ./elfs/go16
COPY --from=go118 /go/hello ./elfs/go18
COPY --from=go120 /go/hello ./elfs/go20
COPY --from=go126 /go/hello ./elfs/go26
COPY --from=go12 /go/hello-static ./elfs/go12-static
COPY --from=go116 /go/hello-static ./elfs/go16-static
COPY --from=go118 /go/hello-static ./elfs/go18-static
COPY --from=go120 /go/hello-static ./elfs/go20-static
COPY --from=go126 /go/hello-static ./elfs/go26-static
Binary file added ebpf/symtab/elf/testdata/elfs/go26
Binary file not shown.
Binary file added ebpf/symtab/elf/testdata/elfs/go26-static
Binary file not shown.