Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 1 | // 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 | |
| 5 | package main |
| 6 | |
| 7 | import ( |
Aman Gupta | 3cb92fc | 2019-04-02 04:35:50 -0700 | [diff] [blame] | 8 | "bytes" |
Clément Chigot | 0ff9df6 | 2019-02-20 16:39:09 +0100 | [diff] [blame] | 9 | cmddwarf "cmd/internal/dwarf" |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 10 | "cmd/internal/objfile" |
| 11 | "debug/dwarf" |
| 12 | "internal/testenv" |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 13 | "os" |
| 14 | "os/exec" |
| 15 | "path" |
| 16 | "path/filepath" |
David du Colombier | ed6f297 | 2017-03-30 21:33:06 +0200 | [diff] [blame] | 17 | "runtime" |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 18 | "strings" |
| 19 | "testing" |
| 20 | ) |
| 21 | |
Bryan C. Mills | 9bc5268 | 2021-05-25 12:21:11 -0400 | [diff] [blame] | 22 | // 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. |
| 28 | func 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 Naur | bcdbd58 | 2018-05-03 15:38:37 +0200 | [diff] [blame] | 52 | func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) { |
Josh Bleecher Snyder | 94c62ef | 2017-03-30 15:07:05 -0700 | [diff] [blame] | 53 | testenv.MustHaveCGO(t) |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 54 | testenv.MustHaveGoBuild(t) |
| 55 | |
David du Colombier | ed6f297 | 2017-03-30 21:33:06 +0200 | [diff] [blame] | 56 | if runtime.GOOS == "plan9" { |
| 57 | t.Skip("skipping on plan9; no DWARF symbol table in executables") |
| 58 | } |
| 59 | |
Cherry Zhang | 041d885 | 2020-07-06 17:49:24 -0400 | [diff] [blame] | 60 | t.Parallel() |
| 61 | |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 62 | for _, prog := range []string{"testprog", "testprogcgo"} { |
Bryan C. Mills | fa8a3f3 | 2019-02-27 12:25:59 -0500 | [diff] [blame] | 63 | prog := prog |
Clément Chigot | 0ff9df6 | 2019-02-20 16:39:09 +0100 | [diff] [blame] | 64 | expectDWARF := expectDWARF |
| 65 | if runtime.GOOS == "aix" && prog == "testprogcgo" { |
| 66 | extld := os.Getenv("CC") |
| 67 | if extld == "" { |
| 68 | extld = "gcc" |
| 69 | } |
Bryan C. Mills | 9bc5268 | 2021-05-25 12:21:11 -0400 | [diff] [blame] | 70 | var err error |
Clément Chigot | 0ff9df6 | 2019-02-20 16:39:09 +0100 | [diff] [blame] | 71 | expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld) |
| 72 | if err != nil { |
| 73 | t.Fatal(err) |
| 74 | } |
Clément Chigot | 0ff9df6 | 2019-02-20 16:39:09 +0100 | [diff] [blame] | 75 | } |
| 76 | |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 77 | t.Run(prog, func(t *testing.T) { |
Ian Lance Taylor | e609bd3 | 2018-12-07 15:00:49 -0800 | [diff] [blame] | 78 | t.Parallel() |
| 79 | |
Brad Fitzpatrick | bd37284 | 2021-03-07 20:52:39 -0800 | [diff] [blame] | 80 | tmpDir := t.TempDir() |
Ian Lance Taylor | 44dc661 | 2019-03-01 12:55:43 -0800 | [diff] [blame] | 81 | |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 82 | exe := filepath.Join(tmpDir, prog+".exe") |
| 83 | dir := "../../runtime/testdata/" + prog |
Bryan C. Mills | 9bc5268 | 2021-05-25 12:21:11 -0400 | [diff] [blame] | 84 | cmd := exec.Command(testenv.GoToolPath(t), "build", "-toolexec", os.Args[0], "-o", exe) |
Elias Naur | bcdbd58 | 2018-05-03 15:38:37 +0200 | [diff] [blame] | 85 | if buildmode != "" { |
| 86 | cmd.Args = append(cmd.Args, "-buildmode", buildmode) |
| 87 | } |
| 88 | cmd.Args = append(cmd.Args, dir) |
Bryan C. Mills | 9bc5268 | 2021-05-25 12:21:11 -0400 | [diff] [blame] | 89 | 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 Zhang | 5f5168e | 2018-04-19 15:09:34 -0400 | [diff] [blame] | 92 | out, err := cmd.CombinedOutput() |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 93 | if err != nil { |
| 94 | t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out) |
| 95 | } |
| 96 | |
Elias Naur | bcdbd58 | 2018-05-03 15:38:37 +0200 | [diff] [blame] | 97 | 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 Gupta | 3cb92fc | 2019-04-02 04:35:50 -0700 | [diff] [blame] | 106 | |
David Chase | aea1259 | 2021-02-28 21:48:20 -0500 | [diff] [blame] | 107 | darwinSymbolTestIsTooFlaky := true // Turn this off, it is too flaky -- See #32218 |
| 108 | if runtime.GOOS == "darwin" && !darwinSymbolTestIsTooFlaky { |
Aman Gupta | 3cb92fc | 2019-04-02 04:35:50 -0700 | [diff] [blame] | 109 | 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 Gupta | a0c96a9 | 2019-04-11 16:20:27 -0700 | [diff] [blame] | 113 | t.Fatalf("symbols %v: %v: %s", filepath.Base(exe), err, out) |
Aman Gupta | 3cb92fc | 2019-04-02 04:35:50 -0700 | [diff] [blame] | 114 | } else { |
| 115 | if bytes.HasPrefix(out, []byte("Unable to find file")) { |
| 116 | // This failure will cause the App Store to reject our binaries. |
Aman Gupta | a0c96a9 | 2019-04-11 16:20:27 -0700 | [diff] [blame] | 117 | t.Fatalf("symbols %v: failed to parse file", filepath.Base(exe)) |
Aman Gupta | 2ae793e | 2019-04-03 01:49:24 -0700 | [diff] [blame] | 118 | } else if bytes.Contains(out, []byte(", Empty]")) { |
| 119 | t.Fatalf("symbols %v: parsed as empty", filepath.Base(exe)) |
Aman Gupta | 3cb92fc | 2019-04-02 04:35:50 -0700 | [diff] [blame] | 120 | } |
| 121 | } |
| 122 | } |
| 123 | } |
| 124 | |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 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 { |
Elias Naur | bcdbd58 | 2018-05-03 15:38:37 +0200 | [diff] [blame] | 149 | if expectDWARF { |
| 150 | t.Fatal(err) |
| 151 | } |
| 152 | return |
| 153 | } else { |
| 154 | if !expectDWARF { |
| 155 | t.Fatal("unexpected DWARF section") |
| 156 | } |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 157 | } |
| 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 Taylor | e609bd3 | 2018-12-07 15:00:49 -0800 | [diff] [blame] | 164 | entry, err := r.SeekPC(addr) |
| 165 | if err != nil { |
| 166 | t.Fatal(err) |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 167 | } |
Ian Lance Taylor | e609bd3 | 2018-12-07 15:00:49 -0800 | [diff] [blame] | 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 | } |
Russ Cox | 18e7767 | 2017-03-29 20:50:34 -0400 | [diff] [blame] | 181 | }) |
| 182 | } |
| 183 | } |
Cherry Zhang | 5f5168e | 2018-04-19 15:09:34 -0400 | [diff] [blame] | 184 | |
| 185 | func TestDWARF(t *testing.T) { |
Elias Naur | bcdbd58 | 2018-05-03 15:38:37 +0200 | [diff] [blame] | 186 | testDWARF(t, "", true) |
Than McIntosh | df855da | 2019-09-16 16:11:01 -0400 | [diff] [blame] | 187 | if !testing.Short() { |
Than McIntosh | 62581ee | 2019-11-13 10:03:19 -0500 | [diff] [blame] | 188 | if runtime.GOOS == "windows" { |
| 189 | t.Skip("skipping Windows/c-archive; see Issue 35512 for more.") |
| 190 | } |
Russ Cox | 06b0bab | 2019-05-15 20:49:39 -0400 | [diff] [blame] | 191 | t.Run("c-archive", func(t *testing.T) { |
| 192 | testDWARF(t, "c-archive", true) |
| 193 | }) |
Aman Gupta | 3cb92fc | 2019-04-02 04:35:50 -0700 | [diff] [blame] | 194 | } |
Cherry Zhang | 5f5168e | 2018-04-19 15:09:34 -0400 | [diff] [blame] | 195 | } |
| 196 | |
| 197 | func 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 Faller | 7214090 | 2020-05-19 10:53:41 -0400 | [diff] [blame] | 210 | // 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 Zhang | 2ff9e01 | 2020-10-16 21:42:01 -0400 | [diff] [blame] | 212 | if output, err := exec.Command("xcodebuild", "-showsdks").CombinedOutput(); err != nil { |
Jeremy Faller | 7214090 | 2020-05-19 10:53:41 -0400 | [diff] [blame] | 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 | } |
Cherry Zhang | 5f5168e | 2018-04-19 15:09:34 -0400 | [diff] [blame] | 217 | cc := "CC=" + runtime.GOROOT() + "/misc/ios/clangwrap.sh" |
Elias Naur | bcdbd58 | 2018-05-03 15:38:37 +0200 | [diff] [blame] | 218 | // iOS doesn't allow unmapped segments, so iOS executables don't have DWARF. |
Cherry Zhang | 2ff9e01 | 2020-10-16 21:42:01 -0400 | [diff] [blame] | 219 | t.Run("exe", func(t *testing.T) { |
| 220 | testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=ios", "GOARCH=arm64") |
| 221 | }) |
Elias Naur | bcdbd58 | 2018-05-03 15:38:37 +0200 | [diff] [blame] | 222 | // However, c-archive iOS objects have embedded DWARF. |
Cherry Zhang | 2ff9e01 | 2020-10-16 21:42:01 -0400 | [diff] [blame] | 223 | t.Run("c-archive", func(t *testing.T) { |
| 224 | testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=ios", "GOARCH=arm64") |
| 225 | }) |
Cherry Zhang | 5f5168e | 2018-04-19 15:09:34 -0400 | [diff] [blame] | 226 | } |