~john-koepi/ubuntu/trusty/golang/default

« back to all changes in this revision

Viewing changes to src/pkg/debug/gosym/pclntab_test.go

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-04-20 17:36:48 UTC
  • Revision ID: james.westby@ubuntu.com-20110420173648-ifergoxyrm832trd
Tags: upstream-2011.03.07.1
Import upstream version 2011.03.07.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
4
 
 
5
package gosym
 
6
 
 
7
import (
 
8
        "debug/elf"
 
9
        "os"
 
10
        "testing"
 
11
        "syscall"
 
12
)
 
13
 
 
14
func dotest() bool {
 
15
        // For now, only works on ELF platforms.
 
16
        return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
 
17
}
 
18
 
 
19
func getTable(t *testing.T) *Table {
 
20
        f, tab := crack(os.Args[0], t)
 
21
        f.Close()
 
22
        return tab
 
23
}
 
24
 
 
25
func crack(file string, t *testing.T) (*elf.File, *Table) {
 
26
        // Open self
 
27
        f, err := elf.Open(file)
 
28
        if err != nil {
 
29
                t.Fatal(err)
 
30
        }
 
31
        return parse(file, f, t)
 
32
}
 
33
 
 
34
func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
 
35
        symdat, err := f.Section(".gosymtab").Data()
 
36
        if err != nil {
 
37
                f.Close()
 
38
                t.Fatalf("reading %s gosymtab: %v", file, err)
 
39
        }
 
40
        pclndat, err := f.Section(".gopclntab").Data()
 
41
        if err != nil {
 
42
                f.Close()
 
43
                t.Fatalf("reading %s gopclntab: %v", file, err)
 
44
        }
 
45
 
 
46
        pcln := NewLineTable(pclndat, f.Section(".text").Addr)
 
47
        tab, err := NewTable(symdat, pcln)
 
48
        if err != nil {
 
49
                f.Close()
 
50
                t.Fatalf("parsing %s gosymtab: %v", file, err)
 
51
        }
 
52
 
 
53
        return f, tab
 
54
}
 
55
 
 
56
var goarch = os.Getenv("O")
 
57
 
 
58
func TestLineFromAline(t *testing.T) {
 
59
        if !dotest() {
 
60
                return
 
61
        }
 
62
 
 
63
        tab := getTable(t)
 
64
 
 
65
        // Find the sym package
 
66
        pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
 
67
        if pkg == nil {
 
68
                t.Fatalf("nil pkg")
 
69
        }
 
70
 
 
71
        // Walk every absolute line and ensure that we hit every
 
72
        // source line monotonically
 
73
        lastline := make(map[string]int)
 
74
        final := -1
 
75
        for i := 0; i < 10000; i++ {
 
76
                path, line := pkg.lineFromAline(i)
 
77
                // Check for end of object
 
78
                if path == "" {
 
79
                        if final == -1 {
 
80
                                final = i - 1
 
81
                        }
 
82
                        continue
 
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)
 
85
                }
 
86
                // It's okay to see files multiple times (e.g., sys.a)
 
87
                if line == 1 {
 
88
                        lastline[path] = 1
 
89
                        continue
 
90
                }
 
91
                // Check that the is the next line in path
 
92
                ll, ok := lastline[path]
 
93
                if !ok {
 
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)
 
97
                }
 
98
                lastline[path] = line
 
99
        }
 
100
        if final == -1 {
 
101
                t.Errorf("never reached end of object")
 
102
        }
 
103
}
 
104
 
 
105
func TestLineAline(t *testing.T) {
 
106
        if !dotest() {
 
107
                return
 
108
        }
 
109
 
 
110
        tab := getTable(t)
 
111
 
 
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)
 
119
                        if path == "" {
 
120
                                break
 
121
                        }
 
122
 
 
123
                        // cgo files are full of 'Z' symbols, which we don't handle
 
124
                        if len(path) > 4 && path[len(path)-4:] == ".cgo" {
 
125
                                continue
 
126
                        }
 
127
 
 
128
                        if minline, ok := found[path]; path != "" && ok {
 
129
                                if minline >= line {
 
130
                                        // We've already covered this file
 
131
                                        continue
 
132
                                }
 
133
                        }
 
134
                        found[path] = line
 
135
 
 
136
                        a, err := o.alineFromLine(path, line)
 
137
                        if err != nil {
 
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)
 
139
                        } else if a != i {
 
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)
 
141
                        }
 
142
                }
 
143
        }
 
144
}
 
145
 
 
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
 
148
// gotest: fi
 
149
func TestPCLine(t *testing.T) {
 
150
        if !dotest() {
 
151
                return
 
152
        }
 
153
 
 
154
        f, tab := crack("_test/pclinetest", t)
 
155
        text := f.Section(".text")
 
156
        textdat, err := text.Data()
 
157
        if err != nil {
 
158
                t.Fatalf("reading .text: %v", err)
 
159
        }
 
160
 
 
161
        // Test PCToLine
 
162
        sym := tab.LookupFunc("linefrompc")
 
163
        wantLine := 0
 
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])
 
168
                if fn == nil {
 
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)
 
172
                }
 
173
        }
 
174
 
 
175
        // Test LineToPC
 
176
        sym = tab.LookupFunc("pcfromline")
 
177
        lookupline := -1
 
178
        wantLine = 0
 
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)
 
182
                off = pc - text.Addr
 
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
 
187
                        continue
 
188
                }
 
189
                if lookupline == -1 {
 
190
                        lookupline = line
 
191
                }
 
192
                for ; lookupline <= line; lookupline++ {
 
193
                        pc2, fn2, err := tab.LineToPC(file, lookupline)
 
194
                        if lookupline != line {
 
195
                                // Should be nothing on this line
 
196
                                if err == nil {
 
197
                                        t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
 
198
                                }
 
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)
 
203
                        }
 
204
                }
 
205
                off = pc + 1 - text.Addr
 
206
        }
 
207
}