diff options
Diffstat (limited to 'src/pkg/debug/macho')
-rw-r--r-- | src/pkg/debug/macho/Makefile | 2 | ||||
-rw-r--r-- | src/pkg/debug/macho/file.go | 167 | ||||
-rw-r--r-- | src/pkg/debug/macho/file_test.go | 6 | ||||
-rw-r--r-- | src/pkg/debug/macho/macho.go | 90 |
4 files changed, 244 insertions, 21 deletions
diff --git a/src/pkg/debug/macho/Makefile b/src/pkg/debug/macho/Makefile index d34aacf54..5fbbf1efe 100644 --- a/src/pkg/debug/macho/Makefile +++ b/src/pkg/debug/macho/Makefile @@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -include ../../../Make.$(GOARCH) +include ../../../Make.inc TARG=debug/macho GOFILES=\ diff --git a/src/pkg/debug/macho/file.go b/src/pkg/debug/macho/file.go index 246dad8e7..fd8da9449 100644 --- a/src/pkg/debug/macho/file.go +++ b/src/pkg/debug/macho/file.go @@ -24,6 +24,9 @@ type File struct { Loads []Load Sections []*Section + Symtab *Symtab + Dysymtab *Dysymtab + closer io.Closer } @@ -112,6 +115,28 @@ func (s *Section) Data() ([]byte, os.Error) { // Open returns a new ReadSeeker reading the Mach-O section. func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } +// A Dylib represents a Mach-O load dynamic library command. +type Dylib struct { + LoadBytes + Name string + Time uint32 + CurrentVersion uint32 + CompatVersion uint32 +} + +// A Symtab represents a Mach-O symbol table command. +type Symtab struct { + LoadBytes + SymtabCmd + Syms []Symbol +} + +// A Dysymtab represents a Mach-O dynamic symbol table command. +type Dysymtab struct { + LoadBytes + DysymtabCmd + IndirectSyms []uint32 // indices into Symtab.Syms +} /* * Mach-O reader @@ -217,6 +242,71 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { default: f.Loads[i] = LoadBytes(cmddat) + case LoadCmdDylib: + var hdr DylibCmd + b := bytes.NewBuffer(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + l := new(Dylib) + if hdr.Name >= uint32(len(cmddat)) { + return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name} + } + l.Name = cstring(cmddat[hdr.Name:]) + l.Time = hdr.Time + l.CurrentVersion = hdr.CurrentVersion + l.CompatVersion = hdr.CompatVersion + l.LoadBytes = LoadBytes(cmddat) + f.Loads[i] = l + + case LoadCmdSymtab: + var hdr SymtabCmd + b := bytes.NewBuffer(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + strtab := make([]byte, hdr.Strsize) + if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil { + return nil, err + } + var symsz int + if f.Magic == Magic64 { + symsz = 16 + } else { + symsz = 12 + } + symdat := make([]byte, int(hdr.Nsyms)*symsz) + if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil { + return nil, err + } + st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset) + if err != nil { + return nil, err + } + f.Loads[i] = st + f.Symtab = st + + case LoadCmdDysymtab: + var hdr DysymtabCmd + b := bytes.NewBuffer(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + dat := make([]byte, hdr.Nindirectsyms*4) + if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil { + return nil, err + } + x := make([]uint32, hdr.Nindirectsyms) + if err := binary.Read(bytes.NewBuffer(dat), bo, x); err != nil { + return nil, err + } + st := new(Dysymtab) + st.LoadBytes = LoadBytes(cmddat) + st.DysymtabCmd = hdr + st.IndirectSyms = x + f.Loads[i] = st + f.Dysymtab = st + case LoadCmdSegment: var seg32 Segment32 b := bytes.NewBuffer(cmddat) @@ -301,18 +391,45 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { return f, nil } -func (f *File) pushSection(sh *Section, r io.ReaderAt) { - n := len(f.Sections) - if n >= cap(f.Sections) { - m := (n + 1) * 2 - new := make([]*Section, n, m) - for i, sh := range f.Sections { - new[i] = sh +func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, os.Error) { + bo := f.ByteOrder + symtab := make([]Symbol, hdr.Nsyms) + b := bytes.NewBuffer(symdat) + for i := range symtab { + var n Nlist64 + if f.Magic == Magic64 { + if err := binary.Read(b, bo, &n); err != nil { + return nil, err + } + } else { + var n32 Nlist32 + if err := binary.Read(b, bo, &n32); err != nil { + return nil, err + } + n.Name = n32.Name + n.Type = n32.Type + n.Sect = n32.Sect + n.Desc = n32.Desc + n.Value = uint64(n32.Value) + } + sym := &symtab[i] + if n.Name >= uint32(len(strtab)) { + return nil, &FormatError{offset, "invalid name in symbol table", n.Name} } - f.Sections = new + sym.Name = cstring(strtab[n.Name:]) + sym.Type = n.Type + sym.Sect = n.Sect + sym.Desc = n.Desc + sym.Value = n.Value } - f.Sections = f.Sections[0 : n+1] - f.Sections[n] = sh + st := new(Symtab) + st.LoadBytes = LoadBytes(cmddat) + st.Syms = symtab + return st, nil +} + +func (f *File) pushSection(sh *Section, r io.ReaderAt) { + f.Sections = append(f.Sections, sh) sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size)) sh.ReaderAt = sh.sr } @@ -368,3 +485,33 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) { abbrev, info, str := dat[0], dat[1], dat[2] return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) } + +// ImportedSymbols returns the names of all symbols +// referred to by the binary f that are expected to be +// satisfied by other libraries at dynamic load time. +func (f *File) ImportedSymbols() ([]string, os.Error) { + if f.Dysymtab == nil || f.Symtab == nil { + return nil, &FormatError{0, "missing symbol table", nil} + } + + st := f.Symtab + dt := f.Dysymtab + var all []string + for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] { + all = append(all, s.Name) + } + return all, nil +} + +// ImportedLibraries returns the paths of all libraries +// referred to by the binary f that are expected to be +// linked with the binary at dynamic link time. +func (f *File) ImportedLibraries() ([]string, os.Error) { + var all []string + for _, l := range f.Loads { + if lib, ok := l.(*Dylib); ok { + all = append(all, lib.Name) + } + } + return all, nil +} diff --git a/src/pkg/debug/macho/file_test.go b/src/pkg/debug/macho/file_test.go index d4f3fc19c..56d8a20be 100644 --- a/src/pkg/debug/macho/file_test.go +++ b/src/pkg/debug/macho/file_test.go @@ -17,7 +17,7 @@ type fileTest struct { } var fileTests = []fileTest{ - fileTest{ + { "testdata/gcc-386-darwin-exec", FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0xc, 0x3c0, 0x85}, []*SegmentHeader{ @@ -42,7 +42,7 @@ var fileTests = []fileTest{ &SectionHeader{"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008}, }, }, - fileTest{ + { "testdata/gcc-amd64-darwin-exec", FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0xb, 0x568, 0x85}, []*SegmentHeader{ @@ -69,7 +69,7 @@ var fileTests = []fileTest{ &SectionHeader{"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7}, }, }, - fileTest{ + { "testdata/gcc-amd64-darwin-exec-debug", FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0xa, 0x4, 0x5a0, 0}, []*SegmentHeader{ diff --git a/src/pkg/debug/macho/macho.go b/src/pkg/debug/macho/macho.go index 41962d562..1386f5acf 100644 --- a/src/pkg/debug/macho/macho.go +++ b/src/pkg/debug/macho/macho.go @@ -47,8 +47,8 @@ const ( ) var cpuStrings = []intName{ - intName{uint32(Cpu386), "Cpu386"}, - intName{uint32(CpuAmd64), "CpuAmd64"}, + {uint32(Cpu386), "Cpu386"}, + {uint32(CpuAmd64), "CpuAmd64"}, } func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) } @@ -59,16 +59,21 @@ type LoadCmd uint32 const ( LoadCmdSegment LoadCmd = 1 - LoadCmdSegment64 LoadCmd = 25 + LoadCmdSymtab LoadCmd = 2 LoadCmdThread LoadCmd = 4 LoadCmdUnixThread LoadCmd = 5 // thread+stack + LoadCmdDysymtab LoadCmd = 11 + LoadCmdDylib LoadCmd = 12 + LoadCmdDylinker LoadCmd = 15 + LoadCmdSegment64 LoadCmd = 25 ) var cmdStrings = []intName{ - intName{uint32(LoadCmdSegment), "LoadCmdSegment"}, - intName{uint32(LoadCmdSegment64), "LoadCmdSegment64"}, - intName{uint32(LoadCmdThread), "LoadCmdThread"}, - intName{uint32(LoadCmdUnixThread), "LoadCmdUnixThread"}, + {uint32(LoadCmdSegment), "LoadCmdSegment"}, + {uint32(LoadCmdThread), "LoadCmdThread"}, + {uint32(LoadCmdUnixThread), "LoadCmdUnixThread"}, + {uint32(LoadCmdDylib), "LoadCmdDylib"}, + {uint32(LoadCmdSegment64), "LoadCmdSegment64"}, } func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) } @@ -104,6 +109,16 @@ type Segment32 struct { Flag uint32 } +// A DylibCmd is a Mach-O load dynamic library command. +type DylibCmd struct { + Cmd LoadCmd + Len uint32 + Name uint32 + Time uint32 + CurrentVersion uint32 + CompatVersion uint32 +} + // A Section32 is a 32-bit Mach-O section header. type Section32 struct { Name [16]byte @@ -135,6 +150,67 @@ type Section64 struct { Reserve3 uint32 } +// A SymtabCmd is a Mach-O symbol table command. +type SymtabCmd struct { + Cmd LoadCmd + Len uint32 + Symoff uint32 + Nsyms uint32 + Stroff uint32 + Strsize uint32 +} + +// A DysymtabCmd is a Mach-O dynamic symbol table command. +type DysymtabCmd struct { + Cmd LoadCmd + Len uint32 + Ilocalsym uint32 + Nlocalsym uint32 + Iextdefsym uint32 + Nextdefsym uint32 + Iundefsym uint32 + Nundefsym uint32 + Tocoffset uint32 + Ntoc uint32 + Modtaboff uint32 + Nmodtab uint32 + Extrefsymoff uint32 + Nextrefsyms uint32 + Indirectsymoff uint32 + Nindirectsyms uint32 + Extreloff uint32 + Nextrel uint32 + Locreloff uint32 + Nlocrel uint32 +} + +// An Nlist32 is a Mach-O 32-bit symbol table entry. +type Nlist32 struct { + Name uint32 + Type uint8 + Sect uint8 + Desc uint16 + Value uint32 +} + +// An Nlist64 is a Mach-O 64-bit symbol table entry. +type Nlist64 struct { + Name uint32 + Type uint8 + Sect uint8 + Desc uint16 + Value uint64 +} + +// A Symbol is a Mach-O 32-bit or 64-bit symbol table entry. +type Symbol struct { + Name string + Type uint8 + Sect uint8 + Desc uint16 + Value uint64 +} + // A Thread is a Mach-O thread state command. type Thread struct { Cmd LoadCmd |