* tree-vect-loop-manip.c (vect_do_peeling): Do not use
[official-gcc.git] / libgo / go / debug / gosym / pclntab_test.go
blob7e7cee6793474583751dac688d668ad380a5dbb8
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.
5 package gosym
7 import (
8 "bytes"
9 "debug/elf"
10 "internal/testenv"
11 "io/ioutil"
12 "os"
13 "os/exec"
14 "path/filepath"
15 "runtime"
16 "strings"
17 "testing"
20 var (
21 pclineTempDir string
22 pclinetestBinary string
25 func dotest(t *testing.T) {
26 testenv.MustHaveGoBuild(t)
27 // For now, only works on amd64 platforms.
28 if runtime.GOARCH != "amd64" {
29 t.Skipf("skipping on non-AMD64 system %s", runtime.GOARCH)
31 var err error
32 pclineTempDir, err = ioutil.TempDir("", "pclinetest")
33 if err != nil {
34 t.Fatal(err)
36 // This command builds pclinetest from pclinetest.asm;
37 // the resulting binary looks like it was built from pclinetest.s,
38 // but we have renamed it to keep it away from the go tool.
39 pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest")
40 cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", pclinetestBinary+".o", "pclinetest.asm")
41 cmd.Stdout = os.Stdout
42 cmd.Stderr = os.Stderr
43 if err := cmd.Run(); err != nil {
44 t.Fatal(err)
47 // stamp .o file as being 'package main' so that go tool link will accept it
48 data, err := ioutil.ReadFile(pclinetestBinary + ".o")
49 if err != nil {
50 t.Fatal(err)
52 i := bytes.IndexByte(data, '\n')
53 if i < 0 {
54 t.Fatal("bad binary")
56 data = append(append(data[:i:i], "\nmain"...), data[i:]...)
57 if err := ioutil.WriteFile(pclinetestBinary+".o", data, 0666); err != nil {
58 t.Fatal(err)
61 cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-H", "linux",
62 "-o", pclinetestBinary, pclinetestBinary+".o")
63 cmd.Stdout = os.Stdout
64 cmd.Stderr = os.Stderr
65 if err := cmd.Run(); err != nil {
66 t.Fatal(err)
70 func endtest() {
71 if pclineTempDir != "" {
72 os.RemoveAll(pclineTempDir)
73 pclineTempDir = ""
74 pclinetestBinary = ""
78 // skipIfNotELF skips the test if we are not running on an ELF system.
79 // These tests open and examine the test binary, and use elf.Open to do so.
80 func skipIfNotELF(t *testing.T) {
81 switch runtime.GOOS {
82 case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
83 // OK.
84 default:
85 t.Skipf("skipping on non-ELF system %s", runtime.GOOS)
89 func getTable(t *testing.T) *Table {
90 f, tab := crack(os.Args[0], t)
91 f.Close()
92 return tab
95 func crack(file string, t *testing.T) (*elf.File, *Table) {
96 // Open self
97 f, err := elf.Open(file)
98 if err != nil {
99 t.Fatal(err)
101 return parse(file, f, t)
104 func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
105 s := f.Section(".gosymtab")
106 if s == nil {
107 t.Skip("no .gosymtab section")
109 symdat, err := s.Data()
110 if err != nil {
111 f.Close()
112 t.Fatalf("reading %s gosymtab: %v", file, err)
114 pclndat, err := f.Section(".gopclntab").Data()
115 if err != nil {
116 f.Close()
117 t.Fatalf("reading %s gopclntab: %v", file, err)
120 pcln := NewLineTable(pclndat, f.Section(".text").Addr)
121 tab, err := NewTable(symdat, pcln)
122 if err != nil {
123 f.Close()
124 t.Fatalf("parsing %s gosymtab: %v", file, err)
127 return f, tab
130 func TestLineFromAline(t *testing.T) {
131 skipIfNotELF(t)
133 tab := getTable(t)
134 if tab.go12line != nil {
135 // aline's don't exist in the Go 1.2 table.
136 t.Skip("not relevant to Go 1.2 symbol table")
139 // Find the sym package
140 pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
141 if pkg == nil {
142 t.Fatalf("nil pkg")
145 // Walk every absolute line and ensure that we hit every
146 // source line monotonically
147 lastline := make(map[string]int)
148 final := -1
149 for i := 0; i < 10000; i++ {
150 path, line := pkg.lineFromAline(i)
151 // Check for end of object
152 if path == "" {
153 if final == -1 {
154 final = i - 1
156 continue
157 } else if final != -1 {
158 t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
160 // It's okay to see files multiple times (e.g., sys.a)
161 if line == 1 {
162 lastline[path] = 1
163 continue
165 // Check that the is the next line in path
166 ll, ok := lastline[path]
167 if !ok {
168 t.Errorf("file %s starts on line %d", path, line)
169 } else if line != ll+1 {
170 t.Fatalf("expected next line of file %s to be %d, got %d", path, ll+1, line)
172 lastline[path] = line
174 if final == -1 {
175 t.Errorf("never reached end of object")
179 func TestLineAline(t *testing.T) {
180 skipIfNotELF(t)
182 tab := getTable(t)
183 if tab.go12line != nil {
184 // aline's don't exist in the Go 1.2 table.
185 t.Skip("not relevant to Go 1.2 symbol table")
188 for _, o := range tab.Files {
189 // A source file can appear multiple times in a
190 // object. alineFromLine will always return alines in
191 // the first file, so track which lines we've seen.
192 found := make(map[string]int)
193 for i := 0; i < 1000; i++ {
194 path, line := o.lineFromAline(i)
195 if path == "" {
196 break
199 // cgo files are full of 'Z' symbols, which we don't handle
200 if len(path) > 4 && path[len(path)-4:] == ".cgo" {
201 continue
204 if minline, ok := found[path]; path != "" && ok {
205 if minline >= line {
206 // We've already covered this file
207 continue
210 found[path] = line
212 a, err := o.alineFromLine(path, line)
213 if err != nil {
214 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)
215 } else if a != i {
216 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)
222 func TestPCLine(t *testing.T) {
223 dotest(t)
224 defer endtest()
226 f, tab := crack(pclinetestBinary, t)
227 defer f.Close()
228 text := f.Section(".text")
229 textdat, err := text.Data()
230 if err != nil {
231 t.Fatalf("reading .text: %v", err)
234 // Test PCToLine
235 sym := tab.LookupFunc("linefrompc")
236 wantLine := 0
237 for pc := sym.Entry; pc < sym.End; pc++ {
238 off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
239 if textdat[off] == 255 {
240 break
242 wantLine += int(textdat[off])
243 t.Logf("off is %d %#x (max %d)", off, textdat[off], sym.End-pc)
244 file, line, fn := tab.PCToLine(pc)
245 if fn == nil {
246 t.Errorf("failed to get line of PC %#x", pc)
247 } else if !strings.HasSuffix(file, "pclinetest.asm") || line != wantLine || fn != sym {
248 t.Errorf("PCToLine(%#x) = %s:%d (%s), want %s:%d (%s)", pc, file, line, fn.Name, "pclinetest.asm", wantLine, sym.Name)
252 // Test LineToPC
253 sym = tab.LookupFunc("pcfromline")
254 lookupline := -1
255 wantLine = 0
256 off := uint64(0) // TODO(rsc): should not need off; bug in 8g
257 for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
258 file, line, fn := tab.PCToLine(pc)
259 off = pc - text.Addr
260 if textdat[off] == 255 {
261 break
263 wantLine += int(textdat[off])
264 if line != wantLine {
265 t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
266 off = pc + 1 - text.Addr
267 continue
269 if lookupline == -1 {
270 lookupline = line
272 for ; lookupline <= line; lookupline++ {
273 pc2, fn2, err := tab.LineToPC(file, lookupline)
274 if lookupline != line {
275 // Should be nothing on this line
276 if err == nil {
277 t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
279 } else if err != nil {
280 t.Errorf("failed to get PC of line %d: %s", lookupline, err)
281 } else if pc != pc2 {
282 t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
285 off = pc + 1 - text.Addr