Home | History | Annotate | Download | only in dwarf
      1 // Copyright 2012 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package dwarf
      6 
      7 import (
      8 	"fmt"
      9 	"strconv"
     10 )
     11 
     12 // Parse the type units stored in a DWARF4 .debug_types section. Each
     13 // type unit defines a single primary type and an 8-byte signature.
     14 // Other sections may then use formRefSig8 to refer to the type.
     15 
     16 // The typeUnit format is a single type with a signature. It holds
     17 // the same data as a compilation unit.
     18 type typeUnit struct {
     19 	unit
     20 	toff  Offset // Offset to signature type within data.
     21 	name  string // Name of .debug_type section.
     22 	cache Type   // Cache the type, nil to start.
     23 }
     24 
     25 // Parse a .debug_types section.
     26 func (d *Data) parseTypes(name string, types []byte) error {
     27 	b := makeBuf(d, unknownFormat{}, name, 0, types)
     28 	for len(b.data) > 0 {
     29 		base := b.off
     30 		n, dwarf64 := b.unitLength()
     31 		if n != Offset(uint32(n)) {
     32 			b.error("type unit length overflow")
     33 			return b.err
     34 		}
     35 		hdroff := b.off
     36 		vers := int(b.uint16())
     37 		if vers != 4 {
     38 			b.error("unsupported DWARF version " + strconv.Itoa(vers))
     39 			return b.err
     40 		}
     41 		var ao uint64
     42 		if !dwarf64 {
     43 			ao = uint64(b.uint32())
     44 		} else {
     45 			ao = b.uint64()
     46 		}
     47 		atable, err := d.parseAbbrev(ao, vers)
     48 		if err != nil {
     49 			return err
     50 		}
     51 		asize := b.uint8()
     52 		sig := b.uint64()
     53 
     54 		var toff uint32
     55 		if !dwarf64 {
     56 			toff = b.uint32()
     57 		} else {
     58 			to64 := b.uint64()
     59 			if to64 != uint64(uint32(to64)) {
     60 				b.error("type unit type offset overflow")
     61 				return b.err
     62 			}
     63 			toff = uint32(to64)
     64 		}
     65 
     66 		boff := b.off
     67 		d.typeSigs[sig] = &typeUnit{
     68 			unit: unit{
     69 				base:   base,
     70 				off:    boff,
     71 				data:   b.bytes(int(n - (b.off - hdroff))),
     72 				atable: atable,
     73 				asize:  int(asize),
     74 				vers:   vers,
     75 				is64:   dwarf64,
     76 			},
     77 			toff: Offset(toff),
     78 			name: name,
     79 		}
     80 		if b.err != nil {
     81 			return b.err
     82 		}
     83 	}
     84 	return nil
     85 }
     86 
     87 // Return the type for a type signature.
     88 func (d *Data) sigToType(sig uint64) (Type, error) {
     89 	tu := d.typeSigs[sig]
     90 	if tu == nil {
     91 		return nil, fmt.Errorf("no type unit with signature %v", sig)
     92 	}
     93 	if tu.cache != nil {
     94 		return tu.cache, nil
     95 	}
     96 
     97 	b := makeBuf(d, tu, tu.name, tu.off, tu.data)
     98 	r := &typeUnitReader{d: d, tu: tu, b: b}
     99 	t, err := d.readType(tu.name, r, tu.toff, make(map[Offset]Type), nil)
    100 	if err != nil {
    101 		return nil, err
    102 	}
    103 
    104 	tu.cache = t
    105 	return t, nil
    106 }
    107 
    108 // typeUnitReader is a typeReader for a tagTypeUnit.
    109 type typeUnitReader struct {
    110 	d   *Data
    111 	tu  *typeUnit
    112 	b   buf
    113 	err error
    114 }
    115 
    116 // Seek to a new position in the type unit.
    117 func (tur *typeUnitReader) Seek(off Offset) {
    118 	tur.err = nil
    119 	doff := off - tur.tu.off
    120 	if doff < 0 || doff >= Offset(len(tur.tu.data)) {
    121 		tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data))
    122 		return
    123 	}
    124 	tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
    125 }
    126 
    127 // AddressSize returns the size in bytes of addresses in the current type unit.
    128 func (tur *typeUnitReader) AddressSize() int {
    129 	return tur.tu.unit.asize
    130 }
    131 
    132 // Next reads the next Entry from the type unit.
    133 func (tur *typeUnitReader) Next() (*Entry, error) {
    134 	if tur.err != nil {
    135 		return nil, tur.err
    136 	}
    137 	if len(tur.tu.data) == 0 {
    138 		return nil, nil
    139 	}
    140 	e := tur.b.entry(tur.tu.atable, tur.tu.base)
    141 	if tur.b.err != nil {
    142 		tur.err = tur.b.err
    143 		return nil, tur.err
    144 	}
    145 	return e, nil
    146 }
    147 
    148 // clone returns a new reader for the type unit.
    149 func (tur *typeUnitReader) clone() typeReader {
    150 	return &typeUnitReader{
    151 		d:  tur.d,
    152 		tu: tur.tu,
    153 		b:  makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data),
    154 	}
    155 }
    156 
    157 // offset returns the current offset.
    158 func (tur *typeUnitReader) offset() Offset {
    159 	return tur.b.off
    160 }
    161