1
2
3
4
5
6
7 package objfile
8
9 import (
10 "debug/dwarf"
11 "debug/macho"
12 "fmt"
13 "io"
14 "sort"
15 )
16
17 const stabTypeMask = 0xe0
18
19 type machoFile struct {
20 macho *macho.File
21 }
22
23 func openMacho(r io.ReaderAt) (rawFile, error) {
24 f, err := macho.NewFile(r)
25 if err != nil {
26 return nil, err
27 }
28 return &machoFile{f}, nil
29 }
30
31 func (f *machoFile) symbols() ([]Sym, error) {
32 if f.macho.Symtab == nil {
33 return nil, nil
34 }
35
36
37
38 var addrs []uint64
39 for _, s := range f.macho.Symtab.Syms {
40
41 if s.Type&stabTypeMask == 0 {
42 addrs = append(addrs, s.Value)
43 }
44 }
45 sort.Sort(uint64s(addrs))
46
47 var syms []Sym
48 for _, s := range f.macho.Symtab.Syms {
49 if s.Type&stabTypeMask != 0 {
50
51 continue
52 }
53 sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
54 i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
55 if i < len(addrs) {
56 sym.Size = int64(addrs[i] - s.Value)
57 }
58 if s.Sect == 0 {
59 sym.Code = 'U'
60 } else if int(s.Sect) <= len(f.macho.Sections) {
61 sect := f.macho.Sections[s.Sect-1]
62 switch sect.Seg {
63 case "__TEXT", "__DATA_CONST":
64 sym.Code = 'R'
65 case "__DATA":
66 sym.Code = 'D'
67 }
68 switch sect.Seg + " " + sect.Name {
69 case "__TEXT __text":
70 sym.Code = 'T'
71 case "__DATA __bss", "__DATA __noptrbss":
72 sym.Code = 'B'
73 }
74 }
75 syms = append(syms, sym)
76 }
77
78 return syms, nil
79 }
80
81 func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
82 if sect := f.macho.Section("__text"); sect != nil {
83 textStart = sect.Addr
84 }
85 if sect := f.macho.Section("__gosymtab"); sect != nil {
86 if symtab, err = sect.Data(); err != nil {
87 return 0, nil, nil, err
88 }
89 }
90 if sect := f.macho.Section("__gopclntab"); sect != nil {
91 if pclntab, err = sect.Data(); err != nil {
92 return 0, nil, nil, err
93 }
94 }
95 return textStart, symtab, pclntab, nil
96 }
97
98 func (f *machoFile) text() (textStart uint64, text []byte, err error) {
99 sect := f.macho.Section("__text")
100 if sect == nil {
101 return 0, nil, fmt.Errorf("text section not found")
102 }
103 textStart = sect.Addr
104 text, err = sect.Data()
105 return
106 }
107
108 func (f *machoFile) goarch() string {
109 switch f.macho.Cpu {
110 case macho.Cpu386:
111 return "386"
112 case macho.CpuAmd64:
113 return "amd64"
114 case macho.CpuArm:
115 return "arm"
116 case macho.CpuArm64:
117 return "arm64"
118 case macho.CpuPpc64:
119 return "ppc64"
120 }
121 return ""
122 }
123
124 type uint64s []uint64
125
126 func (x uint64s) Len() int { return len(x) }
127 func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
128 func (x uint64s) Less(i, j int) bool { return x[i] < x[j] }
129
130 func (f *machoFile) loadAddress() (uint64, error) {
131 if seg := f.macho.Segment("__TEXT"); seg != nil {
132 return seg.Addr, nil
133 }
134 return 0, fmt.Errorf("unknown load address")
135 }
136
137 func (f *machoFile) dwarf() (*dwarf.Data, error) {
138 return f.macho.DWARF()
139 }
140
View as plain text