Skip to content

Commit

Permalink
cmd/link: Fix trampolines breaking DWARF line info
Browse files Browse the repository at this point in the history
When trampolines are needed (e.g. Darwin ARM64), the DWARF LPT (Line
Program Table - see DWARF section 6.1) generation fails because the
replacement symbols are marked as external symbols and skipped during
the DWARF LPT generation phase.

This PR is still subject to extensive testing but has rectified the
issue for the very large binaries we link at Uber.

Fixes golang#54320
  • Loading branch information
jquirke committed Aug 9, 2022
1 parent d75e186 commit 892586e
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 7 deletions.
79 changes: 79 additions & 0 deletions src/cmd/link/internal/ld/dwarf_test.go
Expand Up @@ -1842,3 +1842,82 @@ func main() {
}
}
}
func TestIssue54320(t *testing.T) {
// Check that when trampolines are used, the DWARF LPT is correctly
// emitted in the final binary
testenv.MustHaveGoBuild(t)

if runtime.GOOS == "plan9" {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
}

t.Parallel()

const prog = `
package main
import "fmt"
func main() {
fmt.Printf("Hello world\n");
}
`

dir := t.TempDir()
f := gobuild(t, dir, prog, "-ldflags=-debugtramp=2")
defer f.Close()

d, err := f.DWARF()
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}

rdr := d.Reader()
found := false
var entry *dwarf.Entry
for entry, err = rdr.Next(); entry != nil; entry, err = rdr.Next() {
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
if entry.Tag != dwarf.TagCompileUnit {
continue
}
name, _ := entry.Val(dwarf.AttrName).(string)
if name == "main" {
found = true
break
}
rdr.SkipChildren()
}

if !found {
t.Fatalf("could not find main compile unit")
}
lr, err := d.LineReader(entry)
if err != nil {
t.Fatalf("error obtaining linereader: %v", err)
}

var le dwarf.LineEntry
found = false
for {
if err := lr.Next(&le); err != nil {
if err == io.EOF {
break
}
t.Fatalf("error reading linentry: %v", err)
}
// check LE contains an entry to test.go
if le.File == nil {
continue
}
file := filepath.Base(le.File.Name)
if file == "test.go" {
found = true
break
}
}
if !found {
t.Errorf("no LPT entries for test.go")
}
}
9 changes: 2 additions & 7 deletions src/cmd/link/internal/loader/loader.go
Expand Up @@ -1610,13 +1610,8 @@ func (l *Loader) GetFuncDwarfAuxSyms(fnSymIdx Sym) (auxDwarfInfo, auxDwarfLoc, a
if l.SymType(fnSymIdx) != sym.STEXT {
log.Fatalf("error: non-function sym %d/%s t=%s passed to GetFuncDwarfAuxSyms", fnSymIdx, l.SymName(fnSymIdx), l.SymType(fnSymIdx).String())
}
if l.IsExternal(fnSymIdx) {
// Current expectation is that any external function will
// not have auxsyms.
return
}
r, li := l.toLocal(fnSymIdx)
auxs := r.Auxs(li)
r, auxs := l.auxs(fnSymIdx)

for i := range auxs {
a := &auxs[i]
switch a.Type() {
Expand Down

0 comments on commit 892586e

Please sign in to comment.