github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/src/debug/dwarf/typeunit.go (about)

     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 uint32
    42  		if !dwarf64 {
    43  			ao = b.uint32()
    44  		} else {
    45  			ao64 := b.uint64()
    46  			if ao64 != uint64(uint32(ao64)) {
    47  				b.error("type unit abbrev offset overflow")
    48  				return b.err
    49  			}
    50  			ao = uint32(ao64)
    51  		}
    52  		atable, err := d.parseAbbrev(ao, vers)
    53  		if err != nil {
    54  			return err
    55  		}
    56  		asize := b.uint8()
    57  		sig := b.uint64()
    58  
    59  		var toff uint32
    60  		if !dwarf64 {
    61  			toff = b.uint32()
    62  		} else {
    63  			to64 := b.uint64()
    64  			if to64 != uint64(uint32(to64)) {
    65  				b.error("type unit type offset overflow")
    66  				return b.err
    67  			}
    68  			toff = uint32(to64)
    69  		}
    70  
    71  		boff := b.off
    72  		d.typeSigs[sig] = &typeUnit{
    73  			unit: unit{
    74  				base:   base,
    75  				off:    boff,
    76  				data:   b.bytes(int(n - (b.off - hdroff))),
    77  				atable: atable,
    78  				asize:  int(asize),
    79  				vers:   int(vers),
    80  				is64:   dwarf64,
    81  			},
    82  			toff: Offset(toff),
    83  			name: name,
    84  		}
    85  		if b.err != nil {
    86  			return b.err
    87  		}
    88  	}
    89  	return nil
    90  }
    91  
    92  // Return the type for a type signature.
    93  func (d *Data) sigToType(sig uint64) (Type, error) {
    94  	tu := d.typeSigs[sig]
    95  	if tu == nil {
    96  		return nil, fmt.Errorf("no type unit with signature %v", sig)
    97  	}
    98  	if tu.cache != nil {
    99  		return tu.cache, nil
   100  	}
   101  
   102  	b := makeBuf(d, tu, tu.name, tu.off, tu.data)
   103  	r := &typeUnitReader{d: d, tu: tu, b: b}
   104  	t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type))
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	tu.cache = t
   110  	return t, nil
   111  }
   112  
   113  // typeUnitReader is a typeReader for a tagTypeUnit.
   114  type typeUnitReader struct {
   115  	d   *Data
   116  	tu  *typeUnit
   117  	b   buf
   118  	err error
   119  }
   120  
   121  // Seek to a new position in the type unit.
   122  func (tur *typeUnitReader) Seek(off Offset) {
   123  	tur.err = nil
   124  	doff := off - tur.tu.off
   125  	if doff < 0 || doff >= Offset(len(tur.tu.data)) {
   126  		tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data))
   127  		return
   128  	}
   129  	tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
   130  }
   131  
   132  // AddressSize returns the size in bytes of addresses in the current type unit.
   133  func (tur *typeUnitReader) AddressSize() int {
   134  	return tur.tu.unit.asize
   135  }
   136  
   137  // Next reads the next Entry from the type unit.
   138  func (tur *typeUnitReader) Next() (*Entry, error) {
   139  	if tur.err != nil {
   140  		return nil, tur.err
   141  	}
   142  	if len(tur.tu.data) == 0 {
   143  		return nil, nil
   144  	}
   145  	e := tur.b.entry(tur.tu.atable, tur.tu.base)
   146  	if tur.b.err != nil {
   147  		tur.err = tur.b.err
   148  		return nil, tur.err
   149  	}
   150  	return e, nil
   151  }
   152  
   153  // clone returns a new reader for the type unit.
   154  func (tur *typeUnitReader) clone() typeReader {
   155  	return &typeUnitReader{
   156  		d:  tur.d,
   157  		tu: tur.tu,
   158  		b:  makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data),
   159  	}
   160  }
   161  
   162  // offset returns the current offset.
   163  func (tur *typeUnitReader) offset() Offset {
   164  	return tur.b.off
   165  }