
This patch adds support for listing and setting breakpoints on inlined functions within stripped binaries. It uses a forked version of `debug/gosym` copied from golang.org/x/vuln/internal/vulncheck/internal/gosym which adds support for parsing the inline tree of the pclntab section. Parsing this section requires knowing the offset of the "go:func.*" symbol, which is not present in stripped binaries via the ``.symtab` section so instead, we search the `.noptrdata` section which contains `runtime.moduledatap` which contains the value of that missing symbol, which we then can use to find the inline tree for a given function. Given all this we parse the inline tree for each function we find, and then add that information the the appropriate `Function` contained in `bi.Functions`, using a relatively empty `Function` struct as what would be the abstract origin.
87 lines
2.5 KiB
Go
87 lines
2.5 KiB
Go
// This package implements the parsing and usage of the moduledata
|
|
// structs from a binary.
|
|
// This code is mostly taken and adapted from https://github.com/goretk/gore.
|
|
package moduledata
|
|
|
|
import (
|
|
"bytes"
|
|
"debug/elf"
|
|
"encoding/binary"
|
|
"errors"
|
|
)
|
|
|
|
// GetGoFuncValue is used to acquire the value of the
|
|
// "go:func.*" symbol in stripped binaries.
|
|
// TODO(derekparker) support Mach-O, PE.
|
|
func GetGoFuncValue(f *elf.File, pclntabAddr uint64) (uint64, error) {
|
|
s := f.Section(".noptrdata")
|
|
if s == nil {
|
|
return 0, errors.New("unable to find .noptrdata section")
|
|
}
|
|
data, err := s.Data()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
buf := new(bytes.Buffer)
|
|
err = binary.Write(buf, binary.LittleEndian, &pclntabAddr)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
off := bytes.Index(data, buf.Bytes()[:8])
|
|
|
|
var md moduledata2064
|
|
err = binary.Read(bytes.NewReader(data[off:off+0x340]), f.ByteOrder, &md)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return md.GoFunc, nil
|
|
}
|
|
|
|
type moduledata2064 struct {
|
|
PcHeader uint64
|
|
Funcnametab, Funcnametablen, Funcnametabcap uint64
|
|
Cutab, Cutablen, Cutabcap uint64
|
|
Filetab, Filetablen, Filetabcap uint64
|
|
Pctab, Pctablen, Pctabcap uint64
|
|
Pclntable, Pclntablelen, Pclntablecap uint64
|
|
Ftab, Ftablen, Ftabcap uint64
|
|
Findfunctab uint64
|
|
Minpc, Maxpc uint64
|
|
|
|
Text, Etext uint64
|
|
Noptrdata, Enoptrdata uint64
|
|
Data, Edata uint64
|
|
Bss, Ebss uint64
|
|
Noptrbss, Enoptrbss uint64
|
|
Covctrs, Ecovctrs uint64
|
|
End, Gcdata, Gcbss uint64
|
|
Types, Etypes uint64
|
|
RData uint64
|
|
GoFunc uint64
|
|
|
|
Textsectmap, Textsectmaplen, Textsectmapcap uint64
|
|
Typelinks, Typelinkslen, Typelinkscap uint64 // offsets from types
|
|
Itablinks, Itablinkslen, Itablinkscap uint64
|
|
|
|
Ptab, Ptablen, Ptabcap uint64
|
|
|
|
Pluginpath, Pluginpathlen uint64
|
|
Pkghashes, Pkghasheslen, Pkghashescap uint64
|
|
|
|
Modulename, Modulenamelen uint64
|
|
Modulehashes, Modulehasheslen, Modulehashescap uint64
|
|
|
|
/* These fields we are not planning to use so skipping the parsing of them.
|
|
|
|
hasmain uint8 // 1 if module contains the main function, 0 otherwise
|
|
|
|
gcdatamask, gcbssmask bitvector
|
|
|
|
typemap map[typeOff]*_type // offset to *_rtype in previous module
|
|
|
|
bad bool // module failed to load and should be ignored
|
|
|
|
next *moduledata
|
|
*/
|
|
}
|