aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/ld/dwarf_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link/internal/ld/dwarf_test.go')
-rw-r--r--src/cmd/link/internal/ld/dwarf_test.go119
1 files changed, 119 insertions, 0 deletions
diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go
index fb9c45b07d..f3dd53792a 100644
--- a/src/cmd/link/internal/ld/dwarf_test.go
+++ b/src/cmd/link/internal/ld/dwarf_test.go
@@ -1479,3 +1479,122 @@ func TestIssue38192(t *testing.T) {
t.Logf("row %d: A=%x F=%s L=%d\n", i, r.Address, r.File.Name, r.Line)
}
}
+
+func TestIssue39757(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping on plan9; no DWARF symbol table in executables")
+ }
+
+ // In this bug the DWARF line table contents for the last couple of
+ // instructions in a function were incorrect (bad file/line). This
+ // test verifies that all of the line table rows for a function
+ // of interest have the same file (no "autogenerated").
+ //
+ // Note: the function in this test was written with an eye towards
+ // ensuring that there are no inlined routines from other packages
+ // (which could introduce other source files into the DWARF); it's
+ // possible that at some point things could evolve in the
+ // compiler/runtime in ways that aren't happening now, so this
+ // might be something to check for if it does start failing.
+
+ tmpdir, err := ioutil.TempDir("", "TestIssue38192")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(tmpdir)
+ wd, err := os.Getwd()
+ if err != nil {
+ t.Fatalf("where am I? %v", err)
+ }
+ pdir := filepath.Join(wd, "testdata", "issue39757")
+ f := gobuildTestdata(t, tmpdir, pdir, DefaultOpt)
+
+ syms, err := f.Symbols()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var addr uint64
+ for _, sym := range syms {
+ if sym.Name == "main.main" {
+ addr = sym.Addr
+ break
+ }
+ }
+ if addr == 0 {
+ t.Fatal("cannot find main.main in symbols")
+ }
+
+ // Open the resulting binary and examine the DWARF it contains.
+ // Look for the function of interest ("main.main")
+ // and verify that all line table entries show the same source
+ // file.
+ dw, err := f.DWARF()
+ if err != nil {
+ t.Fatalf("error parsing DWARF: %v", err)
+ }
+ rdr := dw.Reader()
+ ex := 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]
+
+ // Collect the start/end PC for main.main
+ lowpc := maindie.Val(dwarf.AttrLowpc).(uint64)
+ highpc := maindie.Val(dwarf.AttrHighpc).(uint64)
+
+ // Now read the line table for the 'main' compilation unit.
+ mainIdx := ex.idxFromOffset(maindie.Offset)
+ cuentry := ex.Parent(mainIdx)
+ if cuentry == nil {
+ t.Fatalf("main.main DIE appears orphaned")
+ }
+ lnrdr, lerr := dw.LineReader(cuentry)
+ if lerr != nil {
+ t.Fatalf("error creating DWARF line reader: %v", err)
+ }
+ if lnrdr == nil {
+ t.Fatalf("no line table for main.main compilation unit")
+ }
+ rows := []dwarf.LineEntry{}
+ mainrows := 0
+ var lne dwarf.LineEntry
+ for {
+ err := lnrdr.Next(&lne)
+ if err == io.EOF {
+ break
+ }
+ rows = append(rows, lne)
+ if err != nil {
+ t.Fatalf("error reading next DWARF line: %v", err)
+ }
+ if lne.Address < lowpc || lne.Address > highpc {
+ continue
+ }
+ if !strings.HasSuffix(lne.File.Name, "issue39757main.go") {
+ t.Errorf("found row with file=%s (not issue39757main.go)", lne.File.Name)
+ }
+ mainrows++
+ }
+ f.Close()
+
+ // Make sure we saw a few rows.
+ if mainrows < 3 {
+ t.Errorf("not enough line table rows for main.main (got %d, wanted > 3", mainrows)
+ for i, r := range rows {
+ t.Logf("row %d: A=%x F=%s L=%d\n", i, r.Address, r.File.Name, r.Line)
+ }
+ }
+}