pkg/proc: improve stripped binary support with PIE (#3421)

Take into account static base for PIE binaries.
This commit is contained in:
Derek Parker 2023-06-16 00:38:19 -07:00 committed by GitHub
parent 14d9c1881d
commit 656c4f13df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 6 additions and 47 deletions

@ -609,15 +609,15 @@ func (fn *Function) AllPCs(excludeFile string, excludeLine int) ([]uint64, error
return fn.cu.lineInfo.AllPCsBetween(fn.Entry, fn.End-1, excludeFile, excludeLine) return fn.cu.lineInfo.AllPCsBetween(fn.Entry, fn.End-1, excludeFile, excludeLine)
} }
var pcs []uint64 var pcs []uint64
fnFile, lastLine, _ := fn.cu.image.symTable.PCToLine(fn.Entry) fnFile, lastLine, _ := fn.cu.image.symTable.PCToLine(fn.Entry - fn.cu.image.StaticBase)
for pc := fn.Entry; pc < fn.End; pc++ { for pc := fn.Entry - fn.cu.image.StaticBase; pc < fn.End-fn.cu.image.StaticBase; pc++ {
f, line, pcfn := fn.cu.image.symTable.PCToLine(pc) f, line, pcfn := fn.cu.image.symTable.PCToLine(pc)
if pcfn == nil { if pcfn == nil {
continue continue
} }
if f == fnFile && line > lastLine { if f == fnFile && line > lastLine {
lastLine = line lastLine = line
pcs = append(pcs, pc) pcs = append(pcs, pc+fn.cu.image.StaticBase)
} }
} }
return pcs, nil return pcs, nil
@ -762,7 +762,7 @@ func (bi *BinaryInfo) EntryLineForFunc(fn *Function) (string, int) {
func (bi *BinaryInfo) pcToLine(fn *Function, pc uint64) (string, int) { func (bi *BinaryInfo) pcToLine(fn *Function, pc uint64) (string, int) {
if fn.cu.lineInfo == nil { if fn.cu.lineInfo == nil {
f, l, _ := fn.cu.image.symTable.PCToLine(pc) f, l, _ := fn.cu.image.symTable.PCToLine(pc - fn.cu.image.StaticBase)
return f, l return f, l
} }
f, l := fn.cu.lineInfo.PCToLine(fn.Entry, pc) f, l := fn.cu.lineInfo.PCToLine(fn.Entry, pc)
@ -1461,7 +1461,7 @@ func loadBinaryInfoElf(bi *BinaryInfo, image *Image, path string, addr uint64, w
for _, f := range image.symTable.Funcs { for _, f := range image.symTable.Funcs {
cu := &compileUnit{} cu := &compileUnit{}
cu.image = image cu.image = image
fn := Function{Name: f.Name, Entry: f.Entry, End: f.End, cu: cu} fn := Function{Name: f.Name, Entry: f.Entry + image.StaticBase, End: f.End + image.StaticBase, cu: cu}
bi.Functions = append(bi.Functions, fn) bi.Functions = append(bi.Functions, fn)
} }
for f := range image.symTable.Files { for f := range image.symTable.Files {

@ -1,40 +1,11 @@
package proc package proc
import ( import (
"bytes"
"debug/buildinfo"
"debug/elf" "debug/elf"
"debug/gosym" "debug/gosym"
"encoding/binary"
"fmt" "fmt"
"strings"
) )
// From go/src/debug/gosym/pclntab.go
const (
go12magic = 0xfffffffb
go116magic = 0xfffffffa
go118magic = 0xfffffff0
go120magic = 0xfffffff1
)
// Select the magic number based on the Go version
func magicNumber(goVersion string) []byte {
bs := make([]byte, 4)
var magic uint32
if strings.Compare(goVersion, "go1.20") >= 0 {
magic = go120magic
} else if strings.Compare(goVersion, "go1.18") >= 0 {
magic = go118magic
} else if strings.Compare(goVersion, "go1.16") >= 0 {
magic = go116magic
} else {
magic = go12magic
}
binary.LittleEndian.PutUint32(bs, magic)
return bs
}
func readPcLnTableElf(exe *elf.File, path string) (*gosym.Table, error) { func readPcLnTableElf(exe *elf.File, path string) (*gosym.Table, error) {
// Default section label is .gopclntab // Default section label is .gopclntab
sectionLabel := ".gopclntab" sectionLabel := ".gopclntab"
@ -42,7 +13,7 @@ func readPcLnTableElf(exe *elf.File, path string) (*gosym.Table, error) {
section := exe.Section(sectionLabel) section := exe.Section(sectionLabel)
if section == nil { if section == nil {
// binary may be built with -pie // binary may be built with -pie
sectionLabel = ".data.rel.ro" sectionLabel = ".data.rel.ro.gopclntab"
section = exe.Section(sectionLabel) section = exe.Section(sectionLabel)
if section == nil { if section == nil {
return nil, fmt.Errorf("could not read section .gopclntab") return nil, fmt.Errorf("could not read section .gopclntab")
@ -53,17 +24,6 @@ func readPcLnTableElf(exe *elf.File, path string) (*gosym.Table, error) {
return nil, fmt.Errorf("found section but could not read .gopclntab") return nil, fmt.Errorf("found section but could not read .gopclntab")
} }
bi, err := buildinfo.ReadFile(path)
if err != nil {
return nil, err
}
// Find .gopclntab by magic number even if there is no section label
magic := magicNumber(bi.GoVersion)
pclntabIndex := bytes.Index(tableData, magic)
if pclntabIndex >= 0 {
tableData = tableData[pclntabIndex:]
}
addr := exe.Section(".text").Addr addr := exe.Section(".text").Addr
lineTable := gosym.NewLineTable(tableData, addr) lineTable := gosym.NewLineTable(tableData, addr)
symTable, err := gosym.NewTable([]byte{}, lineTable) symTable, err := gosym.NewTable([]byte{}, lineTable)

@ -3169,7 +3169,6 @@ func TestDebugStripped(t *testing.T) {
// Currently only implemented for Linux ELF executables. // Currently only implemented for Linux ELF executables.
// TODO(derekparker): Add support for Mach-O and PE. // TODO(derekparker): Add support for Mach-O and PE.
skipUnlessOn(t, "linux only", "linux") skipUnlessOn(t, "linux only", "linux")
skipOn(t, "does not work with PIE", "pie")
withTestProcessArgs("testnextprog", t, "", []string{}, protest.LinkStrip, func(p *proc.Target, grp *proc.TargetGroup, f protest.Fixture) { withTestProcessArgs("testnextprog", t, "", []string{}, protest.LinkStrip, func(p *proc.Target, grp *proc.TargetGroup, f protest.Fixture) {
setFunctionBreakpoint(p, t, "main.main") setFunctionBreakpoint(p, t, "main.main")
assertNoError(grp.Continue(), t, "Continue") assertNoError(grp.Continue(), t, "Continue")