Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support resolve symbols in mini debug info(".gnu_debugdata") #3590

Merged
merged 3 commits into from
Oct 1, 2024
Merged
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
1 change: 1 addition & 0 deletions ebpf/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
github.com/prometheus/prometheus v0.51.2
github.com/samber/lo v1.38.1
github.com/stretchr/testify v1.9.0
github.com/ulikunitz/xz v0.5.12
golang.org/x/sys v0.25.0
)

Expand Down
2 changes: 2 additions & 0 deletions ebpf/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
Expand Down
25 changes: 23 additions & 2 deletions ebpf/symtab/elf.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,30 @@ func (et *ElfTable) createSymbolTable(me *elf2.MMapedElfFile) (SymbolNameResolve
symbolOptions.FilterFrom = goTable.Index.Entry.Get(0)
symbolOptions.FilterTo = goTable.Index.End
}
symTable, symErr := me.NewSymbolTable(&symbolOptions)
origSymTable, origErr := me.NewSymbolTable(&symbolOptions)

var symTable elf2.SymbolTableInterface
var symErr error
if origErr == nil && origSymTable.HasSection(elf.SHT_SYMTAB) {
symTable = origSymTable
symErr = nil
} else {
miniSymTable, miniErr := me.NewMiniDebugInfoSymbolTable(&symbolOptions)
if origErr != nil && miniErr != nil {
symTable = nil
symErr = fmt.Errorf("o: %s m: %s", origErr.Error(), miniErr.Error())
} else {
tab := &elf2.SymbolTableWithMiniDebugInfo{
Primary: origSymTable,
MiniDebug: miniSymTable,
}
symTable = tab
symErr = nil
}
}

