From: Michael Pratt Date: Thu, 15 Dec 2022 22:17:01 +0000 (-0500) Subject: cmd/link/internal/ld: add dwarf testing helpers X-Git-Tag: go1.21rc1~1739 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=87860873efdcc3fde7327eb4c3a9d3e6ea33d245;p=gostls13.git 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 Reviewed-by: Cherry Mui Auto-Submit: Michael Pratt Run-TryBot: Michael Pratt TryBot-Result: Gopher Robot --- diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index a11541f320..e3a2109445 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -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) - - 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") - } + opt := opt + t.Run(opt, func(t *testing.T) { + _, ex := gobuildAndExamine(t, prog, opt) + + // 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") + } + }) } }