mirror of
https://github.com/golang/go
synced 2024-11-24 09:20:02 -07:00
cmd/link: new DWARF line table test case
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>
This commit is contained in:
parent
f98b9ae07c
commit
09e791feb1
@ -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)
|
||||
}
|
||||
}
|
||||
|
11
src/cmd/link/internal/ld/testdata/issue38192/main.go
vendored
Normal file
11
src/cmd/link/internal/ld/testdata/issue38192/main.go
vendored
Normal file
@ -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()
|
||||
}
|
8
src/cmd/link/internal/ld/testdata/issue38192/oneline.s
vendored
Normal file
8
src/cmd/link/internal/ld/testdata/issue38192/oneline.s
vendored
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user