mirror of
https://github.com/golang/go
synced 2024-11-19 03:44:40 -07:00
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>
This commit is contained in:
parent
bc40294d47
commit
861556c5d7
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user