github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/link/dwarf_test.go (about) 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 ( 8 "bytes" 9 cmddwarf "github.com/gagliardetto/golang-go/cmd/internal/dwarf" 10 "github.com/gagliardetto/golang-go/cmd/internal/objfile" 11 "debug/dwarf" 12 "github.com/gagliardetto/golang-go/not-internal/testenv" 13 "io/ioutil" 14 "os" 15 "os/exec" 16 "path" 17 "path/filepath" 18 "runtime" 19 "strings" 20 "testing" 21 ) 22 23 func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) { 24 testenv.MustHaveCGO(t) 25 testenv.MustHaveGoBuild(t) 26 27 if runtime.GOOS == "plan9" { 28 t.Skip("skipping on plan9; no DWARF symbol table in executables") 29 } 30 31 out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "github.com/gagliardetto/golang-go/cmd/link").CombinedOutput() 32 if err != nil { 33 t.Fatalf("go list: %v\n%s", err, out) 34 } 35 if string(out) != "false\n" { 36 if os.Getenv("GOROOT_FINAL_OLD") != "" { 37 t.Skip("github.com/gagliardetto/golang-go/cmd/link is stale, but $GOROOT_FINAL_OLD is set") 38 } 39 t.Fatalf("github.com/gagliardetto/golang-go/cmd/link is stale - run go install cmd/link") 40 } 41 42 for _, prog := range []string{"testprog", "testprogcgo"} { 43 prog := prog 44 expectDWARF := expectDWARF 45 if runtime.GOOS == "aix" && prog == "testprogcgo" { 46 extld := os.Getenv("CC") 47 if extld == "" { 48 extld = "gcc" 49 } 50 expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld) 51 if err != nil { 52 t.Fatal(err) 53 } 54 55 } 56 57 t.Run(prog, func(t *testing.T) { 58 t.Parallel() 59 60 tmpDir, err := ioutil.TempDir("", "go-link-TestDWARF") 61 if err != nil { 62 t.Fatal(err) 63 } 64 defer os.RemoveAll(tmpDir) 65 66 exe := filepath.Join(tmpDir, prog+".exe") 67 dir := "../../runtime/testdata/" + prog 68 cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe) 69 if buildmode != "" { 70 cmd.Args = append(cmd.Args, "-buildmode", buildmode) 71 } 72 cmd.Args = append(cmd.Args, dir) 73 if env != nil { 74 env = append(env, "CGO_CFLAGS=") // ensure CGO_CFLAGS does not contain any flags. Issue #35459 75 cmd.Env = append(os.Environ(), env...) 76 } 77 out, err := cmd.CombinedOutput() 78 if err != nil { 79 t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out) 80 } 81 82 if buildmode == "c-archive" { 83 // Extract the archive and use the go.o object within. 84 cmd := exec.Command("ar", "-x", exe) 85 cmd.Dir = tmpDir 86 if out, err := cmd.CombinedOutput(); err != nil { 87 t.Fatalf("ar -x %s: %v\n%s", exe, err, out) 88 } 89 exe = filepath.Join(tmpDir, "go.o") 90 } 91 92 if runtime.GOOS == "darwin" { 93 if _, err = exec.LookPath("symbols"); err == nil { 94 // Ensure Apple's tooling can parse our object for symbols. 95 out, err = exec.Command("symbols", exe).CombinedOutput() 96 if err != nil { 97 t.Fatalf("symbols %v: %v: %s", filepath.Base(exe), err, out) 98 } else { 99 if bytes.HasPrefix(out, []byte("Unable to find file")) { 100 // This failure will cause the App Store to reject our binaries. 101 t.Fatalf("symbols %v: failed to parse file", filepath.Base(exe)) 102 } else if bytes.Contains(out, []byte(", Empty]")) { 103 t.Fatalf("symbols %v: parsed as empty", filepath.Base(exe)) 104 } 105 } 106 } 107 } 108 109 f, err := objfile.Open(exe) 110 if err != nil { 111 t.Fatal(err) 112 } 113 defer f.Close() 114 115 syms, err := f.Symbols() 116 if err != nil { 117 t.Fatal(err) 118 } 119 120 var addr uint64 121 for _, sym := range syms { 122 if sym.Name == "main.main" { 123 addr = sym.Addr 124 break 125 } 126 } 127 if addr == 0 { 128 t.Fatal("cannot find main.main in symbols") 129 } 130 131 d, err := f.DWARF() 132 if err != nil { 133 if expectDWARF { 134 t.Fatal(err) 135 } 136 return 137 } else { 138 if !expectDWARF { 139 t.Fatal("unexpected DWARF section") 140 } 141 } 142 143 // TODO: We'd like to use filepath.Join here. 144 // Also related: golang.org/issue/19784. 145 wantFile := path.Join(prog, "main.go") 146 wantLine := 24 147 r := d.Reader() 148 entry, err := r.SeekPC(addr) 149 if err != nil { 150 t.Fatal(err) 151 } 152 lr, err := d.LineReader(entry) 153 if err != nil { 154 t.Fatal(err) 155 } 156 var line dwarf.LineEntry 157 if err := lr.SeekPC(addr, &line); err == dwarf.ErrUnknownPC { 158 t.Fatalf("did not find file:line for %#x (main.main)", addr) 159 } else if err != nil { 160 t.Fatal(err) 161 } 162 if !strings.HasSuffix(line.File.Name, wantFile) || line.Line != wantLine { 163 t.Errorf("%#x is %s:%d, want %s:%d", addr, line.File.Name, line.Line, filepath.Join("...", wantFile), wantLine) 164 } 165 }) 166 } 167 } 168 169 func TestDWARF(t *testing.T) { 170 testDWARF(t, "", true) 171 if !testing.Short() { 172 if runtime.GOOS == "windows" { 173 t.Skip("skipping Windows/c-archive; see Issue 35512 for more.") 174 } 175 t.Run("c-archive", func(t *testing.T) { 176 testDWARF(t, "c-archive", true) 177 }) 178 } 179 } 180 181 func TestDWARFiOS(t *testing.T) { 182 // Normally we run TestDWARF on native platform. But on iOS we don't have 183 // go build, so we do this test with a cross build. 184 // Only run this on darwin/amd64, where we can cross build for iOS. 185 if testing.Short() { 186 t.Skip("skipping in short mode") 187 } 188 if runtime.GOARCH != "amd64" || runtime.GOOS != "darwin" { 189 t.Skip("skipping on non-darwin/amd64 platform") 190 } 191 if err := exec.Command("xcrun", "--help").Run(); err != nil { 192 t.Skipf("error running xcrun, required for iOS cross build: %v", err) 193 } 194 cc := "CC=" + runtime.GOROOT() + "/misc/ios/clangwrap.sh" 195 // iOS doesn't allow unmapped segments, so iOS executables don't have DWARF. 196 testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm", "GOARM=7") 197 testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm64") 198 // However, c-archive iOS objects have embedded DWARF. 199 testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm", "GOARM=7") 200 testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm64") 201 }