mirror of
https://github.com/golang/go
synced 2024-09-30 11:18:33 -06: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()
|
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