diff options
Diffstat (limited to 'src/cmd/internal/objfile/macho.go')
-rw-r--r-- | src/cmd/internal/objfile/macho.go | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/cmd/internal/objfile/macho.go b/src/cmd/internal/objfile/macho.go new file mode 100644 index 0000000..c924975 --- /dev/null +++ b/src/cmd/internal/objfile/macho.go @@ -0,0 +1,139 @@ +// Copyright 2013 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. + +// Parsing of Mach-O executables (OS X). + +package objfile + +import ( + "debug/dwarf" + "debug/macho" + "fmt" + "io" + "sort" +) + +const stabTypeMask = 0xe0 + +type machoFile struct { + macho *macho.File +} + +func openMacho(r io.ReaderAt) (rawFile, error) { + f, err := macho.NewFile(r) + if err != nil { + return nil, err + } + return &machoFile{f}, nil +} + +func (f *machoFile) symbols() ([]Sym, error) { + if f.macho.Symtab == nil { + return nil, nil + } + + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + for _, s := range f.macho.Symtab.Syms { + // Skip stab debug info. + if s.Type&stabTypeMask == 0 { + addrs = append(addrs, s.Value) + } + } + sort.Sort(uint64s(addrs)) + + var syms []Sym + for _, s := range f.macho.Symtab.Syms { + if s.Type&stabTypeMask != 0 { + // Skip stab debug info. + continue + } + sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'} + i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) + if i < len(addrs) { + sym.Size = int64(addrs[i] - s.Value) + } + if s.Sect == 0 { + sym.Code = 'U' + } else if int(s.Sect) <= len(f.macho.Sections) { + sect := f.macho.Sections[s.Sect-1] + switch sect.Seg { + case "__TEXT", "__DATA_CONST": + sym.Code = 'R' + case "__DATA": + sym.Code = 'D' + } + switch sect.Seg + " " + sect.Name { + case "__TEXT __text": + sym.Code = 'T' + case "__DATA __bss", "__DATA __noptrbss": + sym.Code = 'B' + } + } + syms = append(syms, sym) + } + + return syms, nil +} + +func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + if sect := f.macho.Section("__text"); sect != nil { + textStart = sect.Addr + } + if sect := f.macho.Section("__gosymtab"); sect != nil { + if symtab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + if sect := f.macho.Section("__gopclntab"); sect != nil { + if pclntab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + return textStart, symtab, pclntab, nil +} + +func (f *machoFile) text() (textStart uint64, text []byte, err error) { + sect := f.macho.Section("__text") + if sect == nil { + return 0, nil, fmt.Errorf("text section not found") + } + textStart = sect.Addr + text, err = sect.Data() + return +} + +func (f *machoFile) goarch() string { + switch f.macho.Cpu { + case macho.Cpu386: + return "386" + case macho.CpuAmd64: + return "amd64" + case macho.CpuArm: + return "arm" + case macho.CpuArm64: + return "arm64" + case macho.CpuPpc64: + return "ppc64" + } + return "" +} + +type uint64s []uint64 + +func (x uint64s) Len() int { return len(x) } +func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x uint64s) Less(i, j int) bool { return x[i] < x[j] } + +func (f *machoFile) loadAddress() (uint64, error) { + if seg := f.macho.Segment("__TEXT"); seg != nil { + return seg.Addr, nil + } + return 0, fmt.Errorf("unknown load address") +} + +func (f *machoFile) dwarf() (*dwarf.Data, error) { + return f.macho.DWARF() +} |