Commit 861556c5 authored by Austin Clements's avatar Austin Clements

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: default avatarThan McIntosh <thanm@google.com>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent bc40294d
......@@ -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")
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment