github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/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 }