blob: 3ca59bd47f025cf1eac24eac43fddec1700c2348 [file] [log] [blame]
Russ Cox18e77672017-03-29 20:50:34 -04001// Copyright 2017 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
5package main
6
7import (
Aman Gupta3cb92fc2019-04-02 04:35:50 -07008 "bytes"
Clément Chigot0ff9df62019-02-20 16:39:09 +01009 cmddwarf "cmd/internal/dwarf"
Russ Cox18e77672017-03-29 20:50:34 -040010 "cmd/internal/objfile"
11 "debug/dwarf"
12 "internal/testenv"
Russ Cox18e77672017-03-29 20:50:34 -040013 "os"
14 "os/exec"
15 "path"
16 "path/filepath"
David du Colombiered6f2972017-03-30 21:33:06 +020017 "runtime"
Russ Cox18e77672017-03-29 20:50:34 -040018 "strings"
19 "testing"
20)
21
Bryan C. Mills9bc52682021-05-25 12:21:11 -040022// TestMain allows this test binary to run as a -toolexec wrapper for the 'go'
23// command. If LINK_TEST_TOOLEXEC is set, TestMain runs the binary as if it were
24// cmd/link, and otherwise runs the requested tool as a subprocess.
25//
26// This allows the test to verify the behavior of the current contents of the
27// cmd/link package even if the installed cmd/link binary is stale.
28func TestMain(m *testing.M) {
29 if os.Getenv("LINK_TEST_TOOLEXEC") == "" {
30 // Not running as a -toolexec wrapper. Just run the tests.
31 os.Exit(m.Run())
32 }
33
34 if strings.TrimSuffix(filepath.Base(os.Args[1]), ".exe") == "link" {
35 // Running as a -toolexec linker, and the tool is cmd/link.
36 // Substitute this test binary for the linker.
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
Elias Naurbcdbd582018-05-03 15:38:37 +020052func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) {
Josh Bleecher Snyder94c62ef2017-03-30 15:07:05 -070053 testenv.MustHaveCGO(t)
Russ Cox18e77672017-03-29 20:50:34 -040054 testenv.MustHaveGoBuild(t)
55
David du Colombiered6f2972017-03-30 21:33:06 +020056 if runtime.GOOS == "plan9" {
57 t.Skip("skipping on plan9; no DWARF symbol table in executables")
58 }
59
Cherry Zhang041d8852020-07-06 17:49:24 -040060 t.Parallel()
61
Russ Cox18e77672017-03-29 20:50:34 -040062 for _, prog := range []string{"testprog", "testprogcgo"} {
Bryan C. Millsfa8a3f32019-02-27 12:25:59 -050063 prog := prog
Clément Chigot0ff9df62019-02-20 16:39:09 +010064 expectDWARF := expectDWARF
65 if runtime.GOOS == "aix" && prog == "testprogcgo" {
66 extld := os.Getenv("CC")
67 if extld == "" {
68 extld = "gcc"
69 }
Bryan C. Mills9bc52682021-05-25 12:21:11 -040070 var err error
Clément Chigot0ff9df62019-02-20 16:39:09 +010071 expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld)
72 if err != nil {
73 t.Fatal(err)
74 }
Clément Chigot0ff9df62019-02-20 16:39:09 +010075 }
76
Russ Cox18e77672017-03-29 20:50:34 -040077 t.Run(prog, func(t *testing.T) {
Ian Lance Taylore609bd32018-12-07 15:00:49 -080078 t.Parallel()
79
Brad Fitzpatrickbd372842021-03-07 20:52:39 -080080 tmpDir := t.TempDir()
Ian Lance Taylor44dc6612019-03-01 12:55:43 -080081
Russ Cox18e77672017-03-29 20:50:34 -040082 exe := filepath.Join(tmpDir, prog+".exe")
83 dir := "../../runtime/testdata/" + prog
Bryan C. Mills9bc52682021-05-25 12:21:11 -040084 cmd := exec.Command(testenv.GoToolPath(t), "build", "-toolexec", os.Args[0], "-o", exe)
Elias Naurbcdbd582018-05-03 15:38:37 +020085 if buildmode != "" {
86 cmd.Args = append(cmd.Args, "-buildmode", buildmode)
87 }
88 cmd.Args = append(cmd.Args, dir)
Bryan C. Mills9bc52682021-05-25 12:21:11 -040089 cmd.Env = append(os.Environ(), env...)
90 cmd.Env = append(cmd.Env, "CGO_CFLAGS=") // ensure CGO_CFLAGS does not contain any flags. Issue #35459
91 cmd.Env = append(cmd.Env, "LINK_TEST_TOOLEXEC=1")
Cherry Zhang5f5168e2018-04-19 15:09:34 -040092 out, err := cmd.CombinedOutput()
Russ Cox18e77672017-03-29 20:50:34 -040093 if err != nil {
94 t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out)
95 }
96
Elias Naurbcdbd582018-05-03 15:38:37 +020097 if buildmode == "c-archive" {
98 // Extract the archive and use the go.o object within.
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 }
Aman Gupta3cb92fc2019-04-02 04:35:50 -0700106
David Chaseaea12592021-02-28 21:48:20 -0500107 darwinSymbolTestIsTooFlaky := true // Turn this off, it is too flaky -- See #32218
108 if runtime.GOOS == "darwin" && !darwinSymbolTestIsTooFlaky {
Aman Gupta3cb92fc2019-04-02 04:35:50 -0700109 if _, err = exec.LookPath("symbols"); err == nil {
110 // Ensure Apple's tooling can parse our object for symbols.
111 out, err = exec.Command("symbols", exe).CombinedOutput()
112 if err != nil {
Aman Guptaa0c96a92019-04-11 16:20:27 -0700113 t.Fatalf("symbols %v: %v: %s", filepath.Base(exe), err, out)
Aman Gupta3cb92fc2019-04-02 04:35:50 -0700114 } else {
115 if bytes.HasPrefix(out, []byte("Unable to find file")) {
116 // This failure will cause the App Store to reject our binaries.
Aman Guptaa0c96a92019-04-11 16:20:27 -0700117 t.Fatalf("symbols %v: failed to parse file", filepath.Base(exe))
Aman Gupta2ae793e2019-04-03 01:49:24 -0700118 } else if bytes.Contains(out, []byte(", Empty]")) {
119 t.Fatalf("symbols %v: parsed as empty", filepath.Base(exe))
Aman Gupta3cb92fc2019-04-02 04:35:50 -0700120 }
121 }
122 }
123 }
124
Russ Cox18e77672017-03-29 20:50:34 -0400125 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 {
Elias Naurbcdbd582018-05-03 15:38:37 +0200149 if expectDWARF {
150 t.Fatal(err)
151 }
152 return
153 } else {
154 if !expectDWARF {
155 t.Fatal("unexpected DWARF section")
156 }
Russ Cox18e77672017-03-29 20:50:34 -0400157 }
158
159 // TODO: We'd like to use filepath.Join here.
160 // Also related: golang.org/issue/19784.
161 wantFile := path.Join(prog, "main.go")
162 wantLine := 24
163 r := d.Reader()
Ian Lance Taylore609bd32018-12-07 15:00:49 -0800164 entry, err := r.SeekPC(addr)
165 if err != nil {
166 t.Fatal(err)
Russ Cox18e77672017-03-29 20:50:34 -0400167 }
Ian Lance Taylore609bd32018-12-07 15:00:49 -0800168 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 }
Russ Cox18e77672017-03-29 20:50:34 -0400181 })
182 }
183}
Cherry Zhang5f5168e2018-04-19 15:09:34 -0400184
185func TestDWARF(t *testing.T) {
Elias Naurbcdbd582018-05-03 15:38:37 +0200186 testDWARF(t, "", true)
Than McIntoshdf855da2019-09-16 16:11:01 -0400187 if !testing.Short() {
Than McIntosh62581ee2019-11-13 10:03:19 -0500188 if runtime.GOOS == "windows" {
189 t.Skip("skipping Windows/c-archive; see Issue 35512 for more.")
190 }
Russ Cox06b0bab2019-05-15 20:49:39 -0400191 t.Run("c-archive", func(t *testing.T) {
192 testDWARF(t, "c-archive", true)
193 })
Aman Gupta3cb92fc2019-04-02 04:35:50 -0700194 }
Cherry Zhang5f5168e2018-04-19 15:09:34 -0400195}
196
197func TestDWARFiOS(t *testing.T) {
198 // Normally we run TestDWARF on native platform. But on iOS we don't have
199 // go build, so we do this test with a cross build.
200 // Only run this on darwin/amd64, where we can cross build for iOS.
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 }
Jeremy Faller72140902020-05-19 10:53:41 -0400210 // Check to see if the ios tools are installed. It's possible to have the command line tools
211 // installed without the iOS sdk.
Cherry Zhang2ff9e012020-10-16 21:42:01 -0400212 if output, err := exec.Command("xcodebuild", "-showsdks").CombinedOutput(); err != nil {
Jeremy Faller72140902020-05-19 10:53:41 -0400213 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 }
Cherry Zhang5f5168e2018-04-19 15:09:34 -0400217 cc := "CC=" + runtime.GOROOT() + "/misc/ios/clangwrap.sh"
Elias Naurbcdbd582018-05-03 15:38:37 +0200218 // iOS doesn't allow unmapped segments, so iOS executables don't have DWARF.
Cherry Zhang2ff9e012020-10-16 21:42:01 -0400219 t.Run("exe", func(t *testing.T) {
220 testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=ios", "GOARCH=arm64")
221 })
Elias Naurbcdbd582018-05-03 15:38:37 +0200222 // However, c-archive iOS objects have embedded DWARF.
Cherry Zhang2ff9e012020-10-16 21:42:01 -0400223 t.Run("c-archive", func(t *testing.T) {
224 testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=ios", "GOARCH=arm64")
225 })
Cherry Zhang5f5168e2018-04-19 15:09:34 -0400226}