|  | // 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 "strconv" | 
|  |  | 
|  | // A Type conventionally represents a pointer to any of the | 
|  | // specific Type structures (CharType, StructType, etc.). | 
|  | type Type interface { | 
|  | Common() *CommonType | 
|  | String() string | 
|  | Size() int64 | 
|  | } | 
|  |  | 
|  | // 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 } | 
|  |  | 
|  | func (c *CommonType) Size() int64 { return c.ByteSize } | 
|  |  | 
|  | // 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 | 
|  | } | 
|  |  | 
|  | // An UnspecifiedType represents an implicit, unknown, ambiguous or nonexistent type. | 
|  | type UnspecifiedType 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() } | 
|  |  | 
|  | func (t *QualType) Size() int64 { return t.Type.Size() } | 
|  |  | 
|  | // 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 // if == -1, an incomplete array, like char x[]. | 
|  | } | 
|  |  | 
|  | func (t *ArrayType) String() string { | 
|  | return "[" + strconv.FormatInt(t.Count, 10) + "]" + t.Type.String() | 
|  | } | 
|  |  | 
|  | func (t *ArrayType) Size() int64 { | 
|  | if t.Count == -1 { | 
|  | return 0 | 
|  | } | 
|  | return t.Count * t.Type.Size() | 
|  | } | 
|  |  | 
|  | // A VoidType represents the C void type. | 
|  | 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 // usually zero; use Type.Size() for normal fields | 
|  | 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.FormatInt(f.ByteOffset, 10) | 
|  | if f.BitSize > 0 { | 
|  | s += " : " + strconv.FormatInt(f.BitSize, 10) | 
|  | s += "@" + strconv.FormatInt(f.BitOffset, 10) | 
|  | } | 
|  | } | 
|  | 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.FormatInt(v.Val, 10) | 
|  | } | 
|  | 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 } | 
|  |  | 
|  | func (t *TypedefType) Size() int64 { return t.Type.Size() } | 
|  |  | 
|  | // An UnsupportedType is a placeholder returned in situations where we | 
|  | // encounter a type that isn't supported. | 
|  | type UnsupportedType struct { | 
|  | CommonType | 
|  | Tag Tag | 
|  | } | 
|  |  | 
|  | func (t *UnsupportedType) String() string { | 
|  | if t.Name != "" { | 
|  | return t.Name | 
|  | } | 
|  | return t.Name + "(unsupported type " + t.Tag.String() + ")" | 
|  | } | 
|  |  | 
|  | // typeReader is used to read from either the info section or the | 
|  | // types section. | 
|  | type typeReader interface { | 
|  | Seek(Offset) | 
|  | Next() (*Entry, error) | 
|  | clone() typeReader | 
|  | offset() Offset | 
|  | // AddressSize returns the size in bytes of addresses in the current | 
|  | // compilation unit. | 
|  | AddressSize() int | 
|  | } | 
|  |  | 
|  | // Type reads the type at off in the DWARF ``info'' section. | 
|  | func (d *Data) Type(off Offset) (Type, error) { | 
|  | return d.readType("info", d.Reader(), off, d.typeCache, nil) | 
|  | } | 
|  |  | 
|  | // readType reads a type from r at off of name. It adds types to the | 
|  | // type cache, appends new typedef types to typedefs, and computes the | 
|  | // sizes of types. Callers should pass nil for typedefs; this is used | 
|  | // for internal recursion. | 
|  | func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, typedefs *[]*TypedefType) (Type, error) { | 
|  | if t, ok := typeCache[off]; ok { | 
|  | return t, nil | 
|  | } | 
|  | r.Seek(off) | 
|  | e, err := r.Next() | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | addressSize := r.AddressSize() | 
|  | if e == nil || e.Offset != off { | 
|  | return nil, DecodeError{name, off, "no type at offset"} | 
|  | } | 
|  |  | 
|  | // If this is the root of the recursion, prepare to resolve | 
|  | // typedef sizes once the recursion is done. This must be done | 
|  | // after the type graph is constructed because it may need to | 
|  | // resolve cycles in a different order than readType | 
|  | // encounters them. | 
|  | if typedefs == nil { | 
|  | var typedefList []*TypedefType | 
|  | defer func() { | 
|  | for _, t := range typedefList { | 
|  | t.Common().ByteSize = t.Type.Size() | 
|  | } | 
|  | }() | 
|  | typedefs = &typedefList | 
|  | } | 
|  |  | 
|  | // Parse type from Entry. | 
|  | // Must always set typeCache[off] before calling | 
|  | // d.readType recursively, to handle circular types correctly. | 
|  | var typ Type | 
|  |  | 
|  | nextDepth := 0 | 
|  |  | 
|  | // Get next child; set err if error happens. | 
|  | next := func() *Entry { | 
|  | if !e.Children { | 
|  | return nil | 
|  | } | 
|  | // Only return direct children. | 
|  | // Skip over composite entries that happen to be nested | 
|  | // inside this one. Most DWARF generators wouldn't generate | 
|  | // such a thing, but clang does. | 
|  | // See golang.org/issue/6472. | 
|  | for { | 
|  | kid, err1 := r.Next() | 
|  | if err1 != nil { | 
|  | err = err1 | 
|  | return nil | 
|  | } | 
|  | if kid == nil { | 
|  | err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"} | 
|  | return nil | 
|  | } | 
|  | if kid.Tag == 0 { | 
|  | if nextDepth > 0 { | 
|  | nextDepth-- | 
|  | continue | 
|  | } | 
|  | return nil | 
|  | } | 
|  | if kid.Children { | 
|  | nextDepth++ | 
|  | } | 
|  | if nextDepth > 0 { | 
|  | continue | 
|  | } | 
|  | 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 { | 
|  | tval := e.Val(AttrType) | 
|  | var t Type | 
|  | switch toff := tval.(type) { | 
|  | case Offset: | 
|  | if t, err = d.readType(name, r.clone(), toff, typeCache, typedefs); err != nil { | 
|  | return nil | 
|  | } | 
|  | case uint64: | 
|  | if t, err = d.sigToType(toff); err != nil { | 
|  | return nil | 
|  | } | 
|  | default: | 
|  | // It appears that no Type means "void". | 
|  | return new(VoidType) | 
|  | } | 
|  | 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 | 
|  | typeCache[off] = t | 
|  | if t.Type = typeOf(e); err != nil { | 
|  | goto Error | 
|  | } | 
|  | t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64) | 
|  |  | 
|  | // Accumulate dimensions, | 
|  | var dims []int64 | 
|  | 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: | 
|  | count, ok := kid.Val(AttrCount).(int64) | 
|  | if !ok { | 
|  | // Old binaries may have an upper bound instead. | 
|  | count, ok = kid.Val(AttrUpperBound).(int64) | 
|  | if ok { | 
|  | count++ // Length is one more than upper bound. | 
|  | } else if len(dims) == 0 { | 
|  | count = -1 // As in x[]. | 
|  | } | 
|  | } | 
|  | dims = append(dims, count) | 
|  | case TagEnumerationType: | 
|  | err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"} | 
|  | goto Error | 
|  | } | 
|  | } | 
|  | if len(dims) == 0 { | 
|  | // LLVM generates this for x[]. | 
|  | dims = []int64{-1} | 
|  | } | 
|  |  | 
|  | t.Count = dims[0] | 
|  | for i := len(dims) - 1; i >= 1; i-- { | 
|  | t.Type = &ArrayType{Type: t.Type, Count: dims[i]} | 
|  | } | 
|  |  | 
|  | 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{name, e.Offset, "missing encoding attribute for " + name} | 
|  | goto Error | 
|  | } | 
|  | switch enc { | 
|  | default: | 
|  | err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"} | 
|  | goto Error | 
|  |  | 
|  | case encAddress: | 
|  | typ = new(AddrType) | 
|  | case encBoolean: | 
|  | typ = new(BoolType) | 
|  | case encComplexFloat: | 
|  | typ = new(ComplexType) | 
|  | if name == "complex" { | 
|  | // clang writes out 'complex' instead of 'complex float' or 'complex double'. | 
|  | // clang also writes out a byte size that we can use to distinguish. | 
|  | // See issue 8694. | 
|  | switch byteSize, _ := e.Val(AttrByteSize).(int64); byteSize { | 
|  | case 8: | 
|  | name = "complex float" | 
|  | case 16: | 
|  | name = "complex double" | 
|  | } | 
|  | } | 
|  | 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) | 
|  | } | 
|  | 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 | 
|  | 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) | 
|  | var lastFieldType *Type | 
|  | var lastFieldBitOffset int64 | 
|  | for kid := next(); kid != nil; kid = next() { | 
|  | if kid.Tag != TagMember { | 
|  | continue | 
|  | } | 
|  | f := new(StructField) | 
|  | if f.Type = typeOf(kid); err != nil { | 
|  | goto Error | 
|  | } | 
|  | switch loc := kid.Val(AttrDataMemberLoc).(type) { | 
|  | case []byte: | 
|  | // TODO: Should have original compilation | 
|  | // unit here, not unknownFormat. | 
|  | b := makeBuf(d, unknownFormat{}, "location", 0, loc) | 
|  | if b.uint8() != opPlusUconst { | 
|  | err = DecodeError{name, kid.Offset, "unexpected opcode"} | 
|  | goto Error | 
|  | } | 
|  | f.ByteOffset = int64(b.uint()) | 
|  | if b.err != nil { | 
|  | err = b.err | 
|  | goto Error | 
|  | } | 
|  | case int64: | 
|  | f.ByteOffset = loc | 
|  | } | 
|  |  | 
|  | haveBitOffset := false | 
|  | f.Name, _ = kid.Val(AttrName).(string) | 
|  | f.ByteSize, _ = kid.Val(AttrByteSize).(int64) | 
|  | f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64) | 
|  | f.BitSize, _ = kid.Val(AttrBitSize).(int64) | 
|  | t.Field = append(t.Field, f) | 
|  |  | 
|  | bito := f.BitOffset | 
|  | if !haveBitOffset { | 
|  | bito = f.ByteOffset * 8 | 
|  | } | 
|  | if bito == lastFieldBitOffset && t.Kind != "union" { | 
|  | // Last field was zero width. Fix array length. | 
|  | // (DWARF writes out 0-length arrays as if they were 1-length arrays.) | 
|  | zeroArray(lastFieldType) | 
|  | } | 
|  | lastFieldType = &f.Type | 
|  | lastFieldBitOffset = bito | 
|  | } | 
|  | if t.Kind != "union" { | 
|  | b, ok := e.Val(AttrByteSize).(int64) | 
|  | if ok && b*8 == lastFieldBitOffset { | 
|  | // Final field must be zero width. Fix array length. | 
|  | zeroArray(lastFieldType) | 
|  | } | 
|  | } | 
|  |  | 
|  | case TagConstType, TagVolatileType, TagRestrictType: | 
|  | // Type modifier (DWARF v2 §5.2) | 
|  | // Attributes: | 
|  | //	AttrType: subtype | 
|  | t := new(QualType) | 
|  | typ = t | 
|  | 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 | 
|  | 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) | 
|  | copy(val, t.Val) | 
|  | 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 | 
|  | 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 prototype [ignored] | 
|  | // Children: | 
|  | //	TagFormalParameter: typed parameter | 
|  | //		AttrType: type of parameter | 
|  | //	TagUnspecifiedParameter: final ... | 
|  | t := new(FuncType) | 
|  | typ = t | 
|  | typeCache[off] = t | 
|  | 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{} | 
|  | } | 
|  | t.ParamType = append(t.ParamType, tkid) | 
|  | } | 
|  |  | 
|  | case TagTypedef: | 
|  | // Typedef (DWARF v2 §5.3) | 
|  | // Attributes: | 
|  | //	AttrName: name [required] | 
|  | //	AttrType: type definition [required] | 
|  | t := new(TypedefType) | 
|  | typ = t | 
|  | typeCache[off] = t | 
|  | t.Name, _ = e.Val(AttrName).(string) | 
|  | t.Type = typeOf(e) | 
|  |  | 
|  | case TagUnspecifiedType: | 
|  | // Unspecified type (DWARF v3 §5.2) | 
|  | // Attributes: | 
|  | //	AttrName: name | 
|  | t := new(UnspecifiedType) | 
|  | typ = t | 
|  | typeCache[off] = t | 
|  | t.Name, _ = e.Val(AttrName).(string) | 
|  |  | 
|  | default: | 
|  | // This is some other type DIE that we're currently not | 
|  | // equipped to handle. Return an abstract "unsupported type" | 
|  | // object in such cases. | 
|  | t := new(UnsupportedType) | 
|  | typ = t | 
|  | typeCache[off] = t | 
|  | t.Tag = e.Tag | 
|  | t.Name, _ = e.Val(AttrName).(string) | 
|  | } | 
|  |  | 
|  | if err != nil { | 
|  | goto Error | 
|  | } | 
|  |  | 
|  | { | 
|  | b, ok := e.Val(AttrByteSize).(int64) | 
|  | if !ok { | 
|  | b = -1 | 
|  | switch t := typ.(type) { | 
|  | case *TypedefType: | 
|  | // Record that we need to resolve this | 
|  | // type's size once the type graph is | 
|  | // constructed. | 
|  | *typedefs = append(*typedefs, t) | 
|  | case *PtrType: | 
|  | b = int64(addressSize) | 
|  | } | 
|  | } | 
|  | typ.Common().ByteSize = b | 
|  | } | 
|  | 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. | 
|  | delete(typeCache, off) | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | func zeroArray(t *Type) { | 
|  | if t == nil { | 
|  | return | 
|  | } | 
|  | at, ok := (*t).(*ArrayType) | 
|  | if !ok || at.Type.Size() == 0 { | 
|  | return | 
|  | } | 
|  | // Make a copy to avoid invalidating typeCache. | 
|  | tt := *at | 
|  | tt.Count = 0 | 
|  | *t = &tt | 
|  | } |