Skip to content

Commit

Permalink
[release-branch.go1.8] cmd/link: emit a mach-o dwarf segment that dsy…
Browse files Browse the repository at this point in the history
…mutil 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>
  • Loading branch information
rsc authored and aclements committed Apr 5, 2017
1 parent 3ca0d34 commit 2d00430
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 1 deletion.
120 changes: 120 additions & 0 deletions src/cmd/link/dwarf_test.go
Original file line number Diff line number Diff line change
@@ -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)
})
}
}
4 changes: 4 additions & 0 deletions src/cmd/link/internal/ld/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/link/internal/ld/macho.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down

0 comments on commit 2d00430

Please sign in to comment.