| // 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; |
| } |