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
// constant
case formData1:
- val = uint64(b.uint8());
+ val = int64(b.uint8());
case formData2:
- val = uint64(b.uint16());
+ val = int64(b.uint16());
case formData4:
- val = uint64(b.uint32());
+ val = int64(b.uint32());
case formData8:
- val = uint64(b.uint64());
+ val = int64(b.uint64());
case formSdata:
val = int64(b.int());
case formUdata:
- val = uint64(b.uint());
+ val = int64(b.uint());
// flag
case formFlag:
}
// 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.
func (r *Reader) Seek(off Offset) {
d := r.d;
r.err = nil;
+ r.lastChildren = false;
if off == 0 {
if len(d.unit) == 0 {
return;
// maybeNextUnit advances to the next unit if this one is finished.
func (r *Reader) maybeNextUnit() {
- for len(r.b.data) == 0 && r.unit < len(r.d.unit) {
+ 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);
}
u := &r.d.unit[r.unit];
e := r.b.entry(u.atable, u.base);
- r.err = r.b.err;
- return e, r.err;
+ 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();
+ }
+ }
+}
+
--- /dev/null
+// 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 type information structures.
+// The format is heavily biased toward C, but for simplicity
+// the String methods use a pseudo-Go syntax.
+
+package dwarf
+
+import (
+ "os";
+ "strconv";
+)
+
+// A CommonType holds fields common to multiple types.
+// If a field is not known or not applicable for a given type,
+// the zero value is used.
+type CommonType struct {
+ ByteSize int64; // size of value of this type, in bytes
+ Name string; // name that can be used to refer to type
+}
+
+func (c *CommonType) Common() *CommonType {
+ return c;
+}
+
+// Basic types
+
+// A BasicType holds fields common to all basic types.
+type BasicType struct {
+ CommonType;
+ BitSize int64;
+ BitOffset int64;
+}
+
+func (b *BasicType) Basic() *BasicType {
+ return b;
+}
+
+func (t *BasicType) String() string {
+ if t.Name != "" {
+ return t.Name;
+ }
+ return "?"
+}
+
+// A CharType represents a signed character type.
+type CharType struct {
+ BasicType;
+}
+
+// A UcharType represents an unsigned character type.
+type UcharType struct {
+ BasicType;
+}
+
+// An IntType represents a signed integer type.
+type IntType struct {
+ BasicType;
+}
+
+// A UintType represents an unsigned integer type.
+type UintType struct {
+ BasicType;
+}
+
+// A FloatType represents a floating point type.
+type FloatType struct {
+ BasicType;
+}
+
+// A ComplexType represents a complex floating point type.
+type ComplexType struct {
+ BasicType;
+}
+
+// A BoolType represents a boolean type.
+type BoolType struct {
+ BasicType;
+}
+
+// An AddrType represents a machine address type.
+type AddrType struct {
+ BasicType;
+}
+
+// qualifiers
+
+// A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier.
+type QualType struct {
+ CommonType;
+ Qual string;
+ Type Type;
+}
+
+func (t *QualType) String() string {
+ return t.Qual + " " + t.Type.String();
+}
+
+// An ArrayType represents a fixed size array type.
+type ArrayType struct {
+ CommonType;
+ Type Type;
+ StrideBitSize int64; // if > 0, number of bits to hold each element
+ Count int64;
+}
+
+func (t *ArrayType) String() string {
+ return "[" + strconv.Itoa64(t.Count) + "]" + t.Type.String();
+}
+
+// A VoidType represents the C void type.
+// It is only used as the subtype for a pointer:
+// a FuncType that returns no value has a nil ReturnType.
+type VoidType struct {
+ CommonType;
+}
+
+func (t *VoidType) String() string {
+ return "void";
+}
+
+// A PtrType represents a pointer type.
+type PtrType struct {
+ CommonType;
+ Type Type;
+}
+
+func (t *PtrType) String() string {
+ return "*" + t.Type.String();
+}
+
+// A StructType represents a struct, union, or C++ class type.
+type StructType struct {
+ CommonType;
+ StructName string;
+ Kind string; // "struct", "union", or "class".
+ Field []*StructField;
+ Incomplete bool; // if true, struct, union, class is declared but not defined
+}
+
+// A StructField represents a field in a struct, union, or C++ class type.
+type StructField struct {
+ Name string;
+ Type Type;
+ ByteOffset int64;
+ ByteSize int64;
+ BitOffset int64; // within the ByteSize bytes at ByteOffset
+ BitSize int64; // zero if not a bit field
+}
+
+func (t *StructType) String() string {
+ if t.StructName != "" {
+ return t.Kind + " " + t.StructName;
+ }
+ return t.Defn();
+}
+
+func (t *StructType) Defn() string {
+ s := t.Kind;
+ if t.StructName != "" {
+ s += " " + t.StructName;
+ }
+ if t.Incomplete {
+ s += " /*incomplete*/";
+ return s;
+ }
+ s += " {";
+ for i, f := range t.Field {
+ if i > 0 {
+ s += "; ";
+ }
+ s += f.Name + " " + f.Type.String();
+ s += "@" + strconv.Itoa64(f.ByteOffset);
+ if f.BitSize > 0 {
+ s += " : " + strconv.Itoa64(f.BitSize);
+ s += "@" + strconv.Itoa64(f.BitOffset);
+ }
+ }
+ s += "}";
+ return s;
+}
+
+// An EnumType represents an enumerated type.
+// The only indication of its native integer type is its ByteSize
+// (inside CommonType).
+type EnumType struct {
+ CommonType;
+ EnumName string;
+ Val []*EnumValue;
+}
+
+// An EnumValue represents a single enumeration value.
+type EnumValue struct {
+ Name string;
+ Val int64;
+}
+
+func (t *EnumType) String() string {
+ s := "enum";
+ if t.EnumName != "" {
+ s += " " + t.EnumName;
+ }
+ s += " {";
+ for i, v := range t.Val {
+ if i > 0 {
+ s += "; ";
+ }
+ s += v.Name + "=" + strconv.Itoa64(v.Val);
+ }
+ s += "}";
+ return s;
+}
+
+// A FuncType represents a function type.
+type FuncType struct {
+ CommonType;
+ ReturnType Type;
+ ParamType []Type;
+}
+
+func (t *FuncType) String() string {
+ s := "func(";
+ for i, t := range t.ParamType {
+ if i > 0 {
+ s += ", ";
+ }
+ s += t.String();
+ }
+ s += ")";
+ if t.ReturnType != nil {
+ s += " " + t.ReturnType.String();
+ }
+ return s;
+}
+
+// A DotDotDotType represents the variadic ... function parameter.
+type DotDotDotType struct {
+ CommonType;
+}
+
+func (t *DotDotDotType) String() string {
+ return "...";
+}
+
+// A TypedefType represents a named type.
+type TypedefType struct {
+ CommonType;
+ Type Type;
+}
+
+func (t *TypedefType) String() string {
+ return t.Name;
+}
+
+// A Type conventionally represents a pointer to any of the
+// specific Type structures (CharType, StructType, etc.).
+type Type interface {
+ Common() *CommonType;
+ String() string;
+}
+
+func (d *Data) Type(off Offset) (Type, os.Error) {
+ if t, ok := d.typeCache[off]; ok {
+ return t, nil;
+ }
+
+ r := d.Reader();
+ r.Seek(off);
+ e, err := r.Next();
+ if err != nil {
+ return nil, err;
+ }
+ if e == nil || e.Offset != off {
+ return nil, DecodeError{"info", off, "no type at offset"};
+ }
+
+ // Parse type from Entry.
+ // Must always set d.typeCache[off] before calling
+ // d.Type recursively, to handle circular types correctly.
+ var typ Type;
+
+ // Get next child; set err if error happens.
+ next := func() *Entry {
+ if !e.Children {
+ return nil;
+ }
+ kid, err1 := r.Next();
+ if err1 != nil {
+ err = err1;
+ return nil;
+ }
+ if kid == nil {
+ err = DecodeError{"info", r.b.off, "unexpected end of DWARF entries"};
+ return nil;
+ }
+ if kid.Tag == 0 {
+ return nil;
+ }
+ return kid;
+ };
+
+ // Get Type referred to by Entry's AttrType field.
+ // Set err if error happens. Not having a type is an error.
+ typeOf := func(e *Entry) Type {
+ toff, ok := e.Val(AttrType).(Offset);
+ if !ok {
+ err = DecodeError{"info", e.Offset, "missing type attribute"};
+ return nil;
+ }
+ var t Type;
+ if t, err = d.Type(toff); err != nil {
+ return nil;
+ }
+ return t;
+ };
+
+ switch e.Tag {
+ case TagArrayType:
+ // Multi-dimensional array. (DWARF v2 §5.4)
+ // Attributes:
+ // AttrType:subtype [required]
+ // AttrStrideSize: size in bits of each element of the array
+ // AttrByteSize: size of entire array
+ // Children:
+ // TagSubrangeType or TagEnumerationType giving one dimension.
+ // dimensions are in left to right order.
+ t := new(ArrayType);
+ typ = t;
+ d.typeCache[off] = t;
+ if t.Type = typeOf(e); err != nil {
+ goto Error;
+ }
+ t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64);
+
+ // Accumulate dimensions,
+ ndim := 0;
+ for kid := next(); kid != nil; kid = next() {
+ // TODO(rsc): Can also be TagEnumerationType
+ // but haven't seen that in the wild yet.
+ switch kid.Tag {
+ case TagSubrangeType:
+ max, ok := kid.Val(AttrUpperBound).(int64);
+ if !ok {
+ err = DecodeError{"info", kid.Offset, "missing upper bound"};
+ goto Error;
+ }
+ if ndim == 0 {
+ t.Count = max+1;
+ } else {
+ // Multidimensional array.
+ // Create new array type underneath this one.
+ t.Type = &ArrayType{Type: t.Type, Count: max+1};
+ }
+ ndim++;
+ case TagEnumerationType:
+ err = DecodeError{"info", kid.Offset, "cannot handle enumeration type as array bound"};
+ goto Error;
+ }
+ }
+ if ndim == 0 {
+ err = DecodeError{"info", e.Offset, "missing dimension for array"};
+ goto Error;
+ }
+
+ case TagBaseType:
+ // Basic type. (DWARF v2 §5.1)
+ // Attributes:
+ // AttrName: name of base type in programming language of the compilation unit [required]
+ // AttrEncoding: encoding value for type (encFloat etc) [required]
+ // AttrByteSize: size of type in bytes [required]
+ // AttrBitOffset: for sub-byte types, size in bits
+ // AttrBitSize: for sub-byte types, bit offset of high order bit in the AttrByteSize bytes
+ name, _ := e.Val(AttrName).(string);
+ enc, ok := e.Val(AttrEncoding).(int64);
+ if !ok {
+ err = DecodeError{"info", e.Offset, "missing encoding attribute for " + name};
+ goto Error;
+ }
+ switch enc {
+ default:
+ err = DecodeError{"info", e.Offset, "unrecognized encoding attribute value"};
+ goto Error;
+
+ case encAddress:
+ typ = new(AddrType);
+ case encBoolean:
+ typ = new(BoolType);
+ case encComplexFloat:
+ typ = new(ComplexType);
+ case encFloat:
+ typ = new(FloatType);
+ case encSigned:
+ typ = new(IntType);
+ case encUnsigned:
+ typ = new(UintType);
+ case encSignedChar:
+ typ = new(CharType);
+ case encUnsignedChar:
+ typ = new(UcharType);
+ }
+ d.typeCache[off] = typ;
+ t := typ.(interface{Basic() *BasicType}).Basic();
+ t.Name = name;
+ t.BitSize, _ = e.Val(AttrBitSize).(int64);
+ t.BitOffset, _ = e.Val(AttrBitOffset).(int64);
+
+ case TagClassType, TagStructType, TagUnionType:
+ // Structure, union, or class type. (DWARF v2 §5.5)
+ // Attributes:
+ // AttrName: name of struct, union, or class
+ // AttrByteSize: byte size [required]
+ // AttrDeclaration: if true, struct/union/class is incomplete
+ // Children:
+ // TagMember to describe one member.
+ // AttrName: name of member [required]
+ // AttrType: type of member [required]
+ // AttrByteSize: size in bytes
+ // AttrBitOffset: bit offset within bytes for bit fields
+ // AttrBitSize: bit size for bit fields
+ // AttrDataMemberLoc: location within struct [required for struct, class]
+ // There is much more to handle C++, all ignored for now.
+ t := new(StructType);
+ typ = t;
+ d.typeCache[off] = t;
+ switch e.Tag {
+ case TagClassType:
+ t.Kind = "class";
+ case TagStructType:
+ t.Kind = "struct";
+ case TagUnionType:
+ t.Kind = "union";
+ }
+ t.StructName, _ = e.Val(AttrName).(string);
+ t.Incomplete = e.Val(AttrDeclaration) != nil;
+ t.Field = make([]*StructField, 0, 8);
+ for kid := next(); kid != nil; kid = next() {
+ if kid.Tag == TagMember {
+ f := new(StructField);
+ if f.Type = typeOf(kid); err != nil {
+ goto Error;
+ }
+ if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
+ b := makeBuf(d, "location", 0, loc, d.addrsize);
+ if b.uint8() != opPlusUconst {
+ err = DecodeError{"info", kid.Offset, "unexpected opcode"};
+ goto Error;
+ }
+ f.ByteOffset = int64(b.uint());
+ if b.err != nil {
+ err = b.err;
+ goto Error;
+ }
+ }
+ f.Name, _ = kid.Val(AttrName).(string);
+ f.ByteSize, _ = kid.Val(AttrByteSize).(int64);
+ f.BitOffset, _ = kid.Val(AttrBitOffset).(int64);
+ f.BitSize, _ = kid.Val(AttrBitSize).(int64);
+ n := len(t.Field);
+ if n >= cap(t.Field) {
+ fld := make([]*StructField, n, n*2);
+ for i, f := range t.Field {
+ fld[i] = f;
+ }
+ t.Field = fld;
+ }
+ t.Field = t.Field[0:n+1];
+ t.Field[n] = f;
+ }
+ }
+
+ case TagConstType, TagVolatileType, TagRestrictType:
+ // Type modifier (DWARF v2 §5.2)
+ // Attributes:
+ // AttrType: subtype
+ t := new(QualType);
+ typ = t;
+ d.typeCache[off] = t;
+ if t.Type = typeOf(e); err != nil {
+ goto Error;
+ }
+ switch e.Tag {
+ case TagConstType:
+ t.Qual = "const";
+ case TagRestrictType:
+ t.Qual = "restrict";
+ case TagVolatileType:
+ t.Qual = "volatile";
+ }
+
+ case TagEnumerationType:
+ // Enumeration type (DWARF v2 §5.6)
+ // Attributes:
+ // AttrName: enum name if any
+ // AttrByteSize: bytes required to represent largest value
+ // Children:
+ // TagEnumerator:
+ // AttrName: name of constant
+ // AttrConstValue: value of constant
+ t := new(EnumType);
+ typ = t;
+ d.typeCache[off] = t;
+ t.EnumName, _ = e.Val(AttrName).(string);
+ t.Val = make([]*EnumValue, 0, 8);
+ for kid := next(); kid != nil; kid = next() {
+ if kid.Tag == TagEnumerator {
+ f := new(EnumValue);
+ f.Name, _ = kid.Val(AttrName).(string);
+ f.Val, _ = kid.Val(AttrConstValue).(int64);
+ n := len(t.Val);
+ if n >= cap(t.Val) {
+ val := make([]*EnumValue, n, n*2);
+ for i, f := range t.Val {
+ val[i] = f;
+ }
+ t.Val = val;
+ }
+ t.Val = t.Val[0:n+1];
+ t.Val[n] = f;
+ }
+ }
+
+ case TagPointerType:
+ // Type modifier (DWARF v2 §5.2)
+ // Attributes:
+ // AttrType: subtype [not required! void* has no AttrType]
+ // AttrAddrClass: address class [ignored]
+ t := new(PtrType);
+ typ = t;
+ d.typeCache[off] = t;
+ if e.Val(AttrType) == nil {
+ t.Type = &VoidType{};
+ break;
+ }
+ t.Type = typeOf(e);
+
+ case TagSubroutineType:
+ // Subroutine type. (DWARF v2 §5.7)
+ // Attributes:
+ // AttrType: type of return value if any
+ // AttrName: possible name of type [ignored]
+ // AttrPrototyped: whether used ANSI C prototye [ignored]
+ // Children:
+ // TagFormalParameter: typed parameter
+ // AttrType: type of parameter
+ // TagUnspecifiedParameter: final ...
+ t := new(FuncType);
+ typ = t;
+ d.typeCache[off] = t;
+ if e.Val(AttrType) != nil {
+ if t.ReturnType = typeOf(e); err != nil {
+ goto Error;
+ }
+ }
+ t.ParamType = make([]Type, 0, 8);
+ for kid := next(); kid != nil; kid = next() {
+ var tkid Type;
+ switch kid.Tag {
+ default:
+ continue;
+ case TagFormalParameter:
+ if tkid = typeOf(kid); err != nil {
+ goto Error;
+ }
+ case TagUnspecifiedParameters:
+ tkid = &DotDotDotType{};
+ }
+ n := len(t.ParamType);
+ if n >= cap(t.ParamType) {
+ param := make([]Type, n, n*2);
+ for i, t := range t.ParamType {
+ param[i] = t;
+ }
+ t.ParamType = param;
+ }
+ t.ParamType = t.ParamType[0:n+1];
+ t.ParamType[n] = tkid;
+ }
+
+ case TagTypedef:
+ // Typedef (DWARF v2 §5.3)
+ // Attributes:
+ // AttrName: name [required]
+ // AttrType: type definition [required]
+ t := new(TypedefType);
+ typ = t;
+ d.typeCache[off] = t;
+ t.Name, _ = e.Val(AttrName).(string);
+ t.Type = typeOf(e);
+ }
+
+ if err != nil {
+ goto Error;
+ }
+
+ typ.Common().ByteSize, _ = e.Val(AttrByteSize).(int64);
+
+ return typ, nil;
+
+Error:
+ // If the parse fails, take the type out of the cache
+ // so that the next call with this offset doesn't hit
+ // the cache and return success.
+ d.typeCache[off] = nil, false;
+ return nil, err;
+}
--- /dev/null
+// 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.
+
+package dwarf
+
+import (
+ "debug/elf";
+ "testing";
+)
+
+var typedefTests = map[string]string {
+ "t_ptr_volatile_int": "*volatile int",
+ "t_ptr_const_char": "*const char",
+ "t_long": "long int",
+ "t_ushort": "short unsigned int",
+ "t_func_int_of_float_double": "func(float, double) int",
+ "t_ptr_func_int_of_float_double": "*func(float, double) int",
+ "t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int",
+ "t_func_void_of_char": "func(char)",
+ "t_func_void_of_void": "func()",
+ "t_func_void_of_ptr_char_dots": "func(*char, ...)",
+ "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; array [40]long long int@8}",
+ "t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
+ "t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
+ "t_my_list": "struct list {val short int@0; next *t_my_list@8}",
+ "t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}"
+};
+
+func elfData(t *testing.T, name string) *Data {
+ f, err := elf.Open(name);
+ if err != nil {
+ t.Fatal(err);
+ }
+
+ dat := func(name string) []byte {
+ s := f.Section(".debug_" + name);
+ if s == nil {
+ return nil
+ }
+ b, err := s.Data();
+ if err != nil {
+ t.Fatal(".debug_"+name+":", err);
+ }
+ return b;
+ };
+
+ d, err := New(dat("abbrev"), nil, nil, dat("info"), nil, nil, nil, dat("str"));
+ if err != nil {
+ t.Fatal("New:", err);
+ }
+
+ return d;
+}
+
+
+func TestTypedefs(t *testing.T) {
+ d := elfData(t, "testdata/typedef.elf");
+ r := d.Reader();
+ seen := make(map[string]bool);
+ for {
+ e, err := r.Next();
+ if err != nil {
+ t.Fatal("r.Next:", err);
+ }
+ if e == nil {
+ break;
+ }
+ if e.Tag == TagTypedef {
+ typ, err := d.Type(e.Offset);
+ if err != nil {
+ t.Fatal("d.Type:", err);
+ }
+ t1 := typ.(*TypedefType);
+ var typstr string;
+ if ts, ok := t1.Type.(*StructType); ok {
+ typstr = ts.Defn();
+ } else {
+ typstr = t1.Type.String();
+ }
+
+ if want, ok := typedefTests[t1.Name]; ok {
+ if _, ok := seen[t1.Name]; ok {
+ t.Errorf("multiple definitions for %s", t1.Name);
+ }
+ seen[t1.Name] = true;
+ if typstr != want {
+ t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want);
+ }
+ }
+ }
+ if e.Tag != TagCompileUnit {
+ r.SkipChildren();
+ }
+ }
+
+ for k := range typedefTests {
+ if _, ok := seen[k]; !ok {
+ t.Errorf("missing %s", k);
+ }
+ }
+}