| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | package dwarf |
| |
|
| | import "strconv" |
| |
|
| | |
| | |
| | type Type interface { |
| | Common() *CommonType |
| | String() string |
| | Size() int64 |
| | } |
| |
|
| | |
| | |
| | |
| | type CommonType struct { |
| | ByteSize int64 |
| | Name string |
| | } |
| |
|
| | func (c *CommonType) Common() *CommonType { return c } |
| |
|
| | func (c *CommonType) Size() int64 { return c.ByteSize } |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | type BasicType struct { |
| | CommonType |
| | BitSize int64 |
| | BitOffset int64 |
| | DataBitOffset int64 |
| | } |
| |
|
| | func (b *BasicType) Basic() *BasicType { return b } |
| |
|
| | func (t *BasicType) String() string { |
| | if t.Name != "" { |
| | return t.Name |
| | } |
| | return "?" |
| | } |
| |
|
| | |
| | type CharType struct { |
| | BasicType |
| | } |
| |
|
| | |
| | type UcharType struct { |
| | BasicType |
| | } |
| |
|
| | |
| | type IntType struct { |
| | BasicType |
| | } |
| |
|
| | |
| | type UintType struct { |
| | BasicType |
| | } |
| |
|
| | |
| | type FloatType struct { |
| | BasicType |
| | } |
| |
|
| | |
| | type ComplexType struct { |
| | BasicType |
| | } |
| |
|
| | |
| | type BoolType struct { |
| | BasicType |
| | } |
| |
|
| | |
| | type AddrType struct { |
| | BasicType |
| | } |
| |
|
| | |
| | type UnspecifiedType struct { |
| | BasicType |
| | } |
| |
|
| | |
| |
|
| | |
| | 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() } |
| |
|
| | |
| | type ArrayType struct { |
| | CommonType |
| | Type Type |
| | StrideBitSize int64 |
| | Count int64 |
| | } |
| |
|
| | 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() |
| | } |
| |
|
| | |
| | type VoidType struct { |
| | CommonType |
| | } |
| |
|
| | func (t *VoidType) String() string { return "void" } |
| |
|
| | |
| | type PtrType struct { |
| | CommonType |
| | Type Type |
| | } |
| |
|
| | func (t *PtrType) String() string { return "*" + t.Type.String() } |
| |
|
| | |
| | type StructType struct { |
| | CommonType |
| | StructName string |
| | Kind string |
| | Field []*StructField |
| | Incomplete bool |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type StructField struct { |
| | Name string |
| | Type Type |
| | ByteOffset int64 |
| | ByteSize int64 |
| | BitOffset int64 |
| | DataBitOffset int64 |
| | BitSize int64 |
| | } |
| |
|
| | func (t *StructType) String() string { |
| | if t.StructName != "" { |
| | return t.Kind + " " + t.StructName |
| | } |
| | return t.Defn() |
| | } |
| |
|
| | func (f *StructField) bitOffset() int64 { |
| | if f.BitOffset != 0 { |
| | return f.BitOffset |
| | } |
| | return f.DataBitOffset |
| | } |
| |
|
| | 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 |
| | } |
| |
|
| | |
| | |
| | |
| | type EnumType struct { |
| | CommonType |
| | EnumName string |
| | Val []*EnumValue |
| | } |
| |
|
| | |
| | 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 |
| | } |
| |
|
| | |
| | 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 |
| | } |
| |
|
| | |
| | type DotDotDotType struct { |
| | CommonType |
| | } |
| |
|
| | func (t *DotDotDotType) String() string { return "..." } |
| |
|
| | |
| | type TypedefType struct { |
| | CommonType |
| | Type Type |
| | } |
| |
|
| | func (t *TypedefType) String() string { return t.Name } |
| |
|
| | func (t *TypedefType) Size() int64 { return t.Type.Size() } |
| |
|
| | |
| | |
| | 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() + ")" |
| | } |
| |
|
| | |
| | |
| | type typeReader interface { |
| | Seek(Offset) |
| | Next() (*Entry, error) |
| | clone() typeReader |
| | offset() Offset |
| | |
| | |
| | AddressSize() int |
| | } |
| |
|
| | |
| | func (d *Data) Type(off Offset) (Type, error) { |
| | return d.readType("info", d.Reader(), off, d.typeCache, nil) |
| | } |
| |
|
| | type typeFixer struct { |
| | typedefs []*TypedefType |
| | arraytypes []*Type |
| | } |
| |
|
| | func (tf *typeFixer) recordArrayType(t *Type) { |
| | if t == nil { |
| | return |
| | } |
| | _, ok := (*t).(*ArrayType) |
| | if ok { |
| | tf.arraytypes = append(tf.arraytypes, t) |
| | } |
| | } |
| |
|
| | func (tf *typeFixer) apply() { |
| | for _, t := range tf.typedefs { |
| | t.Common().ByteSize = t.Type.Size() |
| | } |
| | for _, t := range tf.arraytypes { |
| | zeroArray(t) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, fixups *typeFixer) (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 fixups == nil { |
| | var fixer typeFixer |
| | defer func() { |
| | fixer.apply() |
| | }() |
| | fixups = &fixer |
| | } |
| |
|
| | |
| | |
| | |
| | var typ Type |
| |
|
| | nextDepth := 0 |
| |
|
| | |
| | next := func() *Entry { |
| | if !e.Children { |
| | return nil |
| | } |
| | |
| | |
| | |
| | |
| | |
| | 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 |
| | } |
| | } |
| |
|
| | |
| | |
| | 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, fixups); err != nil { |
| | return nil |
| | } |
| | case uint64: |
| | if t, err = d.sigToType(toff); err != nil { |
| | return nil |
| | } |
| | default: |
| | |
| | return new(VoidType) |
| | } |
| | return t |
| | } |
| |
|
| | switch e.Tag { |
| | case TagArrayType: |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | t := new(ArrayType) |
| | typ = t |
| | typeCache[off] = t |
| | if t.Type = typeOf(e); err != nil { |
| | goto Error |
| | } |
| | t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64) |
| |
|
| | |
| | var dims []int64 |
| | for kid := next(); kid != nil; kid = next() { |
| | |
| | |
| | switch kid.Tag { |
| | case TagSubrangeType: |
| | count, ok := kid.Val(AttrCount).(int64) |
| | if !ok { |
| | |
| | count, ok = kid.Val(AttrUpperBound).(int64) |
| | if ok { |
| | count++ |
| | } else if len(dims) == 0 { |
| | count = -1 |
| | } |
| | } |
| | dims = append(dims, count) |
| | case TagEnumerationType: |
| | err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"} |
| | goto Error |
| | } |
| | } |
| | if len(dims) == 0 { |
| | |
| | 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: |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | 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" { |
| | |
| | |
| | |
| | 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) |
| | haveBitOffset := false |
| | haveDataBitOffset := false |
| | t.BitOffset, haveBitOffset = e.Val(AttrBitOffset).(int64) |
| | t.DataBitOffset, haveDataBitOffset = e.Val(AttrDataBitOffset).(int64) |
| | if haveBitOffset && haveDataBitOffset { |
| | err = DecodeError{name, e.Offset, "duplicate bit offset attributes"} |
| | goto Error |
| | } |
| |
|
| | case TagClassType, TagStructType, TagUnionType: |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | 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 lastFieldBitSize int64 |
| | var lastFieldByteOffset 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: |
| | |
| | |
| | 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 |
| | } |
| |
|
| | f.Name, _ = kid.Val(AttrName).(string) |
| | f.ByteSize, _ = kid.Val(AttrByteSize).(int64) |
| | haveBitOffset := false |
| | haveDataBitOffset := false |
| | f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64) |
| | f.DataBitOffset, haveDataBitOffset = kid.Val(AttrDataBitOffset).(int64) |
| | if haveBitOffset && haveDataBitOffset { |
| | err = DecodeError{name, e.Offset, "duplicate bit offset attributes"} |
| | goto Error |
| | } |
| | f.BitSize, _ = kid.Val(AttrBitSize).(int64) |
| | t.Field = append(t.Field, f) |
| |
|
| | if lastFieldBitSize == 0 && lastFieldByteOffset == f.ByteOffset && t.Kind != "union" { |
| | |
| | |
| | fixups.recordArrayType(lastFieldType) |
| | } |
| | lastFieldType = &f.Type |
| | lastFieldByteOffset = f.ByteOffset |
| | lastFieldBitSize = f.BitSize |
| | } |
| | if t.Kind != "union" { |
| | b, ok := e.Val(AttrByteSize).(int64) |
| | if ok && b == lastFieldByteOffset { |
| | |
| | fixups.recordArrayType(lastFieldType) |
| | } |
| | } |
| |
|
| | case TagConstType, TagVolatileType, TagRestrictType: |
| | |
| | |
| | |
| | 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: |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | 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: |
| | |
| | |
| | |
| | |
| | t := new(PtrType) |
| | typ = t |
| | typeCache[off] = t |
| | if e.Val(AttrType) == nil { |
| | t.Type = &VoidType{} |
| | break |
| | } |
| | t.Type = typeOf(e) |
| |
|
| | case TagSubroutineType: |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | 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: |
| | |
| | |
| | |
| | |
| | t := new(TypedefType) |
| | typ = t |
| | typeCache[off] = t |
| | t.Name, _ = e.Val(AttrName).(string) |
| | t.Type = typeOf(e) |
| |
|
| | case TagUnspecifiedType: |
| | |
| | |
| | |
| | t := new(UnspecifiedType) |
| | typ = t |
| | typeCache[off] = t |
| | t.Name, _ = e.Val(AttrName).(string) |
| |
|
| | default: |
| | |
| | |
| | |
| | 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: |
| | |
| | |
| | |
| | fixups.typedefs = append(fixups.typedefs, t) |
| | case *PtrType: |
| | b = int64(addressSize) |
| | } |
| | } |
| | typ.Common().ByteSize = b |
| | } |
| | return typ, nil |
| |
|
| | Error: |
| | |
| | |
| | |
| | delete(typeCache, off) |
| | return nil, err |
| | } |
| |
|
| | func zeroArray(t *Type) { |
| | at := (*t).(*ArrayType) |
| | if at.Type.Size() == 0 { |
| | return |
| | } |
| | |
| | tt := *at |
| | tt.Count = 0 |
| | *t = &tt |
| | } |
| |
|