1
// Copyright 2009 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
15
// For now, only works on ELF platforms.
16
return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
19
func getTable(t *testing.T) *Table {
20
f, tab := crack(os.Args[0], t)
25
func crack(file string, t *testing.T) (*elf.File, *Table) {
27
f, err := elf.Open(file)
31
return parse(file, f, t)
34
func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
35
symdat, err := f.Section(".gosymtab").Data()
38
t.Fatalf("reading %s gosymtab: %v", file, err)
40
pclndat, err := f.Section(".gopclntab").Data()
43
t.Fatalf("reading %s gopclntab: %v", file, err)
46
pcln := NewLineTable(pclndat, f.Section(".text").Addr)
47
tab, err := NewTable(symdat, pcln)
50
t.Fatalf("parsing %s gosymtab: %v", file, err)
56
var goarch = os.Getenv("O")
58
func TestLineFromAline(t *testing.T) {
65
// Find the sym package
66
pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
71
// Walk every absolute line and ensure that we hit every
72
// source line monotonically
73
lastline := make(map[string]int)
75
for i := 0; i < 10000; i++ {
76
path, line := pkg.lineFromAline(i)
77
// Check for end of object
83
} else if final != -1 {
84
t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
86
// It's okay to see files multiple times (e.g., sys.a)
91
// Check that the is the next line in path
92
ll, ok := lastline[path]
94
t.Errorf("file %s starts on line %d", path, line)
95
} else if line != ll+1 {
96
t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
101
t.Errorf("never reached end of object")
105
func TestLineAline(t *testing.T) {
112
for _, o := range tab.Files {
113
// A source file can appear multiple times in a
114
// object. alineFromLine will always return alines in
115
// the first file, so track which lines we've seen.
116
found := make(map[string]int)
117
for i := 0; i < 1000; i++ {
118
path, line := o.lineFromAline(i)
123
// cgo files are full of 'Z' symbols, which we don't handle
124
if len(path) > 4 && path[len(path)-4:] == ".cgo" {
128
if minline, ok := found[path]; path != "" && ok {
130
// We've already covered this file
136
a, err := o.alineFromLine(path, line)
138
t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
140
t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
146
// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 -a "$GOARCH" = amd64 ]; then
147
// gotest: mkdir -p _test && $AS pclinetest.s && $LD -E main -o _test/pclinetest pclinetest.$O
149
func TestPCLine(t *testing.T) {
154
f, tab := crack("_test/pclinetest", t)
155
text := f.Section(".text")
156
textdat, err := text.Data()
158
t.Fatalf("reading .text: %v", err)
162
sym := tab.LookupFunc("linefrompc")
164
for pc := sym.Entry; pc < sym.End; pc++ {
165
file, line, fn := tab.PCToLine(pc)
166
off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
167
wantLine += int(textdat[off])
169
t.Errorf("failed to get line of PC %#x", pc)
170
} else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
171
t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
176
sym = tab.LookupFunc("pcfromline")
179
off := uint64(0) // TODO(rsc): should not need off; bug in 8g
180
for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
181
file, line, fn := tab.PCToLine(pc)
183
wantLine += int(textdat[off])
184
if line != wantLine {
185
t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
186
off = pc + 1 - text.Addr
189
if lookupline == -1 {
192
for ; lookupline <= line; lookupline++ {
193
pc2, fn2, err := tab.LineToPC(file, lookupline)
194
if lookupline != line {
195
// Should be nothing on this line
197
t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
199
} else if err != nil {
200
t.Errorf("failed to get PC of line %d: %s", lookupline, err)
201
} else if pc != pc2 {
202
t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
205
off = pc + 1 - text.Addr