1
2
3
4
5
6
7 package objfile
8
9 import (
10 "cmd/internal/archive"
11 "cmd/internal/goobj"
12 "cmd/internal/objabi"
13 "cmd/internal/sys"
14 "debug/dwarf"
15 "debug/gosym"
16 "errors"
17 "fmt"
18 "io"
19 "os"
20 )
21
22 type goobjFile struct {
23 goobj *archive.GoObj
24 r *goobj.Reader
25 f *os.File
26 arch *sys.Arch
27 }
28
29 func openGoFile(f *os.File) (*File, error) {
30 a, err := archive.Parse(f, false)
31 if err != nil {
32 return nil, err
33 }
34 entries := make([]*Entry, 0, len(a.Entries))
35 L:
36 for _, e := range a.Entries {
37 switch e.Type {
38 case archive.EntryPkgDef:
39 continue
40 case archive.EntryGoObj:
41 o := e.Obj
42 b := make([]byte, o.Size)
43 _, err := f.ReadAt(b, o.Offset)
44 if err != nil {
45 return nil, err
46 }
47 r := goobj.NewReaderFromBytes(b, false)
48 var arch *sys.Arch
49 for _, a := range sys.Archs {
50 if a.Name == e.Obj.Arch {
51 arch = a
52 break
53 }
54 }
55 entries = append(entries, &Entry{
56 name: e.Name,
57 raw: &goobjFile{e.Obj, r, f, arch},
58 })
59 continue
60 case archive.EntryNativeObj:
61 nr := io.NewSectionReader(f, e.Offset, e.Size)
62 for _, try := range openers {
63 if raw, err := try(nr); err == nil {
64 entries = append(entries, &Entry{
65 name: e.Name,
66 raw: raw,
67 })
68 continue L
69 }
70 }
71 }
72 return nil, fmt.Errorf("open %s: unrecognized archive member %s", f.Name(), e.Name)
73 }
74 return &File{f, entries}, nil
75 }
76
77 func goobjName(name string, ver int) string {
78 if ver == 0 {
79 return name
80 }
81 return fmt.Sprintf("%s<%d>", name, ver)
82 }
83
84 type goobjReloc struct {
85 Off int32
86 Size uint8
87 Type objabi.RelocType
88 Add int64
89 Sym string
90 }
91
92 func (r goobjReloc) String(insnOffset uint64) string {
93 delta := int64(r.Off) - int64(insnOffset)
94 s := fmt.Sprintf("[%d:%d]%s", delta, delta+int64(r.Size), r.Type)
95 if r.Sym != "" {
96 if r.Add != 0 {
97 return fmt.Sprintf("%s:%s+%d", s, r.Sym, r.Add)
98 }
99 return fmt.Sprintf("%s:%s", s, r.Sym)
100 }
101 if r.Add != 0 {
102 return fmt.Sprintf("%s:%d", s, r.Add)
103 }
104 return s
105 }
106
107 func (f *goobjFile) symbols() ([]Sym, error) {
108 r := f.r
109 var syms []Sym
110
111
112 nrefName := r.NRefName()
113 refNames := make(map[goobj.SymRef]string, nrefName)
114 for i := 0; i < nrefName; i++ {
115 rn := r.RefName(i)
116 refNames[rn.Sym()] = rn.Name(r)
117 }
118
119 abiToVer := func(abi uint16) int {
120 var ver int
121 if abi == goobj.SymABIstatic {
122
123 ver = 1
124 }
125 return ver
126 }
127
128 resolveSymRef := func(s goobj.SymRef) string {
129 var i uint32
130 switch p := s.PkgIdx; p {
131 case goobj.PkgIdxInvalid:
132 if s.SymIdx != 0 {
133 panic("bad sym ref")
134 }
135 return ""
136 case goobj.PkgIdxHashed64:
137 i = s.SymIdx + uint32(r.NSym())
138 case goobj.PkgIdxHashed:
139 i = s.SymIdx + uint32(r.NSym()+r.NHashed64def())
140 case goobj.PkgIdxNone:
141 i = s.SymIdx + uint32(r.NSym()+r.NHashed64def()+r.NHasheddef())
142 case goobj.PkgIdxBuiltin:
143 name, abi := goobj.BuiltinName(int(s.SymIdx))
144 return goobjName(name, abi)
145 case goobj.PkgIdxSelf:
146 i = s.SymIdx
147 default:
148 return refNames[s]
149 }
150 sym := r.Sym(i)
151 return goobjName(sym.Name(r), abiToVer(sym.ABI()))
152 }
153
154
155 ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef())
156 for i := uint32(0); i < ndef; i++ {
157 osym := r.Sym(i)
158 if osym.Name(r) == "" {
159 continue
160 }
161 name := osym.Name(r)
162 ver := osym.ABI()
163 name = goobjName(name, abiToVer(ver))
164 typ := objabi.SymKind(osym.Type())
165 var code rune = '?'
166 switch typ {
167 case objabi.STEXT:
168 code = 'T'
169 case objabi.SRODATA:
170 code = 'R'
171 case objabi.SNOPTRDATA, objabi.SDATA:
172 code = 'D'
173 case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
174 code = 'B'
175 }
176 if ver >= goobj.SymABIstatic {
177 code += 'a' - 'A'
178 }
179
180 sym := Sym{
181 Name: name,
182 Addr: uint64(r.DataOff(i)),
183 Size: int64(osym.Siz()),
184 Code: code,
185 }
186
187 relocs := r.Relocs(i)
188 sym.Relocs = make([]Reloc, len(relocs))
189 for j := range relocs {
190 rel := &relocs[j]
191 sym.Relocs[j] = Reloc{
192 Addr: uint64(r.DataOff(i)) + uint64(rel.Off()),
193 Size: uint64(rel.Siz()),
194 Stringer: goobjReloc{
195 Off: rel.Off(),
196 Size: rel.Siz(),
197 Type: objabi.RelocType(rel.Type()),
198 Add: rel.Add(),
199 Sym: resolveSymRef(rel.Sym()),
200 },
201 }
202 }
203
204 syms = append(syms, sym)
205 }
206
207
208 n := ndef + uint32(r.NNonpkgref())
209 for i := ndef; i < n; i++ {
210 osym := r.Sym(i)
211 sym := Sym{Name: osym.Name(r), Code: 'U'}
212 syms = append(syms, sym)
213 }
214 for i := 0; i < nrefName; i++ {
215 rn := r.RefName(i)
216 sym := Sym{Name: rn.Name(r), Code: 'U'}
217 syms = append(syms, sym)
218 }
219
220 return syms, nil
221 }
222
223 func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
224
225
226 return 0, nil, nil, fmt.Errorf("pcln not available in go object file")
227 }
228
229
230
231
232 func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
233 r := f.r
234 if f.arch == nil {
235 return "", 0, nil
236 }
237 getSymData := func(s goobj.SymRef) []byte {
238 if s.PkgIdx != goobj.PkgIdxHashed {
239
240 panic("not supported")
241 }
242 i := uint32(s.SymIdx + uint32(r.NSym()+r.NHashed64def()))
243 return r.BytesAt(r.DataOff(i), r.DataSize(i))
244 }
245
246 ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef())
247 for i := uint32(0); i < ndef; i++ {
248 osym := r.Sym(i)
249 addr := uint64(r.DataOff(i))
250 if pc < addr || pc >= addr+uint64(osym.Siz()) {
251 continue
252 }
253 var pcfileSym, pclineSym goobj.SymRef
254 for _, a := range r.Auxs(i) {
255 switch a.Type() {
256 case goobj.AuxPcfile:
257 pcfileSym = a.Sym()
258 case goobj.AuxPcline:
259 pclineSym = a.Sym()
260 }
261 }
262 if pcfileSym.IsZero() || pclineSym.IsZero() {
263 continue
264 }
265 pcline := getSymData(pclineSym)
266 line := int(pcValue(pcline, pc-addr, f.arch))
267 pcfile := getSymData(pcfileSym)
268 fileID := pcValue(pcfile, pc-addr, f.arch)
269 fileName := r.File(int(fileID))
270
271
272 return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: osym.Name(r)}}
273 }
274 return "", 0, nil
275 }
276
277
278
279 func pcValue(tab []byte, target uint64, arch *sys.Arch) int32 {
280 val := int32(-1)
281 var pc uint64
282 for step(&tab, &pc, &val, pc == 0, arch) {
283 if target < pc {
284 return val
285 }
286 }
287 return -1
288 }
289
290
291 func step(p *[]byte, pc *uint64, val *int32, first bool, arch *sys.Arch) bool {
292 uvdelta := readvarint(p)
293 if uvdelta == 0 && !first {
294 return false
295 }
296 if uvdelta&1 != 0 {
297 uvdelta = ^(uvdelta >> 1)
298 } else {
299 uvdelta >>= 1
300 }
301 vdelta := int32(uvdelta)
302 pcdelta := readvarint(p) * uint32(arch.MinLC)
303 *pc += uint64(pcdelta)
304 *val += vdelta
305 return true
306 }
307
308
309 func readvarint(p *[]byte) uint32 {
310 var v, shift uint32
311 s := *p
312 for shift = 0; ; shift += 7 {
313 b := s[0]
314 s = s[1:]
315 v |= (uint32(b) & 0x7F) << shift
316 if b&0x80 == 0 {
317 break
318 }
319 }
320 *p = s
321 return v
322 }
323
324
325 func (f *goobjFile) text() (textStart uint64, text []byte, err error) {
326 text = make([]byte, f.goobj.Size)
327 _, err = f.f.ReadAt(text, int64(f.goobj.Offset))
328 return
329 }
330
331 func (f *goobjFile) goarch() string {
332 return f.goobj.Arch
333 }
334
335 func (f *goobjFile) loadAddress() (uint64, error) {
336 return 0, fmt.Errorf("unknown load address")
337 }
338
339 func (f *goobjFile) dwarf() (*dwarf.Data, error) {
340 return nil, errors.New("no DWARF data in go object file")
341 }
342
View as plain text