aboutsummaryrefslogtreecommitdiff
path: root/src/debug
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2019-08-21 16:21:06 -0400
committerAustin Clements <austin@google.com>2019-09-18 19:09:02 +0000
commit861556c5d7b83a75a66549ca4c7199e343f5eb40 (patch)
tree295c1620405a9ba3a6999c859c821545c933ecca /src/debug
parentbc40294d47f100b6da4b21823cf85d11ce931c1b (diff)
downloadgo-861556c5d7b83a75a66549ca4c7199e343f5eb40.tar.gz
go-861556c5d7b83a75a66549ca4c7199e343f5eb40.zip
debug/dwarf: expose file name table from line table reader
Currently, the line table reader keeps the file name table internal. However, there are various attributes like AttrDeclFile and AttrCallFile whose value is an index into this table. Hence, in order to interpret these attributes, we need access to the file name table. This CL adds a method to LineReader that exposes the file table of the current compilation unit in order to allow consumers to interpret attributes that index into this table. Change-Id: I6b64b815f23b3b0695036ddabe1a67c3954867dd Reviewed-on: https://go-review.googlesource.com/c/go/+/192699 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/debug')
-rw-r--r--src/debug/dwarf/line.go29
-rw-r--r--src/debug/dwarf/line_test.go58
2 files changed, 81 insertions, 6 deletions
diff --git a/src/debug/dwarf/line.go b/src/debug/dwarf/line.go
index 4fc1896dbc..1cd9dd98cf 100644
--- a/src/debug/dwarf/line.go
+++ b/src/debug/dwarf/line.go
@@ -441,6 +441,19 @@ func (r *LineReader) readFileEntry() (bool, error) {
mtime := r.buf.uint()
length := int(r.buf.uint())
+ // If this is a dynamically added path and the cursor was
+ // backed up, we may have already added this entry. Avoid
+ // updating existing line table entries in this case. This
+ // avoids an allocation and potential racy access to the slice
+ // backing store if the user called Files.
+ if len(r.fileEntries) < cap(r.fileEntries) {
+ fe := r.fileEntries[:len(r.fileEntries)+1]
+ if fe[len(fe)-1] != nil {
+ // We already processed this addition.
+ r.fileEntries = fe
+ return false, nil
+ }
+ }
r.fileEntries = append(r.fileEntries, &LineFile{name, mtime, length})
return false, nil
}
@@ -692,6 +705,22 @@ func (r *LineReader) resetState() {
r.updateFile()
}
+// Files returns the file name table of this compilation unit as of
+// the current position in the line table. The file name table may be
+// referenced from attributes in this compilation unit such as
+// AttrDeclFile.
+//
+// Entry 0 is always nil, since file index 0 represents "no file".
+//
+// The file name table of a compilation unit is not fixed. Files
+// returns the file table as of the current position in the line
+// table. This may contain more entries than the file table at an
+// earlier position in the line table, though existing entries never
+// change.
+func (r *LineReader) Files() []*LineFile {
+ return r.fileEntries
+}
+
// ErrUnknownPC is the error returned by LineReader.ScanPC when the
// seek PC is not covered by any entry in the line table.
var ErrUnknownPC = errors.New("ErrUnknownPC")
diff --git a/src/debug/dwarf/line_test.go b/src/debug/dwarf/line_test.go
index 11a254464a..1fd9b19b03 100644
--- a/src/debug/dwarf/line_test.go
+++ b/src/debug/dwarf/line_test.go
@@ -43,8 +43,9 @@ func TestLineELFGCC(t *testing.T) {
{Address: 0x40060f, File: file2C, Line: 6, IsStmt: true},
{Address: 0x400611, EndSequence: true},
}
+ files := [][]*LineFile{{nil, file1H, file1C}, {nil, file2C}}
- testLineTable(t, want, elfData(t, "testdata/line-gcc.elf"))
+ testLineTable(t, want, files, elfData(t, "testdata/line-gcc.elf"))
}
func TestLineGCCWindows(t *testing.T) {
@@ -83,8 +84,9 @@ func TestLineGCCWindows(t *testing.T) {
{Address: 0x401595, File: file2C, Line: 6, IsStmt: true},
{Address: 0x40159b, EndSequence: true},
}
+ files := [][]*LineFile{{nil, file1H, file1C}, {nil, file2C}}
- testLineTable(t, want, peData(t, "testdata/line-gcc-win.bin"))
+ testLineTable(t, want, files, peData(t, "testdata/line-gcc-win.bin"))
}
func TestLineELFClang(t *testing.T) {
@@ -110,8 +112,9 @@ func TestLineELFClang(t *testing.T) {
{Address: 0x4005a7, File: file2C, Line: 6, IsStmt: true},
{Address: 0x4005b0, EndSequence: true},
}
+ files := [][]*LineFile{{nil, file1C, file1H}, {nil, file2C}}
- testLineTable(t, want, elfData(t, "testdata/line-clang.elf"))
+ testLineTable(t, want, files, elfData(t, "testdata/line-clang.elf"))
}
func TestLineSeek(t *testing.T) {
@@ -190,7 +193,7 @@ func TestLineSeek(t *testing.T) {
}
}
-func testLineTable(t *testing.T, want []LineEntry, d *Data) {
+func testLineTable(t *testing.T, want []LineEntry, files [][]*LineFile, d *Data) {
// Get line table from d.
var got []LineEntry
dr := d.Reader()
@@ -207,6 +210,12 @@ func testLineTable(t *testing.T, want []LineEntry, d *Data) {
continue
}
+ // Ignore system compilation units (this happens in
+ // the Windows binary). We'll still decode the line
+ // table, but won't check it.
+ name := ent.Val(AttrName).(string)
+ ignore := strings.HasPrefix(name, "C:/crossdev/") || strings.HasPrefix(name, "../../")
+
// Decode CU's line table.
lr, err := d.LineReader(ent)
if err != nil {
@@ -225,12 +234,23 @@ func testLineTable(t *testing.T, want []LineEntry, d *Data) {
t.Fatal("lr.Next:", err)
}
// Ignore sources from the Windows build environment.
- if strings.HasPrefix(line.File.Name, "C:\\crossdev\\") ||
- strings.HasPrefix(line.File.Name, "C:/crossdev/") {
+ if ignore {
continue
}
got = append(got, line)
}
+
+ // Check file table.
+ if !ignore {
+ if !compareFiles(files[0], lr.Files()) {
+ t.Log("File tables do not match. Got:")
+ dumpFiles(t, lr.Files())
+ t.Log("Want:")
+ dumpFiles(t, files[0])
+ t.Fail()
+ }
+ files = files[1:]
+ }
}
// Compare line tables.
@@ -243,6 +263,32 @@ func testLineTable(t *testing.T, want []LineEntry, d *Data) {
}
}
+func compareFiles(a, b []*LineFile) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := range a {
+ if a[i] == nil && b[i] == nil {
+ continue
+ }
+ if a[i] != nil && b[i] != nil && a[i].Name == b[i].Name {
+ continue
+ }
+ return false
+ }
+ return true
+}
+
+func dumpFiles(t *testing.T, files []*LineFile) {
+ for i, f := range files {
+ name := "<nil>"
+ if f != nil {
+ name = f.Name
+ }
+ t.Logf(" %d %s", i, name)
+ }
+}
+
func compareLines(a, b []LineEntry) bool {
if len(a) != len(b) {
return false