1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"cmd/internal/objfile"
"debug/dwarf"
"internal/testenv"
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strings"
"testing"
)
func TestDWARF(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("DWARF is not supported on Windows")
}
testenv.MustHaveGoBuild(t)
out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "cmd/link").CombinedOutput()
if err != nil {
t.Fatalf("go list: %v\n%s", err, out)
}
if string(out) != "false\n" {
t.Fatalf("cmd/link is stale - run go install cmd/link")
}
tmpDir, err := ioutil.TempDir("", "go-link-TestDWARF")
if err != nil {
t.Fatal("TempDir failed: ", err)
}
defer os.RemoveAll(tmpDir)
for _, prog := range []string{"testprog", "testprogcgo"} {
t.Run(prog, func(t *testing.T) {
exe := filepath.Join(tmpDir, prog+".exe")
dir := "../../runtime/testdata/" + prog
out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, dir).CombinedOutput()
if err != nil {
t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out)
}
f, err := objfile.Open(exe)
if err != nil {
t.Fatal(err)
}
defer f.Close()
syms, err := f.Symbols()
if err != nil {
t.Fatal(err)
}
var addr uint64
for _, sym := range syms {
if sym.Name == "main.main" {
addr = sym.Addr
break
}
}
if addr == 0 {
t.Fatal("cannot find main.main in symbols")
}
d, err := f.DWARF()
if err != nil {
t.Fatal(err)
}
// TODO: We'd like to use filepath.Join here.
// Also related: golang.org/issue/19784.
wantFile := path.Join(prog, "main.go")
wantLine := 24
r := d.Reader()
var line dwarf.LineEntry
for {
cu, err := r.Next()
if err != nil {
t.Fatal(err)
}
if cu == nil {
break
}
if cu.Tag != dwarf.TagCompileUnit {
r.SkipChildren()
continue
}
lr, err := d.LineReader(cu)
if err != nil {
t.Fatal(err)
}
for {
err := lr.Next(&line)
if err == io.EOF {
break
}
if err != nil {
t.Fatal(err)
}
if line.Address == addr {
if !strings.HasSuffix(line.File.Name, wantFile) || line.Line != wantLine {
t.Errorf("%#x is %s:%d, want %s:%d", addr, line.File.Name, line.Line, filepath.Join("...", wantFile), wantLine)
}
return
}
}
}
t.Fatalf("did not find file:line for %#x (main.main)", addr)
})
}
}
|