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, archive.EntrySentinelNonObj:
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, objabi.STEXTFIPS:
168 code = 'T'
169 case objabi.SRODATA, objabi.SRODATAFIPS:
170 code = 'R'
171 case objabi.SNOPTRDATA, objabi.SNOPTRDATAFIPS,
172 objabi.SDATA, objabi.SDATAFIPS:
173 code = 'D'
174 case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
175 code = 'B'
176 }
177 if ver >= goobj.SymABIstatic {
178 code += 'a' - 'A'
179 }
180
181 sym := Sym{
182 Name: name,
183 Addr: uint64(r.DataOff(i)),
184 Size: int64(osym.Siz()),
185 Code: code,
186 }
187
188 relocs := r.Relocs(i)
189 sym.Relocs = make([]Reloc, len(relocs))
190 for j := range relocs {
191 rel := &relocs[j]
192 sym.Relocs[j] = Reloc{
193 Addr: uint64(r.DataOff(i)) + uint64(rel.Off()),
194 Size: uint64(rel.Siz()),
195 Stringer: goobjReloc{
196 Off: rel.Off(),
197 Size: rel.Siz(),
198 Type: objabi.RelocType(rel.Type()),
199 Add: rel.Add(),
200 Sym: resolveSymRef(rel.Sym()),
201 },
202 }
203 }
204
205 syms = append(syms, sym)
206 }
207
208
209 n := ndef + uint32(r.NNonpkgref())
210 for i := ndef; i < n; i++ {
211 osym := r.Sym(i)
212 sym := Sym{Name: osym.Name(r), Code: 'U'}
213 syms = append(syms, sym)
214 }
215 for i := 0; i < nrefName; i++ {
216 rn := r.RefName(i)
217 sym := Sym{Name: rn.Name(r), Code: 'U'}
218 syms = append(syms, sym)
219 }
220
221 return syms, nil
222 }
223
224 func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
225
226
227 return 0, nil, nil, fmt.Errorf("pcln not available in go object file")
228 }
229
230
231
232
233 func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
234 r := f.r
235 if f.arch == nil {
236 return "", 0, nil
237 }
238 getSymData := func(s goobj.SymRef) []byte {
239 if s.PkgIdx != goobj.PkgIdxHashed {
240
241 panic("not supported")
242 }
243 i := uint32(s.SymIdx + uint32(r.NSym()+r.NHashed64def()))
244 return r.BytesAt(r.DataOff(i), r.DataSize(i))
245 }
246
247 ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef())
248 for i := uint32(0); i < ndef; i++ {
249 osym := r.Sym(i)
250 addr := uint64(r.DataOff(i))
251 if pc < addr || pc >= addr+uint64(osym.Siz()) {
252 continue
253 }
254 var pcfileSym, pclineSym goobj.SymRef
255 for _, a := range r.Auxs(i) {
256 switch a.Type() {
257 case goobj.AuxPcfile:
258 pcfileSym = a.Sym()
259 case goobj.AuxPcline:
260 pclineSym = a.Sym()
261 }
262 }
263 if pcfileSym.IsZero() || pclineSym.IsZero() {
264 continue
265 }
266 pcline := getSymData(pclineSym)
267 line := int(pcValue(pcline, pc-addr, f.arch))
268 pcfile := getSymData(pcfileSym)
269 fileID := pcValue(pcfile, pc-addr, f.arch)
270 fileName := r.File(int(fileID))
271
272
273 return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: osym.Name(r)}}
274 }
275 return "", 0, nil
276 }
277
278
279
280 func pcValue(tab []byte, target uint64, arch *sys.Arch) int32 {
281 val := int32(-1)
282 var pc uint64
283 for step(&tab, &pc, &val, pc == 0, arch) {
284 if target < pc {
285 return val
286 }
287 }
288 return -1
289 }
290
291
292 func step(p *[]byte, pc *uint64, val *int32, first bool, arch *sys.Arch) bool {
293 uvdelta := readvarint(p)
294 if uvdelta == 0 && !first {
295 return false
296 }
297 if uvdelta&1 != 0 {
298 uvdelta = ^(uvdelta >> 1)
299 } else {
300 uvdelta >>= 1
301 }
302 vdelta := int32(uvdelta)
303 pcdelta := readvarint(p) * uint32(arch.MinLC)
304 *pc += uint64(pcdelta)
305 *val += vdelta
306 return true
307 }
308
309
310 func readvarint(p *[]byte) uint32 {
311 var v, shift uint32
312 s := *p
313 for shift = 0; ; shift += 7 {
314 b := s[0]
315 s = s[1:]
316 v |= (uint32(b) & 0x7F) << shift
317 if b&0x80 == 0 {
318 break
319 }
320 }
321 *p = s
322 return v
323 }
324
325
326 func (f *goobjFile) text() (textStart uint64, text []byte, err error) {
327 text = make([]byte, f.goobj.Size)
328 _, err = f.f.ReadAt(text, int64(f.goobj.Offset))
329 return
330 }
331
332 func (f *goobjFile) goarch() string {
333 return f.goobj.Arch
334 }
335
336 func (f *goobjFile) loadAddress() (uint64, error) {
337 return 0, fmt.Errorf("unknown load address")
338 }
339
340 func (f *goobjFile) dwarf() (*dwarf.Data, error) {
341 return nil, errors.New("no DWARF data in go object file")
342 }
343
View as plain text