blob: 2aec1c17e8367902cd90825ed8cc8a9d42622fee [file] [log] [blame]
// 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:len(data)]
}
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:len(u.data)], 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()
}
}
}