| // Copyright 2012 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package dwarf | |
| import ( | |
| "fmt" | |
| "strconv" | |
| ) | |
| // Parse the type units stored in a DWARF4 .debug_types section. Each | |
| // type unit defines a single primary type and an 8-byte signature. | |
| // Other sections may then use formRefSig8 to refer to the type. | |
| // The typeUnit format is a single type with a signature. It holds | |
| // the same data as a compilation unit. | |
| type typeUnit struct { | |
| unit | |
| toff Offset // Offset to signature type within data. | |
| name string // Name of .debug_type section. | |
| cache Type // Cache the type, nil to start. | |
| } | |
| // Parse a .debug_types section. | |
| func (d *Data) parseTypes(name string, types []byte) error { | |
| b := makeBuf(d, unknownFormat{}, name, 0, types) | |
| for len(b.data) > 0 { | |
| base := b.off | |
| n, dwarf64 := b.unitLength() | |
| if n != Offset(uint32(n)) { | |
| b.error("type unit length overflow") | |
| return b.err | |
| } | |
| hdroff := b.off | |
| vers := int(b.uint16()) | |
| if vers != 4 { | |
| b.error("unsupported DWARF version " + strconv.Itoa(vers)) | |
| return b.err | |
| } | |
| var ao uint64 | |
| if !dwarf64 { | |
| ao = uint64(b.uint32()) | |
| } else { | |
| ao = b.uint64() | |
| } | |
| atable, err := d.parseAbbrev(ao, vers) | |
| if err != nil { | |
| return err | |
| } | |
| asize := b.uint8() | |
| sig := b.uint64() | |
| var toff uint32 | |
| if !dwarf64 { | |
| toff = b.uint32() | |
| } else { | |
| to64 := b.uint64() | |
| if to64 != uint64(uint32(to64)) { | |
| b.error("type unit type offset overflow") | |
| return b.err | |
| } | |
| toff = uint32(to64) | |
| } | |
| boff := b.off | |
| d.typeSigs[sig] = &typeUnit{ | |
| unit: unit{ | |
| base: base, | |
| off: boff, | |
| data: b.bytes(int(n - (b.off - hdroff))), | |
| atable: atable, | |
| asize: int(asize), | |
| vers: vers, | |
| is64: dwarf64, | |
| }, | |
| toff: Offset(toff), | |
| name: name, | |
| } | |
| if b.err != nil { | |
| return b.err | |
| } | |
| } | |
| return nil | |
| } | |
| // Return the type for a type signature. | |
| func (d *Data) sigToType(sig uint64) (Type, error) { | |
| tu := d.typeSigs[sig] | |
| if tu == nil { | |
| return nil, fmt.Errorf("no type unit with signature %v", sig) | |
| } | |
| if tu.cache != nil { | |
| return tu.cache, nil | |
| } | |
| b := makeBuf(d, tu, tu.name, tu.off, tu.data) | |
| r := &typeUnitReader{d: d, tu: tu, b: b} | |
| t, err := d.readType(tu.name, r, tu.toff, make(map[Offset]Type), nil) | |
| if err != nil { | |
| return nil, err | |
| } | |
| tu.cache = t | |
| return t, nil | |
| } | |
| // typeUnitReader is a typeReader for a tagTypeUnit. | |
| type typeUnitReader struct { | |
| d *Data | |
| tu *typeUnit | |
| b buf | |
| err error | |
| } | |
| // Seek to a new position in the type unit. | |
| func (tur *typeUnitReader) Seek(off Offset) { | |
| tur.err = nil | |
| doff := off - tur.tu.off | |
| if doff < 0 || doff >= Offset(len(tur.tu.data)) { | |
| tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data)) | |
| return | |
| } | |
| tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:]) | |
| } | |
| // AddressSize returns the size in bytes of addresses in the current type unit. | |
| func (tur *typeUnitReader) AddressSize() int { | |
| return tur.tu.unit.asize | |
| } | |
| // Next reads the next [Entry] from the type unit. | |
| func (tur *typeUnitReader) Next() (*Entry, error) { | |
| if tur.err != nil { | |
| return nil, tur.err | |
| } | |
| if len(tur.tu.data) == 0 { | |
| return nil, nil | |
| } | |
| e := tur.b.entry(nil, &tur.tu.unit) | |
| if tur.b.err != nil { | |
| tur.err = tur.b.err | |
| return nil, tur.err | |
| } | |
| return e, nil | |
| } | |
| // clone returns a new reader for the type unit. | |
| func (tur *typeUnitReader) clone() typeReader { | |
| return &typeUnitReader{ | |
| d: tur.d, | |
| tu: tur.tu, | |
| b: makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data), | |
| } | |
| } | |
| // offset returns the current offset. | |
| func (tur *typeUnitReader) offset() Offset { | |
| return tur.b.off | |
| } |