Skip to content

Commit

Permalink
Support resolve symbols in mini debug info
Browse files Browse the repository at this point in the history
  • Loading branch information
zmj64351508 committed Sep 25, 2024
1 parent a73673b commit 74acae1
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 89 deletions.
3 changes: 3 additions & 0 deletions ebpf/symtab/elf.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ func (et *ElfTable) createSymbolTable(me *elf2.MMapedElfFile) (SymbolNameResolve
symbolOptions.FilterTo = goTable.Index.End
}
symTable, symErr := me.NewSymbolTable(&symbolOptions)
if symErr != nil && goErr != nil {
symTable, symErr = me.NewMiniDebugInfoSymbolTable(&symbolOptions)
}
if symErr != nil && goErr != nil {
return nil, fmt.Errorf("s: %s g: %s", symErr.Error(), goErr.Error())
}
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
}
87 changes: 10 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,14 @@ func NewMMapedElfFile(fpath string) (*MMapedElfFile, error) {
res.Close()
return nil, err
}
elfFile, err := elf.NewFile(res.fd)
res.InMemElfFile, 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

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 +51,9 @@ func (f *MMapedElfFile) Close() {
f.fd.Close()
f.fd = nil
}
f.stringCache = nil
f.Sections = nil
if f.InMemElfFile != nil {
f.InMemElfFile.Clear()
}
}
func (f *MMapedElfFile) open() error {
if f.err != nil {
Expand All @@ -104,18 +65,17 @@ func (f *MMapedElfFile) open() error {
return fmt.Errorf("open elf file %s %w", f.fpath, err)
}
f.fd = fd
if f.InMemElfFile != nil {
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 +87,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

0 comments on commit 74acae1

Please sign in to comment.