// 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 "os" // 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, os.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, "abbrev", 0, data, 0); // 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") // 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 // reference to other entry case formRefAddr: val = Offset(b.addr()) 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, "str", 0, b.dwarf.str, 0); b1.skip(int(off)); val = b1.string(); if b1.err != nil { b.err = b1.err; return nil; } } 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 os.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; } // 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, "info", u.off, u.data, u.addrsize); 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, "info", off, u.data[off-u.off:], u.addrsize); return; } } r.err = os.NewError("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, "info", u.off, u.data, u.addrsize); } } // 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, os.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() } } }