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, symtab, pclntab []byte, err error) {
83 if sect := f.macho.Section("__text"); sect != nil {
84 textStart = sect.Addr
85 }
86 if sect := f.macho.Section("__gosymtab"); sect != nil {
87 if symtab, err = sect.Data(); err != nil {
88 return 0, nil, nil, err
89 }
90 }
91 if sect := f.macho.Section("__gopclntab"); sect != nil {
92 if pclntab, err = sect.Data(); err != nil {
93 return 0, nil, nil, err
94 }
95 }
96 return textStart, symtab, pclntab, nil
97 }
98
99 func (f *machoFile) text() (textStart uint64, text []byte, err error) {
100 sect := f.macho.Section("__text")
101 if sect == nil {
102 return 0, nil, fmt.Errorf("text section not found")
103 }
104 textStart = sect.Addr
105 text, err = sect.Data()
106 return
107 }
108
109 func (f *machoFile) goarch() string {
110 switch f.macho.Cpu {
111 case macho.Cpu386:
112 return "386"
113 case macho.CpuAmd64:
114 return "amd64"
115 case macho.CpuArm:
116 return "arm"
117 case macho.CpuArm64:
118 return "arm64"
119 case macho.CpuPpc64:
120 return "ppc64"
121 }
122 return ""
123 }
124
125 func (f *machoFile) loadAddress() (uint64, error) {
126 if seg := f.macho.Segment("__TEXT"); seg != nil {
127 return seg.Addr, nil
128 }
129 return 0, fmt.Errorf("unknown load address")
130 }
131
132 func (f *machoFile) dwarf() (*dwarf.Data, error) {
133 return f.macho.DWARF()
134 }
135
View as plain text