debug/macho: support reading imported symbols without LC_DYSYMTAB

Currently, the ImportedSymbols method requires an LC_DYSYMTAB load
command to exist. However, a Mach-O object file may not have an
LC_DYSYMTAB load command, e.g. the one produced by "ld -r".
Support this case by just reading the symbol table and gathers
undefined symbols.

Updates #61229.

Change-Id: I8b4761ac7d99e1f1f378e883e9be75ee4049ffbb
Reviewed-on: https://go-review.googlesource.com/c/go/+/692995
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Cherry Mui 2025-08-04 10:30:26 -04:00
parent 025d36917c
commit 2747f925dd
3 changed files with 50 additions and 8 deletions

View file

@ -719,16 +719,29 @@ func (f *File) DWARF() (*dwarf.Data, error) {
// referred to by the binary f that are expected to be // referred to by the binary f that are expected to be
// satisfied by other libraries at dynamic load time. // satisfied by other libraries at dynamic load time.
func (f *File) ImportedSymbols() ([]string, error) { func (f *File) ImportedSymbols() ([]string, error) {
if f.Dysymtab == nil || f.Symtab == nil { if f.Symtab == nil {
return nil, &FormatError{0, "missing symbol table", nil} return nil, &FormatError{0, "missing symbol table", nil}
} }
st := f.Symtab st := f.Symtab
dt := f.Dysymtab dt := f.Dysymtab
var all []string var all []string
if dt != nil {
for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] { for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {
all = append(all, s.Name) all = append(all, s.Name)
} }
} else {
// From Darwin's include/mach-o/nlist.h
const (
N_TYPE = 0x0e
N_UNDF = 0x0
)
for _, s := range st.Syms {
if s.Type&N_TYPE == N_UNDF && s.Sect == 0 {
all = append(all, s.Name)
}
}
}
return all, nil return all, nil
} }

View file

@ -9,6 +9,7 @@ import (
"internal/obscuretestdata" "internal/obscuretestdata"
"io" "io"
"reflect" "reflect"
"slices"
"testing" "testing"
) )
@ -18,6 +19,7 @@ type fileTest struct {
loads []any loads []any
sections []*SectionHeader sections []*SectionHeader
relocations map[string][]Reloc relocations map[string][]Reloc
importedSyms []string
} }
var fileTests = []fileTest{ var fileTests = []fileTest{
@ -46,6 +48,7 @@ var fileTests = []fileTest{
{"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008}, {"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008},
}, },
nil, nil,
nil,
}, },
{ {
"testdata/gcc-amd64-darwin-exec.base64", "testdata/gcc-amd64-darwin-exec.base64",
@ -74,6 +77,7 @@ var fileTests = []fileTest{
{"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7}, {"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7},
}, },
nil, nil,
nil,
}, },
{ {
"testdata/gcc-amd64-darwin-exec-debug.base64", "testdata/gcc-amd64-darwin-exec-debug.base64",
@ -102,6 +106,7 @@ var fileTests = []fileTest{
{"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0}, {"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0},
}, },
nil, nil,
nil,
}, },
{ {
"testdata/clang-386-darwin-exec-with-rpath.base64", "testdata/clang-386-darwin-exec-with-rpath.base64",
@ -126,6 +131,7 @@ var fileTests = []fileTest{
}, },
nil, nil,
nil, nil,
nil,
}, },
{ {
"testdata/clang-amd64-darwin-exec-with-rpath.base64", "testdata/clang-amd64-darwin-exec-with-rpath.base64",
@ -150,6 +156,7 @@ var fileTests = []fileTest{
}, },
nil, nil,
nil, nil,
nil,
}, },
{ {
"testdata/clang-386-darwin.obj.base64", "testdata/clang-386-darwin.obj.base64",
@ -185,6 +192,7 @@ var fileTests = []fileTest{
}, },
}, },
}, },
nil,
}, },
{ {
"testdata/clang-amd64-darwin.obj.base64", "testdata/clang-amd64-darwin.obj.base64",
@ -221,6 +229,15 @@ var fileTests = []fileTest{
}, },
}, },
}, },
[]string{"_printf"},
},
{
"testdata/clang-amd64-darwin-ld-r.obj.base64",
FileHeader{0xfeedfacf, CpuAmd64, 0x3, 0x1, 0x4, 0x1c0, 0x2000},
nil,
nil,
nil,
[]string{"_printf"},
}, },
} }
@ -345,6 +362,17 @@ func TestOpen(t *testing.T) {
} }
} }
} }
if tt.importedSyms != nil {
ss, err := f.ImportedSymbols()
if err != nil {
t.Errorf("open %s: fail to read imported symbols: %v", tt.file, err)
}
want := tt.importedSyms
if !slices.Equal(ss, want) {
t.Errorf("open %s: imported symbols differ:\n\thave %v\n\twant %v", tt.file, ss, want)
}
}
} }
} }

View file

@ -0,0 +1 @@
z/rt/gcAAAEDAAAAAQAAAAQAAADAAQAAACAAAAAAAAAZAAAAiAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAAAAAAIAAAAAAACYAAAAAAAAAAcAAAAHAAAABAAAAAAAAABfX3RleHQAAAAAAAAAAAAAX19URVhUAAAAAAAAAAAAAAAAAAAAAAAAKgAAAAAAAAAAAgAABAAAAJgCAAACAAAAAAQAgAAAAAAAAAAAAAAAAF9fY3N0cmluZwAAAAAAAABfX1RFWFQAAAAAAAAAAAAAKgAAAAAAAAAOAAAAAAAAACoCAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAX19laF9mcmFtZQAAAAAAAF9fVEVYVAAAAAAAAAAAAAA4AAAAAAAAAEAAAAAAAAAAOAIAAAMAAACoAgAABAAAAAAAAAAAAAAAAAAAAAAAAABfX2NvbXBhY3RfdW53aW5kX19MRAAAAAAAAAAAAAAAAHgAAAAAAAAAIAAAAAAAAAB4AgAAAwAAAMgCAAABAAAAAAAAAgAAAAAAAAAAAAAAAAIAAAAYAAAA0AIAAAUAAAAgAwAAKAAAACQAAAAQAAAAAAwKAAAAAAApAAAAEAAAANACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVSInlSIPsEEiNPQAAAADHRfwAAAAAsADoAAAAADHJiUX4ichIg8QQXcNoZWxsbywgd29ybGQKABQAAAAAAAAAAXpSAAF4EAEQDAcIkAEAACQAAAAEAAAA+P////////8qAAAAAAAAAABBDhCGAkMNBgAAAAAAAAAAAAAAAAAAACoAAAAAAAABAAAAAAAAAAAAAAAAAAAAABkAAAAEAAAtCwAAAAAAAB0cAAAAAQAAXBwAAAACAAAMIAAAAAIAAF4gAAAAAwAADgAAAAADAAAOEAAAAB4CAAAqAAAAAAAAABQAAAAOAwAAOAAAAAAAAAAeAAAADgMAAFAAAAAAAAAAAgAAAA8BAAAAAAAAAAAAAAgAAAABAAAAAAAAAAAAAAAgAF9tYWluAF9wcmludGYATEMxAEVIX0ZyYW1lMQBmdW5jLmVoAAAA