1
0
mirror of https://github.com/golang/go synced 2024-11-26 08:38:01 -07:00

cmd/link/internal/ld: add dwarf testing helpers

Many tests build a program just to analyze it with dwtest.Examiner. Add
gobuildAndExamine, a helper that returns Examiner directly to reduce
duplication in these tests.

Many tests also lookup the DIE for a specific subprogram, which includes
several verification steps. Package those up in findSubprogramDIE.

Change-Id: I72202ba289ae8389b682be525ff7e6cfbfc00ff3
Reviewed-on: https://go-review.googlesource.com/c/go/+/458196
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
Run-TryBot: Michael Pratt <mpratt@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Michael Pratt 2022-12-15 17:17:01 -05:00 committed by Gopher Robot
parent d42c08a2be
commit 87860873ef

View File

@ -135,6 +135,45 @@ func gobuildTestdata(t *testing.T, tdir string, pkgDir string, gcflags string) *
return &builtFile{f, dst}
}
// Helper to build a snippet of source for examination with dwtest.Examiner.
func gobuildAndExamine(t *testing.T, source string, gcflags string) (*dwarf.Data, *dwtest.Examiner) {
dir := t.TempDir()
f := gobuild(t, dir, source, gcflags)
defer f.Close()
d, err := f.DWARF()
if err != nil {
t.Fatalf("error reading DWARF in program %q: %v", source, err)
}
rdr := d.Reader()
ex := &dwtest.Examiner{}
if err := ex.Populate(rdr); err != nil {
t.Fatalf("error populating DWARF examiner for program %q: %v", source, err)
}
return d, ex
}
func findSubprogramDIE(t *testing.T, ex *dwtest.Examiner, sym string) *dwarf.Entry {
dies := ex.Named(sym)
if len(dies) == 0 {
t.Fatalf("unable to locate DIE for %s", sym)
}
if len(dies) != 1 {
t.Fatalf("more than one %s DIE: %+v", sym, dies)
}
die := dies[0]
// Vet the DIE.
if die.Tag != dwarf.TagSubprogram {
t.Fatalf("unexpected tag %v on %s DIE", die.Tag, sym)
}
return die
}
func TestEmbeddedStructMarker(t *testing.T) {
t.Parallel()
testenv.MustHaveGoBuild(t)
@ -341,21 +380,7 @@ func varDeclCoordsAndSubprogramDeclFile(t *testing.T, testpoint string, expectFi
prog := fmt.Sprintf("package main\n%s\nfunc main() {\n\nvar i int\ni = i\n}\n", directive)
const iLineOffset = 2
dir := t.TempDir()
f := gobuild(t, dir, prog, NoOpt)
defer f.Close()
d, err := f.DWARF()
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
rdr := d.Reader()
ex := dwtest.Examiner{}
if err := ex.Populate(rdr); err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
d, ex := gobuildAndExamine(t, prog, NoOpt)
// Locate the main.main DIE
mains := ex.Named("main.main")
@ -466,44 +491,17 @@ func main() {
G = x
}
`
dir := t.TempDir()
// Note: this is a build with "-l=4", as opposed to "-l -N". The
// test is intended to verify DWARF that is only generated when
// the inliner is active. We're only going to look at the DWARF for
// main.main, however, hence we build with "-gcflags=-l=4" as opposed
// to "-gcflags=all=-l=4".
f := gobuild(t, dir, prog, OptInl4)
defer f.Close()
d, err := f.DWARF()
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
d, ex := gobuildAndExamine(t, prog, OptInl4)
// The inlined subroutines we expect to visit
expectedInl := []string{"main.cand"}
rdr := d.Reader()
ex := dwtest.Examiner{}
if err := ex.Populate(rdr); err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
// Locate the main.main DIE
mains := ex.Named("main.main")
if len(mains) == 0 {
t.Fatalf("unable to locate DIE for main.main")
}
if len(mains) != 1 {
t.Fatalf("more than one main.main DIE")
}
maindie := mains[0]
// Vet the main.main DIE
if maindie.Tag != dwarf.TagSubprogram {
t.Fatalf("unexpected tag %v on main.main DIE", maindie.Tag)
}
maindie := findSubprogramDIE(t, ex, "main.main")
// Walk main's children and pick out the inlined subroutines
mainIdx := ex.IdxFromOffset(maindie.Offset)
@ -1334,20 +1332,12 @@ func TestIssue39757(t *testing.T) {
t.Fatalf("error parsing DWARF: %v", err)
}
rdr := dw.Reader()
ex := dwtest.Examiner{}
ex := &dwtest.Examiner{}
if err := ex.Populate(rdr); err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
// Locate the main.main DIE
mains := ex.Named("main.main")
if len(mains) == 0 {
t.Fatalf("unable to locate DIE for main.main")
}
if len(mains) != 1 {
t.Fatalf("more than one main.main DIE")
}
maindie := mains[0]
maindie := findSubprogramDIE(t, ex, "main.main")
// Collect the start/end PC for main.main
lowpc := maindie.Val(dwarf.AttrLowpc).(uint64)
@ -1556,38 +1546,12 @@ func main() {
println(v1, v2, v3[0], v4, v5, v6)
}
`
dir := t.TempDir()
f := gobuild(t, dir, prog, NoOpt)
defer f.Close()
_, ex := gobuildAndExamine(t, prog, NoOpt)
d, err := f.DWARF()
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
rdr := d.Reader()
ex := dwtest.Examiner{}
if err := ex.Populate(rdr); err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
// Locate the main.ABC DIE
abcs := ex.Named("main.ABC")
if len(abcs) == 0 {
t.Fatalf("unable to locate DIE for main.ABC")
}
if len(abcs) != 1 {
t.Fatalf("more than one main.ABC DIE")
}
abcdie := abcs[0]
// Vet the DIE
if abcdie.Tag != dwarf.TagSubprogram {
t.Fatalf("unexpected tag %v on main.ABC DIE", abcdie.Tag)
}
abcdie := findSubprogramDIE(t, ex, "main.ABC")
// Call a helper to collect param info.
found := processParams(abcdie, &ex)
found := processParams(abcdie, ex)
// Make sure we see all of the expected params in the proper
// order, that they have the varparam attr, and the varparam is
@ -1788,20 +1752,7 @@ func main() {
}
`
dir := t.TempDir()
f := gobuild(t, dir, prog, DefaultOpt)
defer f.Close()
d, err := f.DWARF()
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
rdr := d.Reader()
ex := dwtest.Examiner{}
if err := ex.Populate(rdr); err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
_, ex := gobuildAndExamine(t, prog, DefaultOpt)
testcases := []struct {
tag string
@ -1828,22 +1779,10 @@ func main() {
for _, tc := range testcases {
// Locate the proper DIE
which := fmt.Sprintf("main.%s", tc.tag)
tcs := ex.Named(which)
if len(tcs) == 0 {
t.Fatalf("unable to locate DIE for " + which)
}
if len(tcs) != 1 {
t.Fatalf("more than one " + which + " DIE")
}
die := tcs[0]
// Vet the DIE
if die.Tag != dwarf.TagSubprogram {
t.Fatalf("unexpected tag %v on "+which+" DIE", die.Tag)
}
die := findSubprogramDIE(t, ex, which)
// Examine params for this subprogram.
foundParams := processParams(die, &ex)
foundParams := processParams(die, ex)
if foundParams != tc.expected {
t.Errorf("check failed for testcase %s -- wanted:\n%s\ngot:%s\n",
tc.tag, tc.expected, foundParams)
@ -1956,29 +1895,18 @@ func main() {
`
for _, opt := range []string{NoOpt, DefaultOpt} {
dir := t.TempDir()
f := gobuild(t, dir, prog, opt)
defer f.Close()
defer os.RemoveAll(dir)
opt := opt
t.Run(opt, func(t *testing.T) {
_, ex := gobuildAndExamine(t, prog, opt)
d, err := f.DWARF()
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
rdr := d.Reader()
ex := dwtest.Examiner{}
if err := ex.Populate(rdr); err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
// Locate the main.zeroSizedVariable DIE
abcs := ex.Named("zeroSizedVariable")
if len(abcs) == 0 {
t.Fatalf("unable to locate DIE for zeroSizedVariable")
}
if len(abcs) != 1 {
t.Fatalf("more than one zeroSizedVariable DIE")
}
// Locate the main.zeroSizedVariable DIE
abcs := ex.Named("zeroSizedVariable")
if len(abcs) == 0 {
t.Fatalf("unable to locate DIE for zeroSizedVariable")
}
if len(abcs) != 1 {
t.Fatalf("more than one zeroSizedVariable DIE")
}
})
}
}