aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2017-03-29 20:50:34 -0400
committerAustin Clements <austin@google.com>2017-04-05 16:58:35 +0000
commit2d0043014fe397a957f6a85a86c12ffcc0eaef86 (patch)
tree865b0f9723f39a07ed6018cc23e2f32029c6cdd2
parent3ca0d34fa12abad8fc5ca8b8fabec0c1b2c0d288 (diff)
downloadgo-2d0043014fe397a957f6a85a86c12ffcc0eaef86.tar.gz
go-2d0043014fe397a957f6a85a86c12ffcc0eaef86.zip
[release-branch.go1.8] cmd/link: emit a mach-o dwarf segment that dsymutil will accept
Right now, at least with Xcode 8.3, we invoke dsymutil and dutifully copy what it produces back into the binary, but it has actually dropped all the DWARF information that we wanted, because it didn't like the look of go.o. Make it like the look of go.o. DWARF is tested in other ways, but typically indirectly and not for cgo programs. Add a direct test, and one that exercises cgo. This detects missing dwarf information in cgo-using binaries on macOS, at least with Xcode 8.3, and possibly earlier versions as well. Fixes #19772. The backport to Go 1.8 disables TestDWARF on Windows because Windows DWARF support is new in Go 1.9. Change-Id: I0082e52c0bc8fc4e289770ec3dc02f39fd61e743 Reviewed-on: https://go-review.googlesource.com/39605 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
-rw-r--r--src/cmd/link/dwarf_test.go120
-rw-r--r--src/cmd/link/internal/ld/lib.go4
-rw-r--r--src/cmd/link/internal/ld/macho.go2
3 files changed, 125 insertions, 1 deletions
diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go
new file mode 100644
index 0000000000..33465144e4
--- /dev/null
+++ b/src/cmd/link/dwarf_test.go
@@ -0,0 +1,120 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "cmd/internal/objfile"
+ "debug/dwarf"
+ "internal/testenv"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+func TestDWARF(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("DWARF is not supported on Windows")
+ }
+
+ testenv.MustHaveGoBuild(t)
+
+ out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "cmd/link").CombinedOutput()
+ if err != nil {
+ t.Fatalf("go list: %v\n%s", err, out)
+ }
+ if string(out) != "false\n" {
+ t.Fatalf("cmd/link is stale - run go install cmd/link")
+ }
+
+ tmpDir, err := ioutil.TempDir("", "go-link-TestDWARF")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ for _, prog := range []string{"testprog", "testprogcgo"} {
+ t.Run(prog, func(t *testing.T) {
+ exe := filepath.Join(tmpDir, prog+".exe")
+ dir := "../../runtime/testdata/" + prog
+ out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, dir).CombinedOutput()
+ if err != nil {
+ t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out)
+ }
+
+ f, err := objfile.Open(exe)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+
+ syms, err := f.Symbols()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var addr uint64
+ for _, sym := range syms {
+ if sym.Name == "main.main" {
+ addr = sym.Addr
+ break
+ }
+ }
+ if addr == 0 {
+ t.Fatal("cannot find main.main in symbols")
+ }
+
+ d, err := f.DWARF()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // TODO: We'd like to use filepath.Join here.
+ // Also related: golang.org/issue/19784.
+ wantFile := path.Join(prog, "main.go")
+ wantLine := 24
+ r := d.Reader()
+ var line dwarf.LineEntry
+ for {
+ cu, err := r.Next()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if cu == nil {
+ break
+ }
+ if cu.Tag != dwarf.TagCompileUnit {
+ r.SkipChildren()
+ continue
+ }
+ lr, err := d.LineReader(cu)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for {
+ err := lr.Next(&line)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ if line.Address == addr {
+ if !strings.HasSuffix(line.File.Name, wantFile) || line.Line != wantLine {
+ t.Errorf("%#x is %s:%d, want %s:%d", addr, line.File.Name, line.Line, filepath.Join("...", wantFile), wantLine)
+ }
+ return
+ }
+ }
+ }
+ t.Fatalf("did not find file:line for %#x (main.main)", addr)
+ })
+ }
+}
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 6e90d78571..b624aa01af 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -430,6 +430,10 @@ func (ctxt *Link) loadlib() {
// We now have enough information to determine the link mode.
determineLinkMode(ctxt)
+ if Headtype == obj.Hdarwin && Linkmode == LinkExternal {
+ *FlagTextAddr = 0
+ }
+
if Linkmode == LinkExternal && SysArch.Family == sys.PPC64 {
toc := ctxt.Syms.Lookup(".TOC.", 0)
toc.Type = obj.SDYNIMPORT
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index f3687daa91..1ab61b7d15 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -449,7 +449,7 @@ func Asmbmacho(ctxt *Link) {
ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
} else {
ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
- ms.vsize = ms.filesize
+ ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
}
}