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