| /* Convert types from GDB to GCC |
| |
| Copyright (C) 2014-2016 Free Software Foundation, Inc. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| |
| #include "defs.h" |
| #include "gdbtypes.h" |
| #include "compile-internal.h" |
| /* An object that maps a gdb type to a gcc type. */ |
| |
| struct type_map_instance |
| { |
| /* The gdb type. */ |
| |
| struct type *type; |
| |
| /* The corresponding gcc type handle. */ |
| |
| gcc_type gcc_type_handle; |
| }; |
| |
| /* Hash a type_map_instance. */ |
| |
| static hashval_t |
| hash_type_map_instance (const void *p) |
| { |
| const struct type_map_instance *inst = (const struct type_map_instance *) p; |
| |
| return htab_hash_pointer (inst->type); |
| } |
| |
| /* Check two type_map_instance objects for equality. */ |
| |
| static int |
| eq_type_map_instance (const void *a, const void *b) |
| { |
| const struct type_map_instance *insta = (const struct type_map_instance *) a; |
| const struct type_map_instance *instb = (const struct type_map_instance *) b; |
| |
| return insta->type == instb->type; |
| } |
| |
| |
| |
| /* Insert an entry into the type map associated with CONTEXT that maps |
| from the gdb type TYPE to the gcc type GCC_TYPE. It is ok for a |
| given type to be inserted more than once, provided that the exact |
| same association is made each time. This simplifies how type |
| caching works elsewhere in this file -- see how struct type caching |
| is handled. */ |
| |
| static void |
| insert_type (struct compile_c_instance *context, struct type *type, |
| gcc_type gcc_type) |
| { |
| struct type_map_instance inst, *add; |
| void **slot; |
| |
| inst.type = type; |
| inst.gcc_type_handle = gcc_type; |
| slot = htab_find_slot (context->type_map, &inst, INSERT); |
| |
| add = (struct type_map_instance *) *slot; |
| /* The type might have already been inserted in order to handle |
| recursive types. */ |
| if (add != NULL && add->gcc_type_handle != gcc_type) |
| error (_("Unexpected type id from GCC, check you use recent enough GCC.")); |
| |
| if (add == NULL) |
| { |
| add = XNEW (struct type_map_instance); |
| *add = inst; |
| *slot = add; |
| } |
| } |
| |
| /* Convert a pointer type to its gcc representation. */ |
| |
| static gcc_type |
| convert_pointer (struct compile_c_instance *context, struct type *type) |
| { |
| gcc_type target = convert_type (context, TYPE_TARGET_TYPE (type)); |
| |
| return C_CTX (context)->c_ops->build_pointer_type (C_CTX (context), |
| target); |
| } |
| |
| /* Convert an array type to its gcc representation. */ |
| |
| static gcc_type |
| convert_array (struct compile_c_instance *context, struct type *type) |
| { |
| gcc_type element_type; |
| struct type *range = TYPE_INDEX_TYPE (type); |
| |
| element_type = convert_type (context, TYPE_TARGET_TYPE (type)); |
| |
| if (TYPE_LOW_BOUND_KIND (range) != PROP_CONST) |
| return C_CTX (context)->c_ops->error (C_CTX (context), |
| _("array type with non-constant" |
| " lower bound is not supported")); |
| if (TYPE_LOW_BOUND (range) != 0) |
| return C_CTX (context)->c_ops->error (C_CTX (context), |
| _("cannot convert array type with " |
| "non-zero lower bound to C")); |
| |
| if (TYPE_HIGH_BOUND_KIND (range) == PROP_LOCEXPR |
| || TYPE_HIGH_BOUND_KIND (range) == PROP_LOCLIST) |
| { |
| gcc_type result; |
| char *upper_bound; |
| |
| if (TYPE_VECTOR (type)) |
| return C_CTX (context)->c_ops->error (C_CTX (context), |
| _("variably-sized vector type" |
| " is not supported")); |
| |
| upper_bound = c_get_range_decl_name (&TYPE_RANGE_DATA (range)->high); |
| result = C_CTX (context)->c_ops->build_vla_array_type (C_CTX (context), |
| element_type, |
| upper_bound); |
| xfree (upper_bound); |
| return result; |
| } |
| else |
| { |
| LONGEST low_bound, high_bound, count; |
| |
| if (get_array_bounds (type, &low_bound, &high_bound) == 0) |
| count = -1; |
| else |
| { |
| gdb_assert (low_bound == 0); /* Ensured above. */ |
| count = high_bound + 1; |
| } |
| |
| if (TYPE_VECTOR (type)) |
| return C_CTX (context)->c_ops->build_vector_type (C_CTX (context), |
| element_type, |
| count); |
| return C_CTX (context)->c_ops->build_array_type (C_CTX (context), |
| element_type, count); |
| } |
| } |
| |
| /* Convert a struct or union type to its gcc representation. */ |
| |
| static gcc_type |
| convert_struct_or_union (struct compile_c_instance *context, struct type *type) |
| { |
| int i; |
| gcc_type result; |
| |
| /* First we create the resulting type and enter it into our hash |
| table. This lets recursive types work. */ |
| if (TYPE_CODE (type) == TYPE_CODE_STRUCT) |
| result = C_CTX (context)->c_ops->build_record_type (C_CTX (context)); |
| else |
| { |
| gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION); |
| result = C_CTX (context)->c_ops->build_union_type (C_CTX (context)); |
| } |
| insert_type (context, type, result); |
| |
| for (i = 0; i < TYPE_NFIELDS (type); ++i) |
| { |
| gcc_type field_type; |
| unsigned long bitsize = TYPE_FIELD_BITSIZE (type, i); |
| |
| field_type = convert_type (context, TYPE_FIELD_TYPE (type, i)); |
| if (bitsize == 0) |
| bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, i)); |
| C_CTX (context)->c_ops->build_add_field (C_CTX (context), result, |
| TYPE_FIELD_NAME (type, i), |
| field_type, |
| bitsize, |
| TYPE_FIELD_BITPOS (type, i)); |
| } |
| |
| C_CTX (context)->c_ops->finish_record_or_union (C_CTX (context), result, |
| TYPE_LENGTH (type)); |
| return result; |
| } |
| |
| /* Convert an enum type to its gcc representation. */ |
| |
| static gcc_type |
| convert_enum (struct compile_c_instance *context, struct type *type) |
| { |
| gcc_type int_type, result; |
| int i; |
| struct gcc_c_context *ctx = C_CTX (context); |
| |
| int_type = ctx->c_ops->int_type (ctx, |
| TYPE_UNSIGNED (type), |
| TYPE_LENGTH (type)); |
| |
| result = ctx->c_ops->build_enum_type (ctx, int_type); |
| for (i = 0; i < TYPE_NFIELDS (type); ++i) |
| { |
| ctx->c_ops->build_add_enum_constant (ctx, |
| result, |
| TYPE_FIELD_NAME (type, i), |
| TYPE_FIELD_ENUMVAL (type, i)); |
| } |
| |
| ctx->c_ops->finish_enum_type (ctx, result); |
| |
| return result; |
| } |
| |
| /* Convert a function type to its gcc representation. */ |
| |
| static gcc_type |
| convert_func (struct compile_c_instance *context, struct type *type) |
| { |
| int i; |
| gcc_type result, return_type; |
| struct gcc_type_array array; |
| int is_varargs = TYPE_VARARGS (type) || !TYPE_PROTOTYPED (type); |
| |
| /* This approach means we can't make self-referential function |
| types. Those are impossible in C, though. */ |
| return_type = convert_type (context, TYPE_TARGET_TYPE (type)); |
| |
| array.n_elements = TYPE_NFIELDS (type); |
| array.elements = XNEWVEC (gcc_type, TYPE_NFIELDS (type)); |
| for (i = 0; i < TYPE_NFIELDS (type); ++i) |
| array.elements[i] = convert_type (context, TYPE_FIELD_TYPE (type, i)); |
| |
| result = C_CTX (context)->c_ops->build_function_type (C_CTX (context), |
| return_type, |
| &array, is_varargs); |
| xfree (array.elements); |
| |
| return result; |
| } |
| |
| /* Convert an integer type to its gcc representation. */ |
| |
| static gcc_type |
| convert_int (struct compile_c_instance *context, struct type *type) |
| { |
| return C_CTX (context)->c_ops->int_type (C_CTX (context), |
| TYPE_UNSIGNED (type), |
| TYPE_LENGTH (type)); |
| } |
| |
| /* Convert a floating-point type to its gcc representation. */ |
| |
| static gcc_type |
| convert_float (struct compile_c_instance *context, struct type *type) |
| { |
| return C_CTX (context)->c_ops->float_type (C_CTX (context), |
| TYPE_LENGTH (type)); |
| } |
| |
| /* Convert the 'void' type to its gcc representation. */ |
| |
| static gcc_type |
| convert_void (struct compile_c_instance *context, struct type *type) |
| { |
| return C_CTX (context)->c_ops->void_type (C_CTX (context)); |
| } |
| |
| /* Convert a boolean type to its gcc representation. */ |
| |
| static gcc_type |
| convert_bool (struct compile_c_instance *context, struct type *type) |
| { |
| return C_CTX (context)->c_ops->bool_type (C_CTX (context)); |
| } |
| |
| /* Convert a qualified type to its gcc representation. */ |
| |
| static gcc_type |
| convert_qualified (struct compile_c_instance *context, struct type *type) |
| { |
| struct type *unqual = make_unqualified_type (type); |
| gcc_type unqual_converted; |
| gcc_qualifiers_flags quals = 0; |
| |
| unqual_converted = convert_type (context, unqual); |
| |
| if (TYPE_CONST (type)) |
| quals |= GCC_QUALIFIER_CONST; |
| if (TYPE_VOLATILE (type)) |
| quals |= GCC_QUALIFIER_VOLATILE; |
| if (TYPE_RESTRICT (type)) |
| quals |= GCC_QUALIFIER_RESTRICT; |
| |
| return C_CTX (context)->c_ops->build_qualified_type (C_CTX (context), |
| unqual_converted, |
| quals); |
| } |
| |
| /* Convert a complex type to its gcc representation. */ |
| |
| static gcc_type |
| convert_complex (struct compile_c_instance *context, struct type *type) |
| { |
| gcc_type base = convert_type (context, TYPE_TARGET_TYPE (type)); |
| |
| return C_CTX (context)->c_ops->build_complex_type (C_CTX (context), base); |
| } |
| |
| /* A helper function which knows how to convert most types from their |
| gdb representation to the corresponding gcc form. This examines |
| the TYPE and dispatches to the appropriate conversion function. It |
| returns the gcc type. */ |
| |
| static gcc_type |
| convert_type_basic (struct compile_c_instance *context, struct type *type) |
| { |
| /* If we are converting a qualified type, first convert the |
| unqualified type and then apply the qualifiers. */ |
| if ((TYPE_INSTANCE_FLAGS (type) & (TYPE_INSTANCE_FLAG_CONST |
| | TYPE_INSTANCE_FLAG_VOLATILE |
| | TYPE_INSTANCE_FLAG_RESTRICT)) != 0) |
| return convert_qualified (context, type); |
| |
| switch (TYPE_CODE (type)) |
| { |
| case TYPE_CODE_PTR: |
| return convert_pointer (context, type); |
| |
| case TYPE_CODE_ARRAY: |
| return convert_array (context, type); |
| |
| case TYPE_CODE_STRUCT: |
| case TYPE_CODE_UNION: |
| return convert_struct_or_union (context, type); |
| |
| case TYPE_CODE_ENUM: |
| return convert_enum (context, type); |
| |
| case TYPE_CODE_FUNC: |
| return convert_func (context, type); |
| |
| case TYPE_CODE_INT: |
| return convert_int (context, type); |
| |
| case TYPE_CODE_FLT: |
| return convert_float (context, type); |
| |
| case TYPE_CODE_VOID: |
| return convert_void (context, type); |
| |
| case TYPE_CODE_BOOL: |
| return convert_bool (context, type); |
| |
| case TYPE_CODE_COMPLEX: |
| return convert_complex (context, type); |
| } |
| |
| return C_CTX (context)->c_ops->error (C_CTX (context), |
| _("cannot convert gdb type " |
| "to gcc type")); |
| } |
| |
| /* See compile-internal.h. */ |
| |
| gcc_type |
| convert_type (struct compile_c_instance *context, struct type *type) |
| { |
| struct type_map_instance inst, *found; |
| gcc_type result; |
| |
| /* We don't ever have to deal with typedefs in this code, because |
| those are only needed as symbols by the C compiler. */ |
| type = check_typedef (type); |
| |
| inst.type = type; |
| found = (struct type_map_instance *) htab_find (context->type_map, &inst); |
| if (found != NULL) |
| return found->gcc_type_handle; |
| |
| result = convert_type_basic (context, type); |
| insert_type (context, type, result); |
| return result; |
| } |
| |
| |
| |
| /* Delete the compiler instance C. */ |
| |
| static void |
| delete_instance (struct compile_instance *c) |
| { |
| struct compile_c_instance *context = (struct compile_c_instance *) c; |
| |
| context->base.fe->ops->destroy (context->base.fe); |
| htab_delete (context->type_map); |
| if (context->symbol_err_map != NULL) |
| htab_delete (context->symbol_err_map); |
| xfree (context); |
| } |
| |
| /* See compile-internal.h. */ |
| |
| struct compile_instance * |
| new_compile_instance (struct gcc_c_context *fe) |
| { |
| struct compile_c_instance *result = XCNEW (struct compile_c_instance); |
| |
| result->base.fe = &fe->base; |
| result->base.destroy = delete_instance; |
| result->base.gcc_target_options = ("-std=gnu11" |
| /* Otherwise the .o file may need |
| "_Unwind_Resume" and |
| "__gcc_personality_v0". */ |
| " -fno-exceptions"); |
| |
| result->type_map = htab_create_alloc (10, hash_type_map_instance, |
| eq_type_map_instance, |
| xfree, xcalloc, xfree); |
| |
| fe->c_ops->set_callbacks (fe, gcc_convert_symbol, |
| gcc_symbol_address, result); |
| |
| return &result->base; |
| } |