if symErr != nil && goErr != nil {
return nil, fmt.Errorf("s: %s g: %s", symErr.Error(), goErr.Error())
return nil, fmt.Errorf("s: {%s} g: {%s}", symErr.Error(), goErr.Error())
}
if symErr == nil && goErr == nil {
return &elf2.GoTableWithFallback{
Expand Down
6 changes: 3 additions & 3 deletions ebpf/symtab/elf/elf_sym.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type SymbolsOptions struct {
}

// todo consider using ReaderAt here, same as in gopcln
func (f *MMapedElfFile) getSymbols(typ elf.SectionType, opt *SymbolsOptions) ([]SymbolIndex, uint32, error) {
func (f *InMemElfFile) getSymbols(typ elf.SectionType, opt *SymbolsOptions) ([]SymbolIndex, uint32, error) {
switch f.Class {
case elf.ELFCLASS64:
return f.getSymbols64(typ, opt)
Expand All @@ -51,7 +51,7 @@ func (f *MMapedElfFile) getSymbols(typ elf.SectionType, opt *SymbolsOptions) ([]
// if there is no such section in the File.
var ErrNoSymbols = errors.New("no symbol section")

func (f *MMapedElfFile) getSymbols64(typ elf.SectionType, opt *SymbolsOptions) ([]SymbolIndex, uint32, error) {
func (f *InMemElfFile) getSymbols64(typ elf.SectionType, opt *SymbolsOptions) ([]SymbolIndex, uint32, error) {
symtabSection := f.sectionByType(typ)
if symtabSection == nil {
return nil, 0, ErrNoSymbols
Expand Down Expand Up @@ -108,7 +108,7 @@ func (f *MMapedElfFile) getSymbols64(typ elf.SectionType, opt *SymbolsOptions) (
return symbols[:i], symtabSection.Link, nil
}

func (f *MMapedElfFile) getSymbols32(typ elf.SectionType, opt *SymbolsOptions) ([]SymbolIndex, uint32, error) {
func (f *InMemElfFile) getSymbols32(typ elf.SectionType, opt *SymbolsOptions) ([]SymbolIndex, uint32, error) {
symtabSection := f.sectionByType(typ)
if symtabSection == nil {
return nil, 0, ErrNoSymbols
Expand Down
114 changes: 114 additions & 0 deletions ebpf/symtab/elf/elfinmem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package elf

import (
"bytes"
"debug/elf"
"io"
"strings"

"github.com/ianlancetaylor/demangle"
)

type ElfSymbolReader interface {
getString(start int, demangleOptions []demangle.Option) (string, bool)
}

type InMemElfFile struct {
elf.FileHeader
Sections []elf.SectionHeader
Progs []elf.ProgHeader
stringCache map[int]string

reader io.ReaderAt
}

func NewInMemElfFile(r io.ReaderAt) (*InMemElfFile, error) {
res := &InMemElfFile{
reader: r,
}
elfFile, err := elf.NewFile(res.reader)
if err != nil {
return nil, err
}
progs := make([]elf.ProgHeader, 0, len(elfFile.Progs))
sections := make([]elf.SectionHeader, 0, len(elfFile.Sections))
for i := range elfFile.Progs {
progs = append(progs, elfFile.Progs[i].ProgHeader)
}
for i := range elfFile.Sections {
sections = append(sections, elfFile.Sections[i].SectionHeader)
}
res.FileHeader = elfFile.FileHeader
res.Progs = progs
res.Sections = sections
return res, nil
}

func (f *InMemElfFile) Clear() {
f.stringCache = nil
f.Sections = nil
}

func (f *InMemElfFile) resetReader(r io.ReaderAt) {
f.reader = r
}

func (f *InMemElfFile) Section(name string) *elf.SectionHeader {
for i := range f.Sections {
s := &f.Sections[i]
if s.Name == name {
return s
}
}
return nil
}

func (f *InMemElfFile) sectionByType(typ elf.SectionType) *elf.SectionHeader {
for i := range f.Sections {
s := &f.Sections[i]
if s.Type == typ {
return s
}
}
return nil
}

func (f *InMemElfFile) SectionData(s *elf.SectionHeader) ([]byte, error) {
res := make([]byte, s.Size)
if _, err := f.reader.ReadAt(res, int64(s.Offset)); err != nil {
return nil, err
}
return res, nil
}

// getString extracts a string from an ELF string table.
func (f *InMemElfFile) getString(start int, demangleOptions []demangle.Option) (string, bool) {
if s, ok := f.stringCache[start]; ok {
return s, true
}
const tmpBufSize = 128
var tmpBuf [tmpBufSize]byte
sb := strings.Builder{}
for i := 0; i < 10; i++ {
_, err := f.reader.ReadAt(tmpBuf[:], int64(start+i*tmpBufSize))
if err != nil {
return "", false
}
idx := bytes.IndexByte(tmpBuf[:], 0)
if idx >= 0 {
sb.Write(tmpBuf[:idx])
s := sb.String()
if len(demangleOptions) > 0 {
s = demangle.Filter(s, demangleOptions...)
}
if f.stringCache == nil {
f.stringCache = make(map[int]string)
}
f.stringCache[start] = s
return s, true
} else {
sb.Write(tmpBuf[:])
}
}
return "", false
}
84 changes: 7 additions & 77 deletions ebpf/symtab/elf/elfmmap.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
package elf

import (
"bytes"
"debug/elf"
"fmt"
"os"
"runtime"
"strings"

"github.com/ianlancetaylor/demangle"
)

type MMapedElfFile struct {
elf.FileHeader
Sections []elf.SectionHeader
Progs []elf.ProgHeader

InMemElfFile
fpath string
err error
fd *os.File

stringCache map[int]string
}

func NewMMapedElfFile(fpath string) (*MMapedElfFile, error) {
Expand All @@ -32,47 +25,15 @@ func NewMMapedElfFile(fpath string) (*MMapedElfFile, error) {
res.Close()
return nil, err
}
elfFile, err := elf.NewFile(res.fd)
f, err := NewInMemElfFile(res.fd)
if err != nil {
res.Close()
return nil, err
}
progs := make([]elf.ProgHeader, 0, len(elfFile.Progs))
sections := make([]elf.SectionHeader, 0, len(elfFile.Sections))
for i := range elfFile.Progs {
progs = append(progs, elfFile.Progs[i].ProgHeader)
}
for i := range elfFile.Sections {
sections = append(sections, elfFile.Sections[i].SectionHeader)
}
res.FileHeader = elfFile.FileHeader
res.Progs = progs
res.Sections = sections

res.InMemElfFile = *f
runtime.SetFinalizer(res, (*MMapedElfFile).Finalize)
return res, nil
}

func (f *MMapedElfFile) Section(name string) *elf.SectionHeader {
for i := range f.Sections {
s := &f.Sections[i]
if s.Name == name {
return s
}
}
return nil
}

func (f *MMapedElfFile) sectionByType(typ elf.SectionType) *elf.SectionHeader {
for i := range f.Sections {
s := &f.Sections[i]
if s.Type == typ {
return s
}
}
return nil
}

func (f *MMapedElfFile) ensureOpen() error {
if f.fd != nil {
return nil
Expand All @@ -91,8 +52,7 @@ func (f *MMapedElfFile) Close() {
f.fd.Close()
f.fd = nil
}
f.stringCache = nil
f.Sections = nil
f.InMemElfFile.Clear()
}
func (f *MMapedElfFile) open() error {
if f.err != nil {
Expand All @@ -104,18 +64,15 @@ func (f *MMapedElfFile) open() error {
return fmt.Errorf("open elf file %s %w", f.fpath, err)
}
f.fd = fd
f.InMemElfFile.resetReader(f.fd)
return nil
}

func (f *MMapedElfFile) SectionData(s *elf.SectionHeader) ([]byte, error) {
if err := f.ensureOpen(); err != nil {
return nil, err
}
res := make([]byte, s.Size)
if _, err := f.fd.ReadAt(res, int64(s.Offset)); err != nil {
return nil, err
}
return res, nil
return f.InMemElfFile.SectionData(s)
}

func (f *MMapedElfFile) FilePath() string {
Expand All @@ -127,32 +84,5 @@ func (f *MMapedElfFile) getString(start int, demangleOptions []demangle.Option)
if err := f.ensureOpen(); err != nil {
return "", false
}
if s, ok := f.stringCache[start]; ok {
return s, true
}
const tmpBufSize = 128
var tmpBuf [tmpBufSize]byte
sb := strings.Builder{}
for i := 0; i < 10; i++ {
_, err := f.fd.ReadAt(tmpBuf[:], int64(start+i*tmpBufSize))
if err != nil {
return "", false
}
idx := bytes.IndexByte(tmpBuf[:], 0)
if idx >= 0 {
sb.Write(tmpBuf[:idx])
s := sb.String()
if len(demangleOptions) > 0 {
s = demangle.Filter(s, demangleOptions...)
}
if f.stringCache == nil {
f.stringCache = make(map[int]string)
}
f.stringCache[start] = s
return s, true
} else {
sb.Write(tmpBuf[:])
}
}
return "", false
return f.InMemElfFile.getString(start, demangleOptions)
}
Loading
Loading