delve/pkg/internal/moduledata/moduledata_test.go
Derek Parker 6c77c35586
pkg/proc: add inline function support for stripped binaries (#3549)
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.
2023-11-03 10:00:49 +01:00

68 lines
1.4 KiB
Go

package moduledata
import (
"debug/elf"
"github.com/go-delve/delve/pkg/goversion"
"os"
"os/exec"
"runtime"
"testing"
)
func TestGetGoFuncValue(t *testing.T) {
if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
t.Skipf("skipping since not linux/amd64")
}
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 20) {
t.Skip("temporarily disabled on Go versions < 1.20")
}
bin := "getgofuncvaltestbin"
err := exec.Command("go", "build", "-o", bin, "../../../_fixtures/traceprog.go").Run()
if err != nil {
t.Fatal(err)
}
defer func(name string) {
err := os.Remove(name)
if err != nil {
t.Fatal(err)
}
}(bin)
file, err := elf.Open(bin)
if err != nil {
t.Fatal(err)
}
s := file.Section(".gopclntab")
goFuncValue, err := GetGoFuncValue(file, s.Addr)
if err != nil {
t.Fatal(err)
}
goFuncSymValue := getGoFuncSymValue(file, t)
if goFuncSymValue == 0 {
t.Fatal("unable to find value for go:func.* symbol")
}
t.Logf("gofuncVal: %#v goFuncSymValue: %#v\n", goFuncValue, goFuncSymValue)
if goFuncValue != goFuncSymValue {
t.Fatalf("expected goFuncValue %#v to equal goFuncSymValue %#v", goFuncValue, goFuncSymValue)
}
}
func getGoFuncSymValue(f *elf.File, t *testing.T) uint64 {
syms, err := f.Symbols()
if err != nil {
t.Fatal(err)
}
for i := range syms {
if syms[i].Name == "go:func.*" {
return syms[i].Value
}
}
return 0
}