// Copyright 2009 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. // DWARF debug information entry parser. // An entry is a sequence of data items of a given format. // The first word in the entry is an index into what DWARF // calls the ``abbreviation table.'' An abbreviation is really // just a type descriptor: it's an array of attribute tag/value format pairs. package dwarf import ( "errors" "strconv" ) // a single entry's description: a sequence of attributes type abbrev struct { tag Tag children bool field []afield } type afield struct { attr Attr fmt format } // a map from entry format ids to their descriptions type abbrevTable map[uint32]abbrev // ParseAbbrev returns the abbreviation table that starts at byte off // in the .debug_abbrev section. func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) { if m, ok := d.abbrevCache[off]; ok { return m, nil } data := d.abbrev if off > uint32(len(data)) { data = nil } else { data = data[off:] } b := makeBuf(d, unknownFormat{}, "abbrev", 0, data) // Error handling is simplified by the buf getters // returning an endless stream of 0s after an error. m := make(abbrevTable) for { // Table ends with id == 0. id := uint32(b.uint()) if id == 0 { break } // Walk over attributes, counting. n := 0 b1 := b // Read from copy of b. b1.uint() b1.uint8() for { tag := b1.uint() fmt := b1.uint() if tag == 0 && fmt == 0 { break } n++ } if b1.err != nil { return nil, b1.err } // Walk over attributes again, this time writing them down. var a abbrev a.tag = Tag(b.uint()) a.children = b.uint8() != 0 a.field = make([]afield, n) for i := range a.field { a.field[i].attr = Attr(b.uint()) a.field[i].fmt = format(b.uint()) } b.uint() b.uint() m[id] = a } if b.err != nil { return nil, b.err } d.abbrevCache[off] = m return m, nil } // An entry is a sequence of attribute/value pairs. type Entry struct { Offset Offset // offset of Entry in DWARF info Tag Tag // tag (kind of Entry) Children bool // whether Entry is followed by children Field []Field } // A Field is a single attribute/value pair in an Entry. type Field struct { Attr Attr Val interface{} } // Val returns the value associated with attribute Attr in Entry, // or nil if there is no such attribute. // // A common idiom is to merge the check for nil return with // the check that the value has the expected dynamic type, as in: // v, ok := e.Val(AttrSibling).(int64); // func (e *Entry) Val(a Attr) interface{} { for _, f := range e.Field { if f.Attr == a { return f.Val } } return nil } // An Offset represents the location of an Entry within the DWARF info. // (See Reader.Seek.) type Offset uint32 // Entry reads a single entry from buf, decoding // according to the given abbreviation table. func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { off := b.off id := uint32(b.uint()) if id == 0 { return &Entry{} } a, ok := atab[id] if !ok { b.error("unknown abbreviation table index") return nil } e := &Entry{ Offset: off, Tag: a.tag, Children: a.children, Field: make([]Field, len(a.field)), } for i := range e.Field { e.Field[i].Attr = a.field[i].attr fmt := a.field[i].fmt if fmt == formIndirect { fmt = format(b.uint()) } var val interface{} switch fmt { default: b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16)) // address case formAddr: val = b.addr() // block case formDwarfBlock1: val = b.bytes(int(b.uint8())) case formDwarfBlock2: val = b.bytes(int(b.uint16())) case formDwarfBlock4: val = b.bytes(int(b.uint32())) case formDwarfBlock: val = b.bytes(int(b.uint())) // constant case formData1: val = int64(b.uint8()) case formData2: val = int64(b.uint16()) case formData4: val = int64(b.uint32()) case formData8: val = int64(b.uint64()) case formSdata: val = int64(b.int()) case formUdata: val = int64(b.uint()) // flag case formFlag: val = b.uint8() == 1 // New in DWARF 4. case formFlagPresent: // The attribute is implicitly indicated as present, and no value is // encoded in the debugging information entry itself. val = true // reference to other entry case formRefAddr: vers := b.format.version() if vers == 0 { b.error("unknown version for DW_FORM_ref_addr") } else if vers == 2 { val = Offset(b.addr()) } else { is64, known := b.format.dwarf64() if !known { b.error("unknown size for DW_FORM_ref_addr") } else if is64 { val = Offset(b.uint64()) } else { val = Offset(b.uint32()) } } case formRef1: val = Offset(b.uint8()) + ubase case formRef2: val = Offset(b.uint16()) + ubase case formRef4: val = Offset(b.uint32()) + ubase case formRef8: val = Offset(b.uint64()) + ubase case formRefUdata: val = Offset(b.uint()) + ubase // string case formString: val = b.string() case formStrp: off := b.uint32() // offset into .debug_str if b.err != nil { return nil } b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str) b1.skip(int(off)) val = b1.string() if b1.err != nil { b.err = b1.err return nil } // lineptr, loclistptr, macptr, rangelistptr // New in DWARF 4, but clang can generate them with -gdwarf-2. // Section reference, replacing use of formData4 and formData8. case formSecOffset, formGnuRefAlt, formGnuStrpAlt: is64, known := b.format.dwarf64() if !known { b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16)) } else if is64 { val = int64(b.uint64()) } else { val = int64(b.uint32()) } // exprloc // New in DWARF 4. case formExprloc: val = b.bytes(int(b.uint())) // reference // New in DWARF 4. case formRefSig8: // 64-bit type signature. val = b.uint64() } e.Field[i].Val = val } if b.err != nil { return nil } return e } // A Reader allows reading Entry structures from a DWARF ``info'' section. // The Entry structures are arranged in a tree. The Reader's Next function // return successive entries from a pre-order traversal of the tree. // If an entry has children, its Children field will be true, and the children // follow, terminated by an Entry with Tag 0. type Reader struct { b buf d *Data err error unit int lastChildren bool // .Children of last entry returned by Next lastSibling Offset // .Val(AttrSibling) of last entry returned by Next } // Reader returns a new Reader for Data. // The reader is positioned at byte offset 0 in the DWARF ``info'' section. func (d *Data) Reader() *Reader { r := &Reader{d: d} r.Seek(0) return r } // AddressSize returns the size in bytes of addresses in the current compilation // unit. func (r *Reader) AddressSize() int { return r.d.unit[r.unit].asize } // Seek positions the Reader at offset off in the encoded entry stream. // Offset 0 can be used to denote the first entry. func (r *Reader) Seek(off Offset) { d := r.d r.err = nil r.lastChildren = false if off == 0 { if len(d.unit) == 0 { return } u := &d.unit[0] r.unit = 0 r.b = makeBuf(r.d, u, "info", u.off, u.data) return } // TODO(rsc): binary search (maybe a new package) var i int var u *unit for i = range d.unit { u = &d.unit[i] if u.off <= off && off < u.off+Offset(len(u.data)) { r.unit = i r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:]) return } } r.err = errors.New("offset out of range") } // maybeNextUnit advances to the next unit if this one is finished. func (r *Reader) maybeNextUnit() { for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) { r.unit++ u := &r.d.unit[r.unit] r.b = makeBuf(r.d, u, "info", u.off, u.data) } } // Next reads the next entry from the encoded entry stream. // It returns nil, nil when it reaches the end of the section. // It returns an error if the current offset is invalid or the data at the // offset cannot be decoded as a valid Entry. func (r *Reader) Next() (*Entry, error) { if r.err != nil { return nil, r.err } r.maybeNextUnit() if len(r.b.data) == 0 { return nil, nil } u := &r.d.unit[r.unit] e := r.b.entry(u.atable, u.base) if r.b.err != nil { r.err = r.b.err return nil, r.err } if e != nil { r.lastChildren = e.Children if r.lastChildren { r.lastSibling, _ = e.Val(AttrSibling).(Offset) } } else { r.lastChildren = false } return e, nil } // SkipChildren skips over the child entries associated with // the last Entry returned by Next. If that Entry did not have // children or Next has not been called, SkipChildren is a no-op. func (r *Reader) SkipChildren() { if r.err != nil || !r.lastChildren { return } // If the last entry had a sibling attribute, // that attribute gives the offset of the next // sibling, so we can avoid decoding the // child subtrees. if r.lastSibling >= r.b.off { r.Seek(r.lastSibling) return } for { e, err := r.Next() if err != nil || e == nil || e.Tag == 0 { break } if e.Children { r.SkipChildren() } } } // clone returns a copy of the reader. This is used by the typeReader // interface. func (r *Reader) clone() typeReader { return r.d.Reader() } // offset returns the current buffer offset. This is used by the // typeReader interface. func (r *Reader) offset() Offset { return r.b.off }