// 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) *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, 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 { 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 }