github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/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: 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, tu.toff, make(map[Offset]Type), nil) 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 }