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