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.
21 pclinetestBinary
string
24 func dotest(self
bool) bool {
25 // For now, only works on amd64 platforms.
26 if runtime
.GOARCH
!= "amd64" {
29 // Self test reads test binary; only works on Linux.
30 if self
&& runtime
.GOOS
!= "linux" {
33 // Command below expects "sh", so Unix.
34 if runtime
.GOOS
== "windows" || runtime
.GOOS
== "plan9" {
37 if pclinetestBinary
!= "" {
41 pclineTempDir
, err
= ioutil
.TempDir("", "pclinetest")
45 if strings
.Contains(pclineTempDir
, " ") {
46 panic("unexpected space in tempdir")
48 // This command builds pclinetest from pclinetest.asm;
49 // the resulting binary looks like it was built from pclinetest.s,
50 // but we have renamed it to keep it away from the go tool.
51 pclinetestBinary
= filepath
.Join(pclineTempDir
, "pclinetest")
52 command
:= fmt
.Sprintf("go tool 6a -o %s.6 pclinetest.asm && go tool 6l -H linux -E main -o %s %s.6",
53 pclinetestBinary
, pclinetestBinary
, pclinetestBinary
)
54 cmd
:= exec
.Command("sh", "-c", command
)
55 cmd
.Stdout
= os
.Stdout
56 cmd
.Stderr
= os
.Stderr
57 if err
:= cmd
.Run(); err
!= nil {
64 if pclineTempDir
!= "" {
65 os
.RemoveAll(pclineTempDir
)
71 func getTable(t
*testing
.T
) *Table
{
72 f
, tab
:= crack(os
.Args
[0], t
)
77 func crack(file
string, t
*testing
.T
) (*elf
.File
, *Table
) {
79 f
, err
:= elf
.Open(file
)
83 return parse(file
, f
, t
)
86 func parse(file
string, f
*elf
.File
, t
*testing
.T
) (*elf
.File
, *Table
) {
87 symdat
, err
:= f
.Section(".gosymtab").Data()
90 t
.Fatalf("reading %s gosymtab: %v", file
, err
)
92 pclndat
, err
:= f
.Section(".gopclntab").Data()
95 t
.Fatalf("reading %s gopclntab: %v", file
, err
)
98 pcln
:= NewLineTable(pclndat
, f
.Section(".text").Addr
)
99 tab
, err
:= NewTable(symdat
, pcln
)
102 t
.Fatalf("parsing %s gosymtab: %v", file
, err
)
108 var goarch
= os
.Getenv("O")
110 func TestLineFromAline(t
*testing
.T
) {
117 if tab
.go12line
!= nil {
118 // aline's don't exist in the Go 1.2 table.
119 t
.Skip("not relevant to Go 1.2 symbol table")
122 // Find the sym package
123 pkg
:= tab
.LookupFunc("debug/gosym.TestLineFromAline").Obj
128 // Walk every absolute line and ensure that we hit every
129 // source line monotonically
130 lastline
:= make(map[string]int)
132 for i
:= 0; i
< 10000; i
++ {
133 path
, line
:= pkg
.lineFromAline(i
)
134 // Check for end of object
140 } else if final
!= -1 {
141 t
.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final
, i
, path
, line
)
143 // It's okay to see files multiple times (e.g., sys.a)
148 // Check that the is the next line in path
149 ll
, ok
:= lastline
[path
]
151 t
.Errorf("file %s starts on line %d", path
, line
)
152 } else if line
!= ll
+1 {
153 t
.Fatalf("expected next line of file %s to be %d, got %d", path
, ll
+1, line
)
155 lastline
[path
] = line
158 t
.Errorf("never reached end of object")
162 func TestLineAline(t
*testing
.T
) {
169 if tab
.go12line
!= nil {
170 // aline's don't exist in the Go 1.2 table.
171 t
.Skip("not relevant to Go 1.2 symbol table")
174 for _
, o
:= range tab
.Files
{
175 // A source file can appear multiple times in a
176 // object. alineFromLine will always return alines in
177 // the first file, so track which lines we've seen.
178 found
:= make(map[string]int)
179 for i
:= 0; i
< 1000; i
++ {
180 path
, line
:= o
.lineFromAline(i
)
185 // cgo files are full of 'Z' symbols, which we don't handle
186 if len(path
) > 4 && path
[len(path
)-4:] == ".cgo" {
190 if minline
, ok
:= found
[path
]; path
!= "" && ok
{
192 // We've already covered this file
198 a
, err
:= o
.alineFromLine(path
, line
)
200 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
)
202 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
)
208 func TestPCLine(t
*testing
.T
) {
214 f
, tab
:= crack(pclinetestBinary
, t
)
215 text
:= f
.Section(".text")
216 textdat
, err
:= text
.Data()
218 t
.Fatalf("reading .text: %v", err
)
222 sym
:= tab
.LookupFunc("linefrompc")
224 for pc
:= sym
.Entry
; pc
< sym
.End
; pc
++ {
225 off
:= pc
- text
.Addr
// TODO(rsc): should not need off; bug in 8g
226 if textdat
[off
] == 255 {
229 wantLine
+= int(textdat
[off
])
230 t
.Logf("off is %d %#x (max %d)", off
, textdat
[off
], sym
.End
-pc
)
231 file
, line
, fn
:= tab
.PCToLine(pc
)
233 t
.Errorf("failed to get line of PC %#x", pc
)
234 } else if !strings
.HasSuffix(file
, "pclinetest.asm") || line
!= wantLine || fn
!= sym
{
235 t
.Errorf("PCToLine(%#x) = %s:%d (%s), want %s:%d (%s)", pc
, file
, line
, fn
.Name
, "pclinetest.asm", wantLine
, sym
.Name
)
240 sym
= tab
.LookupFunc("pcfromline")
243 off
:= uint64(0) // TODO(rsc): should not need off; bug in 8g
244 for pc
:= sym
.Value
; pc
< sym
.End
; pc
+= 2 + uint64(textdat
[off
]) {
245 file
, line
, fn
:= tab
.PCToLine(pc
)
247 if textdat
[off
] == 255 {
250 wantLine
+= int(textdat
[off
])
251 if line
!= wantLine
{
252 t
.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine
, pc
, line
)
253 off
= pc
+ 1 - text
.Addr
256 if lookupline
== -1 {
259 for ; lookupline
<= line
; lookupline
++ {
260 pc2
, fn2
, err
:= tab
.LineToPC(file
, lookupline
)
261 if lookupline
!= line
{
262 // Should be nothing on this line
264 t
.Errorf("expected no PC at line %d, got %#x (%s)", lookupline
, pc2
, fn2
.Name
)
266 } else if err
!= nil {
267 t
.Errorf("failed to get PC of line %d: %s", lookupline
, err
)
268 } else if pc
!= pc2
{
269 t
.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc
, fn
.Name
, line
, pc2
, fn2
.Name
)
272 off
= pc
+ 1 - text
.Addr