Source file
src/cmd/link/dwarf_test.go
1
2
3
4
5 package main
6
7 import (
8 "bytes"
9 cmddwarf "cmd/internal/dwarf"
10 "cmd/internal/objfile"
11 "debug/dwarf"
12 "internal/testenv"
13 "os"
14 "os/exec"
15 "path"
16 "path/filepath"
17 "runtime"
18 "strings"
19 "testing"
20 )
21
22
23
24
25
26
27
28 func TestMain(m *testing.M) {
29 if os.Getenv("LINK_TEST_TOOLEXEC") == "" {
30
31 os.Exit(m.Run())
32 }
33
34 if strings.TrimSuffix(filepath.Base(os.Args[1]), ".exe") == "link" {
35
36
37 os.Args = os.Args[1:]
38 main()
39 os.Exit(0)
40 }
41
42 cmd := exec.Command(os.Args[1], os.Args[2:]...)
43 cmd.Stdin = os.Stdin
44 cmd.Stdout = os.Stdout
45 cmd.Stderr = os.Stderr
46 if err := cmd.Run(); err != nil {
47 os.Exit(1)
48 }
49 os.Exit(0)
50 }
51
52 func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) {
53 testenv.MustHaveCGO(t)
54 testenv.MustHaveGoBuild(t)
55
56 if runtime.GOOS == "plan9" {
57 t.Skip("skipping on plan9; no DWARF symbol table in executables")
58 }
59
60 t.Parallel()
61
62 for _, prog := range []string{"testprog", "testprogcgo"} {
63 prog := prog
64 expectDWARF := expectDWARF
65 if runtime.GOOS == "aix" && prog == "testprogcgo" {
66 extld := os.Getenv("CC")
67 if extld == "" {
68 extld = "gcc"
69 }
70 var err error
71 expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld)
72 if err != nil {
73 t.Fatal(err)
74 }
75 }
76
77 t.Run(prog, func(t *testing.T) {
78 t.Parallel()
79
80 tmpDir := t.TempDir()
81
82 exe := filepath.Join(tmpDir, prog+".exe")
83 dir := "../../runtime/testdata/" + prog
84 cmd := exec.Command(testenv.GoToolPath(t), "build", "-toolexec", os.Args[0], "-o", exe)
85 if buildmode != "" {
86 cmd.Args = append(cmd.Args, "-buildmode", buildmode)
87 }
88 cmd.Args = append(cmd.Args, dir)
89 cmd.Env = append(os.Environ(), env...)
90 cmd.Env = append(cmd.Env, "CGO_CFLAGS=")
91 cmd.Env = append(cmd.Env, "LINK_TEST_TOOLEXEC=1")
92 out, err := cmd.CombinedOutput()
93 if err != nil {
94 t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out)
95 }
96
97 if buildmode == "c-archive" {
98
99 cmd := exec.Command("ar", "-x", exe)
100 cmd.Dir = tmpDir
101 if out, err := cmd.CombinedOutput(); err != nil {
102 t.Fatalf("ar -x %s: %v\n%s", exe, err, out)
103 }
104 exe = filepath.Join(tmpDir, "go.o")
105 }
106
107 darwinSymbolTestIsTooFlaky := true
108 if runtime.GOOS == "darwin" && !darwinSymbolTestIsTooFlaky {
109 if _, err = exec.LookPath("symbols"); err == nil {
110
111 out, err = exec.Command("symbols", exe).CombinedOutput()
112 if err != nil {
113 t.Fatalf("symbols %v: %v: %s", filepath.Base(exe), err, out)
114 } else {
115 if bytes.HasPrefix(out, []byte("Unable to find file")) {
116
117 t.Fatalf("symbols %v: failed to parse file", filepath.Base(exe))
118 } else if bytes.Contains(out, []byte(", Empty]")) {
119 t.Fatalf("symbols %v: parsed as empty", filepath.Base(exe))
120 }
121 }
122 }
123 }
124
125 f, err := objfile.Open(exe)
126 if err != nil {
127 t.Fatal(err)
128 }
129 defer f.Close()
130
131 syms, err := f.Symbols()
132 if err != nil {
133 t.Fatal(err)
134 }
135
136 var addr uint64
137 for _, sym := range syms {
138 if sym.Name == "main.main" {
139 addr = sym.Addr
140 break
141 }
142 }
143 if addr == 0 {
144 t.Fatal("cannot find main.main in symbols")
145 }
146
147 d, err := f.DWARF()
148 if err != nil {
149 if expectDWARF {
150 t.Fatal(err)
151 }
152 return
153 } else {
154 if !expectDWARF {
155 t.Fatal("unexpected DWARF section")
156 }
157 }
158
159
160
161 wantFile := path.Join(prog, "main.go")
162 wantLine := 24
163 r := d.Reader()
164 entry, err := r.SeekPC(addr)
165 if err != nil {
166 t.Fatal(err)
167 }
168 lr, err := d.LineReader(entry)
169 if err != nil {
170 t.Fatal(err)
171 }
172 var line dwarf.LineEntry
173 if err := lr.SeekPC(addr, &line); err == dwarf.ErrUnknownPC {
174 t.Fatalf("did not find file:line for %#x (main.main)", addr)
175 } else if err != nil {
176 t.Fatal(err)
177 }
178 if !strings.HasSuffix(line.File.Name, wantFile) || line.Line != wantLine {
179 t.Errorf("%#x is %s:%d, want %s:%d", addr, line.File.Name, line.Line, filepath.Join("...", wantFile), wantLine)
180 }
181 })
182 }
183 }
184
185 func TestDWARF(t *testing.T) {
186 testDWARF(t, "", true)
187 if !testing.Short() {
188 if runtime.GOOS == "windows" {
189 t.Skip("skipping Windows/c-archive; see Issue 35512 for more.")
190 }
191 t.Run("c-archive", func(t *testing.T) {
192 testDWARF(t, "c-archive", true)
193 })
194 }
195 }
196
197 func TestDWARFiOS(t *testing.T) {
198
199
200
201 if testing.Short() {
202 t.Skip("skipping in short mode")
203 }
204 if runtime.GOARCH != "amd64" || runtime.GOOS != "darwin" {
205 t.Skip("skipping on non-darwin/amd64 platform")
206 }
207 if err := exec.Command("xcrun", "--help").Run(); err != nil {
208 t.Skipf("error running xcrun, required for iOS cross build: %v", err)
209 }
210
211
212 if output, err := exec.Command("xcodebuild", "-showsdks").CombinedOutput(); err != nil {
213 t.Skipf("error running xcodebuild, required for iOS cross build: %v", err)
214 } else if !strings.Contains(string(output), "iOS SDK") {
215 t.Skipf("iOS SDK not detected.")
216 }
217 cc := "CC=" + runtime.GOROOT() + "/misc/ios/clangwrap.sh"
218
219 t.Run("exe", func(t *testing.T) {
220 testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=ios", "GOARCH=arm64")
221 })
222
223 t.Run("c-archive", func(t *testing.T) {
224 testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=ios", "GOARCH=arm64")
225 })
226 }
227
View as plain text