Source file src/cmd/internal/goobj/read.go
1
2
3
4
5
6
7
8
9 package goobj
10
11 import (
12 "bufio"
13 "bytes"
14 "cmd/internal/objabi"
15 "errors"
16 "fmt"
17 "io"
18 "os"
19 "strconv"
20 "strings"
21 )
22
23
24 type Sym struct {
25 SymID
26 Kind objabi.SymKind
27 DupOK bool
28 Size int64
29 Type SymID
30 Data Data
31 Reloc []Reloc
32 Func *Func
33 }
34
35
36
37 type SymID struct {
38
39 Name string
40
41
42
43
44
45
46 Version int64
47 }
48
49 func (s SymID) String() string {
50 if s.Version == 0 {
51 return s.Name
52 }
53 return fmt.Sprintf("%s<%d>", s.Name, s.Version)
54 }
55
56
57
58
59 type Data struct {
60 Offset int64
61 Size int64
62 }
63
64
65
66 type Reloc struct {
67
68
69
70 Offset int64
71 Size int64
72 Sym SymID
73 Add int64
74
75
76
77
78 Type objabi.RelocType
79 }
80
81
82
83 type Var struct {
84
85
86
87 Name string
88 Kind int64
89 Offset int64
90
91 Type SymID
92 }
93
94
95 type Func struct {
96 Args int64
97 Frame int64
98 Leaf bool
99 NoSplit bool
100 TopFrame bool
101 Var []Var
102 PCSP Data
103 PCFile Data
104 PCLine Data
105 PCInline Data
106 PCData []Data
107 FuncData []FuncData
108 File []string
109 InlTree []InlinedCall
110 }
111
112
113
114
115 type FuncData struct {
116 Sym SymID
117 Offset int64
118 }
119
120
121
122 type InlinedCall struct {
123 Parent int64
124 File string
125 Line int64
126 Func SymID
127 ParentPC int64
128 }
129
130
131 type Package struct {
132 ImportPath string
133 Imports []string
134 SymRefs []SymID
135 Syms []*Sym
136 MaxVersion int64
137 Arch string
138 Native []*NativeReader
139 }
140
141 type NativeReader struct {
142 Name string
143 io.ReaderAt
144 }
145
146 var (
147 archiveHeader = []byte("!<arch>\n")
148 archiveMagic = []byte("`\n")
149 goobjHeader = []byte("go objec")
150
151 errCorruptArchive = errors.New("corrupt archive")
152 errTruncatedArchive = errors.New("truncated archive")
153 errCorruptObject = errors.New("corrupt object file")
154 errNotObject = errors.New("unrecognized object file format")
155 )
156
157
158 type objReader struct {
159 p *Package
160 b *bufio.Reader
161 f *os.File
162 err error
163 offset int64
164 dataOffset int64
165 limit int64
166 tmp [256]byte
167 pkgprefix string
168 }
169
170
171 func (r *objReader) init(f *os.File, p *Package) {
172 r.f = f
173 r.p = p
174 r.offset, _ = f.Seek(0, io.SeekCurrent)
175 r.limit, _ = f.Seek(0, io.SeekEnd)
176 f.Seek(r.offset, io.SeekStart)
177 r.b = bufio.NewReader(f)
178 r.pkgprefix = objabi.PathToPrefix(p.ImportPath) + "."
179 }
180
181
182
183
184
185 func (r *objReader) error(err error) error {
186 if r.err == nil {
187 if err == io.EOF {
188 err = io.ErrUnexpectedEOF
189 }
190 r.err = err
191 }
192
193 return r.err
194 }
195
196
197 func (r *objReader) peek(n int) ([]byte, error) {
198 if r.err != nil {
199 return nil, r.err
200 }
201 if r.offset >= r.limit {
202 r.error(io.ErrUnexpectedEOF)
203 return nil, r.err
204 }
205 b, err := r.b.Peek(n)
206 if err != nil {
207 if err != bufio.ErrBufferFull {
208 r.error(err)
209 }
210 }
211 return b, err
212 }
213
214
215
216
217
218
219 func (r *objReader) readByte() byte {
220 if r.err != nil {
221 return 0
222 }
223 if r.offset >= r.limit {
224 r.error(io.ErrUnexpectedEOF)
225 return 0
226 }
227 b, err := r.b.ReadByte()
228 if err != nil {
229 if err == io.EOF {
230 err = io.ErrUnexpectedEOF
231 }
232 r.error(err)
233 b = 0
234 } else {
235 r.offset++
236 }
237 return b
238 }
239
240
241
242
243
244 func (r *objReader) readFull(b []byte) error {
245 if r.err != nil {
246 return r.err
247 }
248 if r.offset+int64(len(b)) > r.limit {
249 return r.error(io.ErrUnexpectedEOF)
250 }
251 n, err := io.ReadFull(r.b, b)
252 r.offset += int64(n)
253 if err != nil {
254 return r.error(err)
255 }
256 return nil
257 }
258
259
260 func (r *objReader) readInt() int64 {
261 var u uint64
262
263 for shift := uint(0); ; shift += 7 {
264 if shift >= 64 {
265 r.error(errCorruptObject)
266 return 0
267 }
268 c := r.readByte()
269 u |= uint64(c&0x7F) << shift
270 if c&0x80 == 0 {
271 break
272 }
273 }
274
275 return int64(u>>1) ^ (int64(u) << 63 >> 63)
276 }
277
278
279 func (r *objReader) readString() string {
280 n := r.readInt()
281 buf := make([]byte, n)
282 r.readFull(buf)
283 return string(buf)
284 }
285
286
287 func (r *objReader) readSymID() SymID {
288 i := r.readInt()
289 return r.p.SymRefs[i]
290 }
291
292 func (r *objReader) readRef() {
293 name, abiOrStatic := r.readString(), r.readInt()
294
295
296
297
298 name = strings.ReplaceAll(name, `"".`, r.pkgprefix)
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315 var vers int64
316 if abiOrStatic == -1 {
317
318 vers = r.p.MaxVersion
319 }
320 r.p.SymRefs = append(r.p.SymRefs, SymID{name, vers})
321 }
322
323
324 func (r *objReader) readData() Data {
325 n := r.readInt()
326 d := Data{Offset: r.dataOffset, Size: n}
327 r.dataOffset += n
328 return d
329 }
330
331
332 func (r *objReader) skip(n int64) {
333 if n < 0 {
334 r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip"))
335 }
336 if n < int64(len(r.tmp)) {
337
338
339 r.readFull(r.tmp[:n])
340 } else if n <= int64(r.b.Buffered()) {
341
342
343 for n > int64(len(r.tmp)) {
344 r.readFull(r.tmp[:])
345 n -= int64(len(r.tmp))
346 }
347 r.readFull(r.tmp[:n])
348 } else {
349
350 _, err := r.f.Seek(r.offset+n, io.SeekStart)
351 if err != nil {
352 r.error(err)
353 }
354 r.offset += n
355 r.b.Reset(r.f)
356 }
357 }
358
359
360
361 func Parse(f *os.File, pkgpath string) (*Package, error) {
362 if pkgpath == "" {
363 pkgpath = `""`
364 }
365 p := new(Package)
366 p.ImportPath = pkgpath
367
368 var rd objReader
369 rd.init(f, p)
370 err := rd.readFull(rd.tmp[:8])
371 if err != nil {
372 if err == io.EOF {
373 err = io.ErrUnexpectedEOF
374 }
375 return nil, err
376 }
377
378 switch {
379 default:
380 return nil, errNotObject
381
382 case bytes.Equal(rd.tmp[:8], archiveHeader):
383 if err := rd.parseArchive(); err != nil {
384 return nil, err
385 }
386 case bytes.Equal(rd.tmp[:8], goobjHeader):
387 if err := rd.parseObject(goobjHeader); err != nil {
388 return nil, err
389 }
390 }
391
392 return p, nil
393 }
394
395
396
397 func trimSpace(b []byte) string {
398 return string(bytes.TrimRight(b, " "))
399 }
400
401
402 func (r *objReader) parseArchive() error {
403 for r.offset < r.limit {
404 if err := r.readFull(r.tmp[:60]); err != nil {
405 return err
406 }
407 data := r.tmp[:60]
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425 if len(data) < 60 {
426 return errTruncatedArchive
427 }
428 if !bytes.Equal(data[58:60], archiveMagic) {
429 return errCorruptArchive
430 }
431 name := trimSpace(data[0:16])
432 size, err := strconv.ParseInt(trimSpace(data[48:58]), 10, 64)
433 if err != nil {
434 return errCorruptArchive
435 }
436 data = data[60:]
437 fsize := size + size&1
438 if fsize < 0 || fsize < size {
439 return errCorruptArchive
440 }
441 switch name {
442 case "__.PKGDEF":
443 r.skip(size)
444 default:
445 oldLimit := r.limit
446 r.limit = r.offset + size
447
448 p, err := r.peek(8)
449 if err != nil {
450 return err
451 }
452 if bytes.Equal(p, goobjHeader) {
453 if err := r.parseObject(nil); err != nil {
454 return fmt.Errorf("parsing archive member %q: %v", name, err)
455 }
456 } else {
457 r.p.Native = append(r.p.Native, &NativeReader{
458 Name: name,
459 ReaderAt: io.NewSectionReader(r.f, r.offset, size),
460 })
461 }
462
463 r.skip(r.limit - r.offset)
464 r.limit = oldLimit
465 }
466 if size&1 != 0 {
467 r.skip(1)
468 }
469 }
470 return nil
471 }
472
473
474
475
476
477
478
479
480 func (r *objReader) parseObject(prefix []byte) error {
481 r.p.MaxVersion++
482 h := make([]byte, 0, 256)
483 h = append(h, prefix...)
484 var c1, c2, c3 byte
485 for {
486 c1, c2, c3 = c2, c3, r.readByte()
487 h = append(h, c3)
488
489
490 if r.err != nil {
491 return errCorruptObject
492 }
493 if c1 == '\n' && c2 == '!' && c3 == '\n' {
494 break
495 }
496 }
497
498 hs := strings.Fields(string(h))
499 if len(hs) >= 4 {
500 r.p.Arch = hs[3]
501 }
502
503
504 r.readFull(r.tmp[:8])
505 if !bytes.Equal(r.tmp[:8], []byte("\x00go112ld")) {
506 return r.error(errCorruptObject)
507 }
508
509 b := r.readByte()
510 if b != 1 {
511 return r.error(errCorruptObject)
512 }
513
514
515 for {
516 s := r.readString()
517 if s == "" {
518 break
519 }
520 r.p.Imports = append(r.p.Imports, s)
521 }
522
523 r.p.SymRefs = []SymID{{"", 0}}
524 for {
525 if b := r.readByte(); b != 0xfe {
526 if b != 0xff {
527 return r.error(errCorruptObject)
528 }
529 break
530 }
531
532 r.readRef()
533 }
534
535 dataLength := r.readInt()
536 r.readInt()
537 r.readInt()
538 r.readInt()
539 r.readInt()
540 r.readInt()
541
542 r.dataOffset = r.offset
543 r.skip(dataLength)
544
545
546 for {
547 if b := r.readByte(); b != 0xfe {
548 if b != 0xff {
549 return r.error(errCorruptObject)
550 }
551 break
552 }
553
554 typ := r.readByte()
555 s := &Sym{SymID: r.readSymID()}
556 r.p.Syms = append(r.p.Syms, s)
557 s.Kind = objabi.SymKind(typ)
558 flags := r.readInt()
559 s.DupOK = flags&1 != 0
560 s.Size = r.readInt()
561 s.Type = r.readSymID()
562 s.Data = r.readData()
563 s.Reloc = make([]Reloc, r.readInt())
564 for i := range s.Reloc {
565 rel := &s.Reloc[i]
566 rel.Offset = r.readInt()
567 rel.Size = r.readInt()
568 rel.Type = objabi.RelocType(r.readInt())
569 rel.Add = r.readInt()
570 rel.Sym = r.readSymID()
571 }
572
573 if s.Kind == objabi.STEXT {
574 f := new(Func)
575 s.Func = f
576 f.Args = r.readInt()
577 f.Frame = r.readInt()
578 flags := r.readInt()
579 f.Leaf = flags&(1<<0) != 0
580 f.TopFrame = flags&(1<<4) != 0
581 f.NoSplit = r.readInt() != 0
582 f.Var = make([]Var, r.readInt())
583 for i := range f.Var {
584 v := &f.Var[i]
585 v.Name = r.readSymID().Name
586 v.Offset = r.readInt()
587 v.Kind = r.readInt()
588 v.Type = r.readSymID()
589 }
590
591 f.PCSP = r.readData()
592 f.PCFile = r.readData()
593 f.PCLine = r.readData()
594 f.PCInline = r.readData()
595 f.PCData = make([]Data, r.readInt())
596 for i := range f.PCData {
597 f.PCData[i] = r.readData()
598 }
599 f.FuncData = make([]FuncData, r.readInt())
600 for i := range f.FuncData {
601 f.FuncData[i].Sym = r.readSymID()
602 }
603 for i := range f.FuncData {
604 f.FuncData[i].Offset = r.readInt()
605 }
606 f.File = make([]string, r.readInt())
607 for i := range f.File {
608 f.File[i] = r.readSymID().Name
609 }
610 f.InlTree = make([]InlinedCall, r.readInt())
611 for i := range f.InlTree {
612 f.InlTree[i].Parent = r.readInt()
613 f.InlTree[i].File = r.readSymID().Name
614 f.InlTree[i].Line = r.readInt()
615 f.InlTree[i].Func = r.readSymID()
616 f.InlTree[i].ParentPC = r.readInt()
617 }
618 }
619 }
620
621 r.readFull(r.tmp[:7])
622 if !bytes.Equal(r.tmp[:7], []byte("go112ld")) {
623 return r.error(errCorruptObject)
624 }
625
626 return nil
627 }
628
629 func (r *Reloc) String(insnOffset uint64) string {
630 delta := r.Offset - int64(insnOffset)
631 s := fmt.Sprintf("[%d:%d]%s", delta, delta+r.Size, r.Type)
632 if r.Sym.Name != "" {
633 if r.Add != 0 {
634 return fmt.Sprintf("%s:%s+%d", s, r.Sym.Name, r.Add)
635 }
636 return fmt.Sprintf("%s:%s", s, r.Sym.Name)
637 }
638 if r.Add != 0 {
639 return fmt.Sprintf("%s:%d", s, r.Add)
640 }
641 return s
642 }
643
View as plain text