File size: 2,782 Bytes
e36aeda | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | // 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"
"slices"
"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)
}
}
slices.Sort(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, pclntab []byte, err error) {
if sect := f.macho.Section("__text"); sect != nil {
textStart = sect.Addr
}
if sect := f.macho.Section("__gopclntab"); sect != nil {
if pclntab, err = sect.Data(); err != nil {
return 0, nil, err
}
}
return textStart, 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 ""
}
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()
}
|