summaryrefslogtreecommitdiff
path: root/libgo/go/debug/dwarf/line_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/debug/dwarf/line_test.go')
-rw-r--r--libgo/go/debug/dwarf/line_test.go232
1 files changed, 204 insertions, 28 deletions
diff --git a/libgo/go/debug/dwarf/line_test.go b/libgo/go/debug/dwarf/line_test.go
index 2476a6faf53..4104b5d49b8 100644
--- a/libgo/go/debug/dwarf/line_test.go
+++ b/libgo/go/debug/dwarf/line_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2015 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.
@@ -6,48 +6,224 @@ package dwarf_test
import (
. "debug/dwarf"
- "path/filepath"
+ "io"
"testing"
)
-type lineTest struct {
- pc uint64
- file string
- line int
-}
+var (
+ file1C = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line1.c"}
+ file1H = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line1.h"}
+ file2C = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line2.c"}
+)
-var elfLineTests = [...]lineTest{
- {0x4004c4, "typedef.c", 83},
- {0x4004c8, "typedef.c", 84},
- {0x4004ca, "typedef.c", 84},
- {0x4003e0, "", 0},
-}
+func TestLineELFGCC(t *testing.T) {
+ // Generated by:
+ // # gcc --version | head -n1
+ // gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
+ // # gcc -g -o line-gcc.elf line*.c
+
+ // Line table based on readelf --debug-dump=rawline,decodedline
+ want := []LineEntry{
+ {Address: 0x40059d, File: file1H, Line: 2, IsStmt: true},
+ {Address: 0x4005a5, File: file1H, Line: 2, IsStmt: true},
+ {Address: 0x4005b4, File: file1H, Line: 5, IsStmt: true},
+ {Address: 0x4005bd, File: file1H, Line: 6, IsStmt: true, Discriminator: 2},
+ {Address: 0x4005c7, File: file1H, Line: 5, IsStmt: true, Discriminator: 2},
+ {Address: 0x4005cb, File: file1H, Line: 5, IsStmt: false, Discriminator: 1},
+ {Address: 0x4005d1, File: file1H, Line: 7, IsStmt: true},
+ {Address: 0x4005e7, File: file1C, Line: 6, IsStmt: true},
+ {Address: 0x4005eb, File: file1C, Line: 7, IsStmt: true},
+ {Address: 0x4005f5, File: file1C, Line: 8, IsStmt: true},
+ {Address: 0x4005ff, File: file1C, Line: 9, IsStmt: true},
+ {Address: 0x400601, EndSequence: true},
-var machoLineTests = [...]lineTest{
- {0x0, "typedef.c", 83},
+ {Address: 0x400601, File: file2C, Line: 4, IsStmt: true},
+ {Address: 0x400605, File: file2C, Line: 5, IsStmt: true},
+ {Address: 0x40060f, File: file2C, Line: 6, IsStmt: true},
+ {Address: 0x400611, EndSequence: true},
+ }
+
+ testLineTable(t, want, elfData(t, "testdata/line-gcc.elf"))
}
-func TestLineElf(t *testing.T) {
- testLine(t, elfData(t, "testdata/typedef.elf"), elfLineTests[:], "elf")
+func TestLineELFClang(t *testing.T) {
+ // Generated by:
+ // # clang --version | head -n1
+ // Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)
+ // # clang -g -o line-clang.elf line*.
+
+ want := []LineEntry{
+ {Address: 0x400530, File: file1C, Line: 6, IsStmt: true},
+ {Address: 0x400534, File: file1C, Line: 7, IsStmt: true, PrologueEnd: true},
+ {Address: 0x400539, File: file1C, Line: 8, IsStmt: true},
+ {Address: 0x400545, File: file1C, Line: 9, IsStmt: true},
+ {Address: 0x400550, File: file1H, Line: 2, IsStmt: true},
+ {Address: 0x400554, File: file1H, Line: 5, IsStmt: true, PrologueEnd: true},
+ {Address: 0x400568, File: file1H, Line: 6, IsStmt: true},
+ {Address: 0x400571, File: file1H, Line: 5, IsStmt: true},
+ {Address: 0x400581, File: file1H, Line: 7, IsStmt: true},
+ {Address: 0x400583, EndSequence: true},
+
+ {Address: 0x400590, File: file2C, Line: 4, IsStmt: true},
+ {Address: 0x4005a0, File: file2C, Line: 5, IsStmt: true, PrologueEnd: true},
+ {Address: 0x4005a7, File: file2C, Line: 6, IsStmt: true},
+ {Address: 0x4005b0, EndSequence: true},
+ }
+
+ testLineTable(t, want, elfData(t, "testdata/line-clang.elf"))
}
-func TestLineMachO(t *testing.T) {
- testLine(t, machoData(t, "testdata/typedef.macho"), machoLineTests[:], "macho")
+func TestLineSeek(t *testing.T) {
+ d := elfData(t, "testdata/line-gcc.elf")
+
+ // Get the line table for the first CU.
+ cu, err := d.Reader().Next()
+ if err != nil {
+ t.Fatal("d.Reader().Next:", err)
+ }
+ lr, err := d.LineReader(cu)
+ if err != nil {
+ t.Fatal("d.LineReader:", err)
+ }
+
+ // Read entries forward.
+ var line LineEntry
+ var posTable []LineReaderPos
+ var table []LineEntry
+ for {
+ posTable = append(posTable, lr.Tell())
+
+ err := lr.Next(&line)
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ t.Fatal("lr.Next:", err)
+ }
+ table = append(table, line)
+ }
+
+ // Test that Reset returns to the first line.
+ lr.Reset()
+ if err := lr.Next(&line); err != nil {
+ t.Fatal("lr.Next after Reset failed:", err)
+ } else if line != table[0] {
+ t.Fatal("lr.Next after Reset returned", line, "instead of", table[0])
+ }
+
+ // Check that entries match when seeking backward.
+ for i := len(posTable) - 1; i >= 0; i-- {
+ lr.Seek(posTable[i])
+ err := lr.Next(&line)
+ if i == len(posTable)-1 {
+ if err != io.EOF {
+ t.Fatal("expected io.EOF after seek to end, got", err)
+ }
+ } else if err != nil {
+ t.Fatal("lr.Next after seek to", posTable[i], "failed:", err)
+ } else if line != table[i] {
+ t.Fatal("lr.Next after seek to", posTable[i], "returned", line, "instead of", table[i])
+ }
+ }
+
+ // Check that seeking to a PC returns the right line.
+ if err := lr.SeekPC(table[0].Address-1, &line); err != ErrUnknownPC {
+ t.Fatalf("lr.SeekPC to %#x returned %v instead of ErrUnknownPC", table[0].Address-1, err)
+ }
+ for i, testLine := range table {
+ if testLine.EndSequence {
+ if err := lr.SeekPC(testLine.Address, &line); err != ErrUnknownPC {
+ t.Fatalf("lr.SeekPC to %#x returned %v instead of ErrUnknownPC", testLine.Address, err)
+ }
+ continue
+ }
+
+ nextPC := table[i+1].Address
+ for pc := testLine.Address; pc < nextPC; pc++ {
+ if err := lr.SeekPC(pc, &line); err != nil {
+ t.Fatalf("lr.SeekPC to %#x failed: %v", pc, err)
+ } else if line != testLine {
+ t.Fatalf("lr.SeekPC to %#x returned %v instead of %v", pc, line, testLine)
+ }
+ }
+ }
}
-func testLine(t *testing.T, d *Data, tests []lineTest, kind string) {
- for _, v := range tests {
- file, line, err := d.FileLine(v.pc)
+func testLineTable(t *testing.T, want []LineEntry, d *Data) {
+ // Get line table from d.
+ var got []LineEntry
+ dr := d.Reader()
+ for {
+ ent, err := dr.Next()
if err != nil {
- t.Errorf("%s: %v", kind, err)
+ t.Fatal("dr.Next:", err)
+ } else if ent == nil {
+ break
+ }
+
+ if ent.Tag != TagCompileUnit {
+ dr.SkipChildren()
continue
}
- if file != "" {
- file = filepath.Base(file)
+
+ // Decode CU's line table.
+ lr, err := d.LineReader(ent)
+ if err != nil {
+ t.Fatal("d.LineReader:", err)
+ } else if lr == nil {
+ continue
}
- if file != v.file || line != v.line {
- t.Errorf("%s: for %d have %q:%d want %q:%d",
- kind, v.pc, file, line, v.file, v.line)
+
+ for {
+ var line LineEntry
+ err := lr.Next(&line)
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ t.Fatal("lr.Next:", err)
+ }
+ got = append(got, line)
}
}
+
+ // Compare line tables.
+ if !compareLines(got, want) {
+ t.Log("Line tables do not match. Got:")
+ dumpLines(t, got)
+ t.Log("Want:")
+ dumpLines(t, want)
+ t.FailNow()
+ }
+}
+
+func compareLines(a, b []LineEntry) bool {
+ if len(a) != len(b) {
+ return false
+ }
+
+ for i := range a {
+ al, bl := a[i], b[i]
+ // If both are EndSequence, then the only other valid
+ // field is Address. Otherwise, test equality of all
+ // fields.
+ if al.EndSequence && bl.EndSequence && al.Address == bl.Address {
+ continue
+ }
+ if al.File.Name != bl.File.Name {
+ return false
+ }
+ al.File = nil
+ bl.File = nil
+ if al != bl {
+ return false
+ }
+ }
+ return true
+}
+
+func dumpLines(t *testing.T, lines []LineEntry) {
+ for _, l := range lines {
+ t.Logf(" %+v File:%+v", l, l.File)
+ }
}