]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.8] cmd/link: emit a mach-o dwarf segment that dsymutil will accept
authorRuss Cox <rsc@golang.org>
Thu, 30 Mar 2017 00:50:34 +0000 (20:50 -0400)
committerAustin Clements <austin@google.com>
Wed, 5 Apr 2017 16:58:35 +0000 (16:58 +0000)
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>
src/cmd/link/dwarf_test.go [new file with mode: 0644]
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/macho.go

diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go
new file mode 100644 (file)
index 0000000..3346514
--- /dev/null
@@ -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)
+               })
+       }
+}
index 6e90d7857195aede479e6dabfea9d3095d7a554f..b624aa01afd123aac0d4c2427dc0ffc2a5f11acb 100644 (file)
@@ -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
index f3687daa91306da209f7a192607287f4914e2e6b..1ab61b7d1597d81093ddcb67ebcfeb7c3dde377a 100644 (file)
@@ -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
                }
        }