]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: new DWARF line table test case
authorThan McIntosh <thanm@google.com>
Mon, 1 Jun 2020 14:24:46 +0000 (10:24 -0400)
committerThan McIntosh <thanm@google.com>
Wed, 3 Jun 2020 18:03:41 +0000 (18:03 +0000)
Add a test case for an issue with how Go emits DWARF line tables,
specifically relating to the line table "end sequence" operator.

Updates #38192.

Change-Id: I878b262e6ca6c550c0e460c3d5a1969ac4a2c31b
Reviewed-on: https://go-review.googlesource.com/c/go/+/235917
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
src/cmd/link/internal/ld/dwarf_test.go
src/cmd/link/internal/ld/testdata/issue38192/main.go [new file with mode: 0644]
src/cmd/link/internal/ld/testdata/issue38192/oneline.s [new file with mode: 0644]

index a1c8496eeae6987e726de71b785e49ff5b13084e..fb9c45b07d011e905e57ebb12044bb996f48e910 100644 (file)
@@ -1368,3 +1368,114 @@ func main() {
                rdr.SkipChildren()
        }
 }
+
+func TestIssue38192(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       if runtime.GOOS == "plan9" {
+               t.Skip("skipping on plan9; no DWARF symbol table in executables")
+       }
+
+       // Build a test program that contains a translation unit whose
+       // text (from am assembly source) contains only a single instruction.
+       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", "issue38192")
+       f := gobuildTestdata(t, tmpdir, pdir, DefaultOpt)
+
+       // Open the resulting binary and examine the DWARF it contains.
+       // Look for the function of interest ("main.singleInstruction")
+       // and verify that the line table has an entry not just for the
+       // single instruction but also a dummy instruction following it,
+       // so as to test that whoever is emitting the DWARF doesn't
+       // emit an end-sequence op immediately after the last instruction
+       // in the translation unit.
+       //
+       // NB: another way to write this test would have been to run the
+       // resulting executable under GDB, set a breakpoint in
+       // "main.singleInstruction", then verify that GDB displays the
+       // correct line/file information.  Given the headache and flakiness
+       // associated with GDB-based tests these days, a direct read of
+       // the line table seems more desirable.
+       rows := []dwarf.LineEntry{}
+       dw, err := f.DWARF()
+       if err != nil {
+               t.Fatalf("error parsing DWARF: %v", err)
+       }
+       rdr := dw.Reader()
+       for {
+               e, err := rdr.Next()
+               if err != nil {
+                       t.Fatalf("error reading DWARF: %v", err)
+               }
+               if e == nil {
+                       break
+               }
+               if e.Tag != dwarf.TagCompileUnit {
+                       continue
+               }
+               // NB: there can be multiple compile units named "main".
+               name := e.Val(dwarf.AttrName).(string)
+               if name != "main" {
+                       continue
+               }
+               lnrdr, err := dw.LineReader(e)
+               if err != nil {
+                       t.Fatalf("error creating DWARF line reader: %v", err)
+               }
+               if lnrdr != nil {
+                       var lne dwarf.LineEntry
+                       for {
+                               err := lnrdr.Next(&lne)
+                               if err == io.EOF {
+                                       break
+                               }
+                               if err != nil {
+                                       t.Fatalf("error reading next DWARF line: %v", err)
+                               }
+                               if !strings.HasSuffix(lne.File.Name, "ld/testdata/issue38192/oneline.s") {
+                                       continue
+                               }
+                               rows = append(rows, lne)
+                       }
+               }
+               rdr.SkipChildren()
+       }
+       f.Close()
+
+       // Make sure that:
+       // - main.singleInstruction appears in the line table
+       // - more than one PC value appears the line table for
+       //   that compilation unit.
+       // - at least one row has the correct line number (8)
+       pcs := make(map[uint64]bool)
+       line8seen := false
+       for _, r := range rows {
+               pcs[r.Address] = true
+               if r.Line == 8 {
+                       line8seen = true
+               }
+       }
+       failed := false
+       if len(pcs) < 2 {
+               failed = true
+               t.Errorf("not enough line table rows for main.singleInstruction (got %d, wanted > 1", len(pcs))
+       }
+       if !line8seen {
+               failed = true
+               t.Errorf("line table does not contain correct line for main.singleInstruction")
+       }
+       if !failed {
+               return
+       }
+       for i, r := range rows {
+               t.Logf("row %d: A=%x F=%s L=%d\n", i, r.Address, r.File.Name, r.Line)
+       }
+}
diff --git a/src/cmd/link/internal/ld/testdata/issue38192/main.go b/src/cmd/link/internal/ld/testdata/issue38192/main.go
new file mode 100644 (file)
index 0000000..3b7df60
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func singleInstruction()
+
+func main() {
+       singleInstruction()
+}
diff --git a/src/cmd/link/internal/ld/testdata/issue38192/oneline.s b/src/cmd/link/internal/ld/testdata/issue38192/oneline.s
new file mode 100644 (file)
index 0000000..f5290d7
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+TEXT ·singleInstruction(SB),NOSPLIT,$0
+        RET