func newVariable(name string, addr uintptr, dwarfType dwarf.Type, thread *Thread) (*Variable, error) { v := &Variable{ Name: name, Addr: addr, dwarfType: dwarfType, thread: thread, Type: dwarfType.String(), } switch t := dwarfType.(type) { case *dwarf.StructType: if strings.HasPrefix(t.StructName, "[]") { err := v.loadSliceInfo(t) if err != nil { return nil, err } } case *dwarf.ArrayType: v.base = v.Addr v.Len = t.Count v.Cap = -1 v.fieldType = t.Type v.stride = 0 if t.Count > 0 { v.stride = t.ByteSize / t.Count } } return v, nil }
func (thread *Thread) readSlice(addr uintptr, t *dwarf.StructType) (string, error) { var sliceLen, sliceCap int64 var arrayAddr uintptr var arrayType dwarf.Type for _, f := range t.Field { switch f.Name { case "array": val, err := thread.readMemory(addr+uintptr(f.ByteOffset), thread.dbp.arch.PtrSize()) if err != nil { return "", err } arrayAddr = uintptr(binary.LittleEndian.Uint64(val)) // Dereference array type to get value type ptrType, ok := f.Type.(*dwarf.PtrType) if !ok { return "", fmt.Errorf("Invalid type %s in slice array", f.Type) } arrayType = ptrType.Type case "len": lstr, err := thread.extractValue(nil, int64(addr+uintptr(f.ByteOffset)), f.Type, true) if err != nil { return "", err } sliceLen, err = strconv.ParseInt(lstr, 10, 64) if err != nil { return "", err } case "cap": cstr, err := thread.extractValue(nil, int64(addr+uintptr(f.ByteOffset)), f.Type, true) if err != nil { return "", err } sliceCap, err = strconv.ParseInt(cstr, 10, 64) if err != nil { return "", err } } } stride := arrayType.Size() if _, ok := arrayType.(*dwarf.PtrType); ok { stride = int64(thread.dbp.arch.PtrSize()) } vals, err := thread.readArrayValues(arrayAddr, sliceLen, stride, arrayType) if err != nil { return "", err } return fmt.Sprintf("[]%s len: %d, cap: %d, [%s]", arrayType, sliceLen, sliceCap, strings.Join(vals, ",")), nil }
// Type returns a *Type with the same memory layout as // dtype when used as the type of a variable or a struct field. func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { if t, ok := c.m[dtype]; ok { if t.Go == nil { fatalf("%s: type conversion loop at %s", lineno(pos), dtype) } return t } t := new(Type) t.Size = dtype.Size() // note: wrong for array of pointers, corrected below t.Align = -1 t.C = &TypeRepr{Repr: dtype.Common().Name} c.m[dtype] = t switch dt := dtype.(type) { default: fatalf("%s: unexpected type: %s", lineno(pos), dtype) case *dwarf.AddrType: if t.Size != c.ptrSize { fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype) } t.Go = c.uintptr t.Align = t.Size case *dwarf.ArrayType: if dt.StrideBitSize > 0 { // Cannot represent bit-sized elements in Go. t.Go = c.Opaque(t.Size) break } count := dt.Count if count == -1 { // Indicates flexible array member, which Go doesn't support. // Translate to zero-length array instead. count = 0 } sub := c.Type(dt.Type, pos) t.Align = sub.Align t.Go = &ast.ArrayType{ Len: c.intExpr(count), Elt: sub.Go, } // Recalculate t.Size now that we know sub.Size. t.Size = count * sub.Size t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count) case *dwarf.BoolType: t.Go = c.bool t.Align = 1 case *dwarf.CharType: if t.Size != 1 { fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype) } t.Go = c.int8 t.Align = 1 case *dwarf.EnumType: if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } t.C.Set("enum " + dt.EnumName) signed := 0 t.EnumValues = make(map[string]int64) for _, ev := range dt.Val { t.EnumValues[ev.Name] = ev.Val if ev.Val < 0 { signed = signedDelta } } switch t.Size + int64(signed) { default: fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype) case 1: t.Go = c.uint8 case 2: t.Go = c.uint16 case 4: t.Go = c.uint32 case 8: t.Go = c.uint64 case 1 + signedDelta: t.Go = c.int8 case 2 + signedDelta: t.Go = c.int16 case 4 + signedDelta: t.Go = c.int32 case 8 + signedDelta: t.Go = c.int64 } case *dwarf.FloatType: switch t.Size { default: fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype) case 4: t.Go = c.float32 case 8: t.Go = c.float64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.ComplexType: switch t.Size { default: fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype) case 8: t.Go = c.complex64 case 16: t.Go = c.complex128 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.FuncType: // No attempt at translation: would enable calls // directly between worlds, but we need to moderate those. t.Go = c.uintptr t.Align = c.ptrSize case *dwarf.IntType: if dt.BitSize > 0 { fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype) } switch t.Size { default: fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype) case 1: t.Go = c.int8 case 2: t.Go = c.int16 case 4: t.Go = c.int32 case 8: t.Go = c.int64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.PtrType: // Clang doesn't emit DW_AT_byte_size for pointer types. if t.Size != c.ptrSize && t.Size != -1 { fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype) } t.Size = c.ptrSize t.Align = c.ptrSize if _, ok := base(dt.Type).(*dwarf.VoidType); ok { t.Go = c.goVoidPtr t.C.Set("void*") break } // Placeholder initialization; completed in FinishType. t.Go = &ast.StarExpr{} t.C.Set("<incomplete>*") if _, ok := c.ptrs[dt.Type]; !ok { c.ptrKeys = append(c.ptrKeys, dt.Type) } c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t) case *dwarf.QualType: // Ignore qualifier. t = c.Type(dt.Type, pos) c.m[dtype] = t return t case *dwarf.StructType: // Convert to Go struct, being careful about alignment. // Have to give it a name to simulate C "struct foo" references. tag := dt.StructName if dt.ByteSize < 0 && tag == "" { // opaque unnamed struct - should not be possible break } if tag == "" { tag = "__" + strconv.Itoa(tagGen) tagGen++ } else if t.C.Empty() { t.C.Set(dt.Kind + " " + tag) } name := c.Ident("_Ctype_" + dt.Kind + "_" + tag) t.Go = name // publish before recursive calls goIdent[name.Name] = name if dt.ByteSize < 0 { // Size calculation in c.Struct/c.Opaque will die with size=-1 (unknown), // so execute the basic things that the struct case would do // other than try to determine a Go representation. tt := *t tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}} tt.Go = c.Ident("struct{}") typedef[name.Name] = &tt break } switch dt.Kind { case "class", "union": t.Go = c.Opaque(t.Size) if t.C.Empty() { t.C.Set("__typeof__(unsigned char[%d])", t.Size) } t.Align = 1 // TODO: should probably base this on field alignment. typedef[name.Name] = t case "struct": g, csyntax, align := c.Struct(dt, pos) if t.C.Empty() { t.C.Set(csyntax) } t.Align = align tt := *t if tag != "" { tt.C = &TypeRepr{"struct %s", []interface{}{tag}} } tt.Go = g typedef[name.Name] = &tt } case *dwarf.TypedefType: // Record typedef for printing. if dt.Name == "_GoString_" { // Special C name for Go string type. // Knows string layout used by compilers: pointer plus length, // which rounds up to 2 pointers after alignment. t.Go = c.string t.Size = c.ptrSize * 2 t.Align = c.ptrSize break } if dt.Name == "_GoBytes_" { // Special C name for Go []byte type. // Knows slice layout used by compilers: pointer, length, cap. t.Go = c.Ident("[]byte") t.Size = c.ptrSize + 4 + 4 t.Align = c.ptrSize break } name := c.Ident("_Ctype_" + dt.Name) goIdent[name.Name] = name sub := c.Type(dt.Type, pos) t.Go = name t.Size = sub.Size t.Align = sub.Align oldType := typedef[name.Name] if oldType == nil { tt := *t tt.Go = sub.Go typedef[name.Name] = &tt } // If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo", // use that as the Go form for this typedef too, so that the typedef will be interchangeable // with the base type. // In -godefs mode, do this for all typedefs. if isStructUnionClass(sub.Go) || *godefs { t.Go = sub.Go if isStructUnionClass(sub.Go) { // Use the typedef name for C code. typedef[sub.Go.(*ast.Ident).Name].C = t.C } // If we've seen this typedef before, and it // was an anonymous struct/union/class before // too, use the old definition. // TODO: it would be safer to only do this if // we verify that the types are the same. if oldType != nil && isStructUnionClass(oldType.Go) { t.Go = oldType.Go } } case *dwarf.UcharType: if t.Size != 1 { fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype) } t.Go = c.uint8 t.Align = 1 case *dwarf.UintType: if dt.BitSize > 0 { fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype) } switch t.Size { default: fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype) case 1: t.Go = c.uint8 case 2: t.Go = c.uint16 case 4: t.Go = c.uint32 case 8: t.Go = c.uint64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.VoidType: t.Go = c.goVoid t.C.Set("void") t.Align = 1 } switch dtype.(type) { case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType: s := dtype.Common().Name if s != "" { if ss, ok := dwarfToName[s]; ok { s = ss } s = strings.Join(strings.Split(s, " "), "") // strip spaces name := c.Ident("_Ctype_" + s) tt := *t typedef[name.Name] = &tt if !*godefs { t.Go = name } } } if t.Size < 0 { // Unsized types are [0]byte, unless they're typedefs of other types // or structs with tags. // if so, use the name we've already defined. t.Size = 0 switch dt := dtype.(type) { case *dwarf.TypedefType: // ok case *dwarf.StructType: if dt.StructName != "" { break } t.Go = c.Opaque(0) default: t.Go = c.Opaque(0) } if t.C.Empty() { t.C.Set("void") } } if t.C.Empty() { fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype) } return t }
// Type returns a *Type with the same memory layout as // dtype when used as the type of a variable or a struct field. func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { if t, ok := c.m[dtype]; ok { if t.Go == nil { fatalf("%s: type conversion loop at %s", lineno(pos), dtype) } return t } // clang won't generate DW_AT_byte_size for pointer types, // so we have to fix it here. if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 { dt.ByteSize = c.ptrSize } t := new(Type) t.Size = dtype.Size() // note: wrong for array of pointers, corrected below t.Align = -1 t.C = &TypeRepr{Repr: dtype.Common().Name} c.m[dtype] = t switch dt := dtype.(type) { default: fatalf("%s: unexpected type: %s", lineno(pos), dtype) case *dwarf.AddrType: if t.Size != c.ptrSize { fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype) } t.Go = c.uintptr t.Align = t.Size case *dwarf.ArrayType: if dt.StrideBitSize > 0 { // Cannot represent bit-sized elements in Go. t.Go = c.Opaque(t.Size) break } gt := &ast.ArrayType{ Len: c.intExpr(dt.Count), } t.Go = gt // publish before recursive call sub := c.Type(dt.Type, pos) t.Align = sub.Align gt.Elt = sub.Go t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count) case *dwarf.BoolType: t.Go = c.bool t.Align = 1 case *dwarf.CharType: if t.Size != 1 { fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype) } t.Go = c.int8 t.Align = 1 case *dwarf.EnumType: if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } t.C.Set("enum " + dt.EnumName) signed := 0 t.EnumValues = make(map[string]int64) for _, ev := range dt.Val { t.EnumValues[ev.Name] = ev.Val if ev.Val < 0 { signed = signedDelta } } switch t.Size + int64(signed) { default: fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype) case 1: t.Go = c.uint8 case 2: t.Go = c.uint16 case 4: t.Go = c.uint32 case 8: t.Go = c.uint64 case 1 + signedDelta: t.Go = c.int8 case 2 + signedDelta: t.Go = c.int16 case 4 + signedDelta: t.Go = c.int32 case 8 + signedDelta: t.Go = c.int64 } case *dwarf.FloatType: switch t.Size { default: fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype) case 4: t.Go = c.float32 case 8: t.Go = c.float64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.ComplexType: switch t.Size { default: fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype) case 8: t.Go = c.complex64 case 16: t.Go = c.complex128 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.FuncType: // No attempt at translation: would enable calls // directly between worlds, but we need to moderate those. t.Go = c.uintptr t.Align = c.ptrSize case *dwarf.IntType: if dt.BitSize > 0 { fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype) } switch t.Size { default: fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype) case 1: t.Go = c.int8 case 2: t.Go = c.int16 case 4: t.Go = c.int32 case 8: t.Go = c.int64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.PtrType: t.Align = c.ptrSize // Translate void* as unsafe.Pointer if _, ok := base(dt.Type).(*dwarf.VoidType); ok { t.Go = c.unsafePointer t.C.Set("void*") break } gt := &ast.StarExpr{} t.Go = gt // publish before recursive call sub := c.Type(dt.Type, pos) gt.X = sub.Go t.C.Set("%s*", sub.C) case *dwarf.QualType: // Ignore qualifier. t = c.Type(dt.Type, pos) c.m[dtype] = t return t case *dwarf.StructType: if dt.ByteSize < 0 { // opaque struct break } // Convert to Go struct, being careful about alignment. // Have to give it a name to simulate C "struct foo" references. tag := dt.StructName if tag == "" { tag = "__" + strconv.Itoa(tagGen) tagGen++ } else if t.C.Empty() { t.C.Set(dt.Kind + " " + tag) } name := c.Ident("_Ctype_" + dt.Kind + "_" + tag) t.Go = name // publish before recursive calls goIdent[name.Name] = name switch dt.Kind { case "class", "union": t.Go = c.Opaque(t.Size) if t.C.Empty() { t.C.Set("__typeof__(unsigned char[%d])", t.Size) } t.Align = 1 // TODO: should probably base this on field alignment. typedef[name.Name] = t case "struct": g, csyntax, align := c.Struct(dt, pos) if t.C.Empty() { t.C.Set(csyntax) } t.Align = align tt := *t if tag != "" { tt.C = &TypeRepr{"struct %s", []interface{}{tag}} } tt.Go = g typedef[name.Name] = &tt } case *dwarf.TypedefType: // Record typedef for printing. if dt.Name == "_GoString_" { // Special C name for Go string type. // Knows string layout used by compilers: pointer plus length, // which rounds up to 2 pointers after alignment. t.Go = c.string t.Size = c.ptrSize * 2 t.Align = c.ptrSize break } if dt.Name == "_GoBytes_" { // Special C name for Go []byte type. // Knows slice layout used by compilers: pointer, length, cap. t.Go = c.Ident("[]byte") t.Size = c.ptrSize + 4 + 4 t.Align = c.ptrSize break } name := c.Ident("_Ctype_" + dt.Name) goIdent[name.Name] = name t.Go = name // publish before recursive call sub := c.Type(dt.Type, pos) t.Size = sub.Size t.Align = sub.Align if _, ok := typedef[name.Name]; !ok { tt := *t tt.Go = sub.Go typedef[name.Name] = &tt } if *godefs || *cdefs { t.Go = sub.Go } case *dwarf.UcharType: if t.Size != 1 { fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype) } t.Go = c.uint8 t.Align = 1 case *dwarf.UintType: if dt.BitSize > 0 { fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype) } switch t.Size { default: fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype) case 1: t.Go = c.uint8 case 2: t.Go = c.uint16 case 4: t.Go = c.uint32 case 8: t.Go = c.uint64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.VoidType: t.Go = c.goVoid t.C.Set("void") t.Align = 1 } switch dtype.(type) { case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType: s := dtype.Common().Name if s != "" { if ss, ok := dwarfToName[s]; ok { s = ss } s = strings.Join(strings.Split(s, " "), "") // strip spaces name := c.Ident("_Ctype_" + s) tt := *t typedef[name.Name] = &tt if !*godefs && !*cdefs { t.Go = name } } } if t.Size <= 0 { // Clang does not record the size of a pointer in its DWARF entry, // so if dtype is an array, the call to dtype.Size at the top of the function // computed the size as the array length * 0 = 0. // The type switch called Type (this function) recursively on the pointer // entry, and the code near the top of the function updated the size to // be correct, so calling dtype.Size again will produce the correct value. t.Size = dtype.Size() if t.Size < 0 { // Unsized types are [0]byte, unless they're typedefs of other types. // if so, use the name of the typedef for the go name. t.Size = 0 if _, ok := dtype.(*dwarf.TypedefType); !ok { t.Go = c.Opaque(0) } if t.C.Empty() { t.C.Set("void") } return t } } if t.C.Empty() { fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype) } return t }
// Type returns a *Type with the same memory layout as // dtype when used as the type of a variable or a struct field. func (c *typeConv) Type(dtype dwarf.Type) *Type { if t, ok := c.m[dtype]; ok { if t.Go == nil { fatalf("type conversion loop at %s", dtype) } return t } t := new(Type) t.Size = dtype.Size() t.Align = -1 t.C = &TypeRepr{Repr: dtype.Common().Name} c.m[dtype] = t if t.Size < 0 { // Unsized types are [0]byte t.Size = 0 t.Go = c.Opaque(0) if t.C.Empty() { t.C.Set("void") } return t } switch dt := dtype.(type) { default: fatalf("unexpected type: %s", dtype) case *dwarf.AddrType: if t.Size != c.ptrSize { fatalf("unexpected: %d-byte address type - %s", t.Size, dtype) } t.Go = c.uintptr t.Align = t.Size case *dwarf.ArrayType: if dt.StrideBitSize > 0 { // Cannot represent bit-sized elements in Go. t.Go = c.Opaque(t.Size) break } gt := &ast.ArrayType{ Len: c.intExpr(dt.Count), } t.Go = gt // publish before recursive call sub := c.Type(dt.Type) t.Align = sub.Align gt.Elt = sub.Go t.C.Set("typeof(%s[%d])", sub.C, dt.Count) case *dwarf.BoolType: t.Go = c.bool t.Align = c.ptrSize case *dwarf.CharType: if t.Size != 1 { fatalf("unexpected: %d-byte char type - %s", t.Size, dtype) } t.Go = c.int8 t.Align = 1 case *dwarf.EnumType: if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } t.C.Set("enum " + dt.EnumName) signed := 0 t.EnumValues = make(map[string]int64) for _, ev := range dt.Val { t.EnumValues[ev.Name] = ev.Val if ev.Val < 0 { signed = signedDelta } } switch t.Size + int64(signed) { default: fatalf("unexpected: %d-byte enum type - %s", t.Size, dtype) case 1: t.Go = c.uint8 case 2: t.Go = c.uint16 case 4: t.Go = c.uint32 case 8: t.Go = c.uint64 case 1 + signedDelta: t.Go = c.int8 case 2 + signedDelta: t.Go = c.int16 case 4 + signedDelta: t.Go = c.int32 case 8 + signedDelta: t.Go = c.int64 } case *dwarf.FloatType: switch t.Size { default: fatalf("unexpected: %d-byte float type - %s", t.Size, dtype) case 4: t.Go = c.float32 case 8: t.Go = c.float64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.ComplexType: switch t.Size { default: fatalf("unexpected: %d-byte complex type - %s", t.Size, dtype) case 8: t.Go = c.complex64 case 16: t.Go = c.complex128 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.FuncType: // No attempt at translation: would enable calls // directly between worlds, but we need to moderate those. t.Go = c.uintptr t.Align = c.ptrSize case *dwarf.IntType: if dt.BitSize > 0 { fatalf("unexpected: %d-bit int type - %s", dt.BitSize, dtype) } switch t.Size { default: fatalf("unexpected: %d-byte int type - %s", t.Size, dtype) case 1: t.Go = c.int8 case 2: t.Go = c.int16 case 4: t.Go = c.int32 case 8: t.Go = c.int64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.PtrType: t.Align = c.ptrSize // Translate void* as unsafe.Pointer if _, ok := base(dt.Type).(*dwarf.VoidType); ok { t.Go = c.unsafePointer t.C.Set("void*") break } gt := &ast.StarExpr{} t.Go = gt // publish before recursive call sub := c.Type(dt.Type) gt.X = sub.Go t.C.Set("%s*", sub.C) case *dwarf.QualType: // Ignore qualifier. t = c.Type(dt.Type) c.m[dtype] = t return t case *dwarf.StructType: // Convert to Go struct, being careful about alignment. // Have to give it a name to simulate C "struct foo" references. tag := dt.StructName if tag == "" { tag = "__" + strconv.Itoa(tagGen) tagGen++ } else if t.C.Empty() { t.C.Set(dt.Kind + " " + tag) } name := c.Ident("_Ctype_" + dt.Kind + "_" + tag) t.Go = name // publish before recursive calls switch dt.Kind { case "union", "class": typedef[name.Name] = c.Opaque(t.Size) if t.C.Empty() { t.C.Set("typeof(unsigned char[%d])", t.Size) } case "struct": g, csyntax, align := c.Struct(dt) if t.C.Empty() { t.C.Set(csyntax) } t.Align = align typedef[name.Name] = g } case *dwarf.TypedefType: // Record typedef for printing. if dt.Name == "_GoString_" { // Special C name for Go string type. // Knows string layout used by compilers: pointer plus length, // which rounds up to 2 pointers after alignment. t.Go = c.string t.Size = c.ptrSize * 2 t.Align = c.ptrSize break } if dt.Name == "_GoBytes_" { // Special C name for Go []byte type. // Knows slice layout used by compilers: pointer, length, cap. t.Go = c.Ident("[]byte") t.Size = c.ptrSize + 4 + 4 t.Align = c.ptrSize break } name := c.Ident("_Ctypedef_" + dt.Name) t.Go = name // publish before recursive call sub := c.Type(dt.Type) t.Size = sub.Size t.Align = sub.Align if _, ok := typedef[name.Name]; !ok { typedef[name.Name] = sub.Go } case *dwarf.UcharType: if t.Size != 1 { fatalf("unexpected: %d-byte uchar type - %s", t.Size, dtype) } t.Go = c.uint8 t.Align = 1 case *dwarf.UintType: if dt.BitSize > 0 { fatalf("unexpected: %d-bit uint type - %s", dt.BitSize, dtype) } switch t.Size { default: fatalf("unexpected: %d-byte uint type - %s", t.Size, dtype) case 1: t.Go = c.uint8 case 2: t.Go = c.uint16 case 4: t.Go = c.uint32 case 8: t.Go = c.uint64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.VoidType: t.Go = c.void t.C.Set("void") } switch dtype.(type) { case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType: s := dtype.Common().Name if s != "" { if ss, ok := dwarfToName[s]; ok { s = ss } s = strings.Join(strings.Split(s, " "), "") // strip spaces name := c.Ident("_Ctype_" + s) typedef[name.Name] = t.Go t.Go = name } } if t.C.Empty() { fatalf("internal error: did not create C name for %s", dtype) } return t }
// Type returns a *Type with the same memory layout as // dtype when used as the type of a variable or a struct field. func (c *typeConv) Type(dtype dwarf.Type) *Type { if t, ok := c.m[dtype]; ok { if t.Go == nil { fatal("type conversion loop at %s", dtype) } return t } t := new(Type) t.Size = dtype.Size() t.Align = -1 t.C = dtype.Common().Name if t.Size < 0 { fatal("dwarf.Type %s reports unknown size", dtype) } c.m[dtype] = t switch dt := dtype.(type) { default: fatal("unexpected type: %s", dtype) case *dwarf.AddrType: if t.Size != c.ptrSize { fatal("unexpected: %d-byte address type - %s", t.Size, dtype) } t.Go = c.uintptr t.Align = t.Size case *dwarf.ArrayType: if dt.StrideBitSize > 0 { // Cannot represent bit-sized elements in Go. t.Go = c.Opaque(t.Size) break } gt := &ast.ArrayType{ Len: c.intExpr(dt.Count), } t.Go = gt // publish before recursive call sub := c.Type(dt.Type) t.Align = sub.Align gt.Elt = sub.Go t.C = fmt.Sprintf("typeof(%s[%d])", sub.C, dt.Count) case *dwarf.CharType: if t.Size != 1 { fatal("unexpected: %d-byte char type - %s", t.Size, dtype) } t.Go = c.int8 t.Align = 1 case *dwarf.EnumType: switch t.Size { default: fatal("unexpected: %d-byte enum type - %s", t.Size, dtype) case 1: t.Go = c.uint8 case 2: t.Go = c.uint16 case 4: t.Go = c.uint32 case 8: t.Go = c.uint64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } t.C = "enum " + dt.EnumName case *dwarf.FloatType: switch t.Size { default: fatal("unexpected: %d-byte float type - %s", t.Size, dtype) case 4: t.Go = c.float32 case 8: t.Go = c.float64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.FuncType: // No attempt at translation: would enable calls // directly between worlds, but we need to moderate those. t.Go = c.uintptr t.Align = c.ptrSize case *dwarf.IntType: if dt.BitSize > 0 { fatal("unexpected: %d-bit int type - %s", dt.BitSize, dtype) } switch t.Size { default: fatal("unexpected: %d-byte int type - %s", t.Size, dtype) case 1: t.Go = c.int8 case 2: t.Go = c.int16 case 4: t.Go = c.int32 case 8: t.Go = c.int64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.PtrType: t.Align = c.ptrSize // Translate void* as unsafe.Pointer if _, ok := base(dt.Type).(*dwarf.VoidType); ok { t.Go = c.unsafePointer t.C = "void*" break } gt := &ast.StarExpr{} t.Go = gt // publish before recursive call sub := c.Type(dt.Type) gt.X = sub.Go t.C = sub.C + "*" case *dwarf.QualType: // Ignore qualifier. t = c.Type(dt.Type) c.m[dtype] = t return t case *dwarf.StructType: // Convert to Go struct, being careful about alignment. // Have to give it a name to simulate C "struct foo" references. tag := dt.StructName if tag == "" { tag = "__" + strconv.Itoa(c.tagGen) c.tagGen++ } else if t.C == "" { t.C = dt.Kind + " " + tag } name := c.Ident("_C" + dt.Kind + "_" + tag) t.Go = name // publish before recursive calls switch dt.Kind { case "union", "class": c.typedef[name.Value] = c.Opaque(t.Size) if t.C == "" { t.C = fmt.Sprintf("typeof(unsigned char[%d])", t.Size) } case "struct": g, csyntax, align := c.Struct(dt) if t.C == "" { t.C = csyntax } t.Align = align c.typedef[name.Value] = g } case *dwarf.TypedefType: // Record typedef for printing. if dt.Name == "_GoString_" { // Special C name for Go string type. // Knows string layout used by compilers: pointer plus length, // which rounds up to 2 pointers after alignment. t.Go = c.string t.Size = c.ptrSize * 2 t.Align = c.ptrSize break } name := c.Ident("_C_" + dt.Name) t.Go = name // publish before recursive call sub := c.Type(dt.Type) t.Size = sub.Size t.Align = sub.Align if _, ok := c.typedef[name.Value]; !ok { c.typedef[name.Value] = sub.Go } case *dwarf.UcharType: if t.Size != 1 { fatal("unexpected: %d-byte uchar type - %s", t.Size, dtype) } t.Go = c.uint8 t.Align = 1 case *dwarf.UintType: if dt.BitSize > 0 { fatal("unexpected: %d-bit uint type - %s", dt.BitSize, dtype) } switch t.Size { default: fatal("unexpected: %d-byte uint type - %s", t.Size, dtype) case 1: t.Go = c.uint8 case 2: t.Go = c.uint16 case 4: t.Go = c.uint32 case 8: t.Go = c.uint64 } if t.Align = t.Size; t.Align >= c.ptrSize { t.Align = c.ptrSize } case *dwarf.VoidType: t.Go = c.void t.C = "void" } switch dtype.(type) { case *dwarf.AddrType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType: s := dtype.Common().Name if s != "" { if ss, ok := cnameMap[s]; ok { s = ss } s = strings.Join(strings.Split(s, " ", 0), "") // strip spaces name := c.Ident("_C_" + s) c.typedef[name.Value] = t.Go t.Go = name } } if t.C == "" { fatal("internal error: did not create C name for %s", dtype) } return t }
func (v *Variable) isType(typ dwarf.Type, kind reflect.Kind) error { if v.DwarfType != nil { if typ != nil && typ.String() != v.RealType.String() { return fmt.Errorf("can not convert value of type %s to %s", v.DwarfType.String(), typ.String()) } return nil } if typ == nil { return nil } if v == nilVariable { switch kind { case reflect.Slice, reflect.Map, reflect.Func, reflect.Ptr, reflect.Chan, reflect.Interface: return nil default: return fmt.Errorf("mismatched types nil and %s", typ.String()) } } converr := fmt.Errorf("can not convert %s constant to %s", v.Value, typ.String()) if v.Value == nil { return converr } switch t := typ.(type) { case *dwarf.IntType: if v.Value.Kind() != constant.Int { return converr } case *dwarf.UintType: if v.Value.Kind() != constant.Int { return converr } case *dwarf.FloatType: if (v.Value.Kind() != constant.Int) && (v.Value.Kind() != constant.Float) { return converr } case *dwarf.BoolType: if v.Value.Kind() != constant.Bool { return converr } case *dwarf.StructType: if t.StructName != "string" { return converr } if v.Value.Kind() != constant.String { return converr } case *dwarf.ComplexType: if v.Value.Kind() != constant.Complex && v.Value.Kind() != constant.Float && v.Value.Kind() != constant.Int { return converr } default: return converr } return nil }
// Eval type cast expressions func (scope *EvalScope) evalTypeCast(node *ast.CallExpr) (*Variable, error) { if len(node.Args) != 1 { return nil, fmt.Errorf("wrong number of arguments for a type cast") } argv, err := scope.evalAST(node.Args[0]) if err != nil { return nil, err } argv.loadValue() if argv.Unreadable != nil { return nil, argv.Unreadable } fnnode := node.Fun // remove all enclosing parenthesis from the type name for { p, ok := fnnode.(*ast.ParenExpr) if !ok { break } fnnode = p.X } var typ dwarf.Type if snode, ok := fnnode.(*ast.StarExpr); ok { // Pointer types only appear in the dwarf informations when // a pointer to the type is used in the target program, here // we create a pointer type on the fly so that the user can // specify a pointer to any variable used in the target program ptyp, err := scope.findType(exprToString(snode.X)) if err != nil { return nil, err } typ = &dwarf.PtrType{dwarf.CommonType{int64(scope.Thread.dbp.arch.PtrSize()), exprToString(fnnode)}, ptyp} } else { typ, err = scope.findType(exprToString(fnnode)) if err != nil { return nil, err } } // only supports cast of integer constants into pointers ptyp, isptrtyp := typ.(*dwarf.PtrType) if !isptrtyp { return nil, fmt.Errorf("can not convert \"%s\" to %s", exprToString(node.Args[0]), typ.String()) } switch argv.Kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: // ok case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: // ok default: return nil, fmt.Errorf("can not convert \"%s\" to %s", exprToString(node.Args[0]), typ.String()) } n, _ := constant.Int64Val(argv.Value) v := newVariable("", 0, ptyp, scope.Thread) v.Children = []Variable{*newVariable("", uintptr(n), ptyp.Type, scope.Thread)} return v, nil }