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