OSDN Git Service

libgo: Update to weekly.2012-01-15.
[pf3gnuchains/gcc-fork.git] / libgo / go / debug / gosym / pclntab_test.go
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         "runtime"
11         "testing"
12 )
13
14 func dotest() bool {
15         // For now, only works on ELF platforms.
16         // TODO: convert to work with new go tool
17         return false && runtime.GOOS == "linux" && runtime.GOARCH == "amd64"
18 }
19
20 func getTable(t *testing.T) *Table {
21         f, tab := crack(os.Args[0], t)
22         f.Close()
23         return tab
24 }
25
26 func crack(file string, t *testing.T) (*elf.File, *Table) {
27         // Open self
28         f, err := elf.Open(file)
29         if err != nil {
30                 t.Fatal(err)
31         }
32         return parse(file, f, t)
33 }
34
35 func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
36         symdat, err := f.Section(".gosymtab").Data()
37         if err != nil {
38                 f.Close()
39                 t.Fatalf("reading %s gosymtab: %v", file, err)
40         }
41         pclndat, err := f.Section(".gopclntab").Data()
42         if err != nil {
43                 f.Close()
44                 t.Fatalf("reading %s gopclntab: %v", file, err)
45         }
46
47         pcln := NewLineTable(pclndat, f.Section(".text").Addr)
48         tab, err := NewTable(symdat, pcln)
49         if err != nil {
50                 f.Close()
51                 t.Fatalf("parsing %s gosymtab: %v", file, err)
52         }
53
54         return f, tab
55 }
56
57 var goarch = os.Getenv("O")
58
59 func TestLineFromAline(t *testing.T) {
60         if !dotest() {
61                 return
62         }
63
64         tab := getTable(t)
65
66         // Find the sym package
67         pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
68         if pkg == nil {
69                 t.Fatalf("nil pkg")
70         }
71
72         // Walk every absolute line and ensure that we hit every
73         // source line monotonically
74         lastline := make(map[string]int)
75         final := -1
76         for i := 0; i < 10000; i++ {
77                 path, line := pkg.lineFromAline(i)
78                 // Check for end of object
79                 if path == "" {
80                         if final == -1 {
81                                 final = i - 1
82                         }
83                         continue
84                 } else if final != -1 {
85                         t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
86                 }
87                 // It's okay to see files multiple times (e.g., sys.a)
88                 if line == 1 {
89                         lastline[path] = 1
90                         continue
91                 }
92                 // Check that the is the next line in path
93                 ll, ok := lastline[path]
94                 if !ok {
95                         t.Errorf("file %s starts on line %d", path, line)
96                 } else if line != ll+1 {
97                         t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
98                 }
99                 lastline[path] = line
100         }
101         if final == -1 {
102                 t.Errorf("never reached end of object")
103         }
104 }
105
106 func TestLineAline(t *testing.T) {
107         if !dotest() {
108                 return
109         }
110
111         tab := getTable(t)
112
113         for _, o := range tab.Files {
114                 // A source file can appear multiple times in a
115                 // object.  alineFromLine will always return alines in
116                 // the first file, so track which lines we've seen.
117                 found := make(map[string]int)
118                 for i := 0; i < 1000; i++ {
119                         path, line := o.lineFromAline(i)
120                         if path == "" {
121                                 break
122                         }
123
124                         // cgo files are full of 'Z' symbols, which we don't handle
125                         if len(path) > 4 && path[len(path)-4:] == ".cgo" {
126                                 continue
127                         }
128
129                         if minline, ok := found[path]; path != "" && ok {
130                                 if minline >= line {
131                                         // We've already covered this file
132                                         continue
133                                 }
134                         }
135                         found[path] = line
136
137                         a, err := o.alineFromLine(path, line)
138                         if err != nil {
139                                 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                         } else if a != i {
141                                 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)
142                         }
143                 }
144         }
145 }
146
147 func TestPCLine(t *testing.T) {
148         if !dotest() {
149                 return
150         }
151
152         f, tab := crack("_test/pclinetest", t)
153         text := f.Section(".text")
154         textdat, err := text.Data()
155         if err != nil {
156                 t.Fatalf("reading .text: %v", err)
157         }
158
159         // Test PCToLine
160         sym := tab.LookupFunc("linefrompc")
161         wantLine := 0
162         for pc := sym.Entry; pc < sym.End; pc++ {
163                 file, line, fn := tab.PCToLine(pc)
164                 off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
165                 wantLine += int(textdat[off])
166                 if fn == nil {
167                         t.Errorf("failed to get line of PC %#x", pc)
168                 } else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
169                         t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
170                 }
171         }
172
173         // Test LineToPC
174         sym = tab.LookupFunc("pcfromline")
175         lookupline := -1
176         wantLine = 0
177         off := uint64(0) // TODO(rsc): should not need off; bug in 8g
178         for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
179                 file, line, fn := tab.PCToLine(pc)
180                 off = pc - text.Addr
181                 wantLine += int(textdat[off])
182                 if line != wantLine {
183                         t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
184                         off = pc + 1 - text.Addr
185                         continue
186                 }
187                 if lookupline == -1 {
188                         lookupline = line
189                 }
190                 for ; lookupline <= line; lookupline++ {
191                         pc2, fn2, err := tab.LineToPC(file, lookupline)
192                         if lookupline != line {
193                                 // Should be nothing on this line
194                                 if err == nil {
195                                         t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
196                                 }
197                         } else if err != nil {
198                                 t.Errorf("failed to get PC of line %d: %s", lookupline, err)
199                         } else if pc != pc2 {
200                                 t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
201                         }
202                 }
203                 off = pc + 1 - text.Addr
204         }
205 }