| /* Convert types from GDB to GCC |
| |
| Copyright (C) 2014-2021 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" |
| #include "compile-c.h" |
| #include "objfiles.h" |
| |
| /* Convert a pointer type to its gcc representation. */ |
| |
| static gcc_type |
| convert_pointer (compile_c_instance *context, struct type *type) |
| { |
| gcc_type target = context->convert_type (TYPE_TARGET_TYPE (type)); |
| |
| return context->plugin ().build_pointer_type (target); |
| } |
| |
| /* Convert an array type to its gcc representation. */ |
| |
| static gcc_type |
| convert_array (compile_c_instance *context, struct type *type) |
| { |
| gcc_type element_type; |
| struct type *range = type->index_type (); |
| |
| element_type = context->convert_type (TYPE_TARGET_TYPE (type)); |
| |
| if (range->bounds ()->low.kind () != PROP_CONST) |
| return context->plugin ().error (_("array type with non-constant" |
| " lower bound is not supported")); |
| if (range->bounds ()->low.const_val () != 0) |
| return context->plugin ().error (_("cannot convert array type with " |
| "non-zero lower bound to C")); |
| |
| if (range->bounds ()->high.kind () == PROP_LOCEXPR |
| || range->bounds ()->high.kind () == PROP_LOCLIST) |
| { |
| gcc_type result; |
| |
| if (type->is_vector ()) |
| return context->plugin ().error (_("variably-sized vector type" |
| " is not supported")); |
| |
| std::string upper_bound |
| = c_get_range_decl_name (&range->bounds ()->high); |
| result = context->plugin ().build_vla_array_type (element_type, |
| upper_bound.c_str ()); |
| return result; |
| } |
| else |
| { |
| LONGEST low_bound, high_bound, count; |
| |
| if (!get_array_bounds (type, &low_bound, &high_bound)) |
| count = -1; |
| else |
| { |
| gdb_assert (low_bound == 0); /* Ensured above. */ |
| count = high_bound + 1; |
| } |
| |
| if (type->is_vector ()) |
| return context->plugin ().build_vector_type (element_type, count); |
| return context->plugin ().build_array_type (element_type, count); |
| } |
| } |
| |
| /* Convert a struct or union type to its gcc representation. */ |
| |
| static gcc_type |
| convert_struct_or_union (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_CODE_STRUCT) |
| result = context->plugin ().build_record_type (); |
| else |
| { |
| gdb_assert (type->code () == TYPE_CODE_UNION); |
| result = context->plugin ().build_union_type (); |
| } |
| context->insert_type (type, result); |
| |
| for (i = 0; i < type->num_fields (); ++i) |
| { |
| gcc_type field_type; |
| unsigned long bitsize = TYPE_FIELD_BITSIZE (type, i); |
| |
| field_type = context->convert_type (type->field (i).type ()); |
| if (bitsize == 0) |
| bitsize = 8 * TYPE_LENGTH (type->field (i).type ()); |
| context->plugin ().build_add_field (result, |
| type->field (i).name (), |
| field_type, |
| bitsize, |
| TYPE_FIELD_BITPOS (type, i)); |
| } |
| |
| context->plugin ().finish_record_or_union (result, TYPE_LENGTH (type)); |
| return result; |
| } |
| |
| /* Convert an enum type to its gcc representation. */ |
| |
| static gcc_type |
| convert_enum (compile_c_instance *context, struct type *type) |
| { |
| gcc_type int_type, result; |
| int i; |
| |
| int_type = context->plugin ().int_type_v0 (type->is_unsigned (), |
| TYPE_LENGTH (type)); |
| |
| result = context->plugin ().build_enum_type (int_type); |
| for (i = 0; i < type->num_fields (); ++i) |
| { |
| context->plugin ().build_add_enum_constant |
| (result, type->field (i).name (), TYPE_FIELD_ENUMVAL (type, i)); |
| } |
| |
| context->plugin ().finish_enum_type (result); |
| |
| return result; |
| } |
| |
| /* Convert a function type to its gcc representation. */ |
| |
| static gcc_type |
| convert_func (compile_c_instance *context, struct type *type) |
| { |
| int i; |
| gcc_type result, return_type; |
| struct gcc_type_array array; |
| int is_varargs = type->has_varargs () || !type->is_prototyped (); |
| |
| struct type *target_type = TYPE_TARGET_TYPE (type); |
| |
| /* Functions with no debug info have no return type. Ideally we'd |
| want to fallback to the type of the cast just before the |
| function, like GDB's built-in expression parser, but we don't |
| have access to that type here. For now, fallback to int, like |
| GDB's parser used to do. */ |
| if (target_type == NULL) |
| { |
| if (type->is_objfile_owned ()) |
| target_type = objfile_type (type->objfile_owner ())->builtin_int; |
| else |
| target_type = builtin_type (type->arch_owner ())->builtin_int; |
| warning (_("function has unknown return type; assuming int")); |
| } |
| |
| /* This approach means we can't make self-referential function |
| types. Those are impossible in C, though. */ |
| return_type = context->convert_type (target_type); |
| |
| array.n_elements = type->num_fields (); |
| std::vector<gcc_type> elements (array.n_elements); |
| array.elements = elements.data (); |
| for (i = 0; i < type->num_fields (); ++i) |
| array.elements[i] = context->convert_type (type->field (i).type ()); |
| |
| result = context->plugin ().build_function_type (return_type, |
| &array, is_varargs); |
| |
| return result; |
| } |
| |
| /* Convert an integer type to its gcc representation. */ |
| |
| static gcc_type |
| convert_int (compile_c_instance *context, struct type *type) |
| { |
| if (context->plugin ().version () >= GCC_C_FE_VERSION_1) |
| { |
| if (type->has_no_signedness ()) |
| { |
| gdb_assert (TYPE_LENGTH (type) == 1); |
| return context->plugin ().char_type (); |
| } |
| return context->plugin ().int_type (type->is_unsigned (), |
| TYPE_LENGTH (type), |
| type->name ()); |
| } |
| else |
| return context->plugin ().int_type_v0 (type->is_unsigned (), |
| TYPE_LENGTH (type)); |
| } |
| |
| /* Convert a floating-point type to its gcc representation. */ |
| |
| static gcc_type |
| convert_float (compile_c_instance *context, struct type *type) |
| { |
| if (context->plugin ().version () >= GCC_C_FE_VERSION_1) |
| return context->plugin ().float_type (TYPE_LENGTH (type), |
| type->name ()); |
| else |
| return context->plugin ().float_type_v0 (TYPE_LENGTH (type)); |
| } |
| |
| /* Convert the 'void' type to its gcc representation. */ |
| |
| static gcc_type |
| convert_void (compile_c_instance *context, struct type *type) |
| { |
| return context->plugin ().void_type (); |
| } |
| |
| /* Convert a boolean type to its gcc representation. */ |
| |
| static gcc_type |
| convert_bool (compile_c_instance *context, struct type *type) |
| { |
| return context->plugin ().bool_type (); |
| } |
| |
| /* Convert a qualified type to its gcc representation. */ |
| |
| static gcc_type |
| convert_qualified (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 = context->convert_type (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 context->plugin ().build_qualified_type (unqual_converted, |
| quals.raw ()); |
| } |
| |
| /* Convert a complex type to its gcc representation. */ |
| |
| static gcc_type |
| convert_complex (compile_c_instance *context, struct type *type) |
| { |
| gcc_type base = context->convert_type (TYPE_TARGET_TYPE (type)); |
| |
| return context->plugin ().build_complex_type (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 (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_INSTANCE_FLAG_CONST |
| | TYPE_INSTANCE_FLAG_VOLATILE |
| | TYPE_INSTANCE_FLAG_RESTRICT)) != 0) |
| return convert_qualified (context, type); |
| |
| switch (type->code ()) |
| { |
| 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); |
| |
| case TYPE_CODE_ERROR: |
| { |
| /* Ideally, if we get here due to a cast expression, we'd use |
| the cast-to type as the variable's type, like GDB's |
| built-in parser does. For now, assume "int" like GDB's |
| built-in parser used to do, but at least warn. */ |
| struct type *fallback; |
| if (type->is_objfile_owned ()) |
| fallback = objfile_type (type->objfile_owner ())->builtin_int; |
| else |
| fallback = builtin_type (type->arch_owner ())->builtin_int; |
| warning (_("variable has unknown type; assuming int")); |
| return convert_int (context, fallback); |
| } |
| } |
| |
| return context->plugin ().error (_("cannot convert gdb type to gcc type")); |
| } |
| |
| /* Default compile flags for C. */ |
| |
| const char *compile_c_instance::m_default_cflags = "-std=gnu11" |
| /* Otherwise the .o file may need |
| "_Unwind_Resume" and |
| "__gcc_personality_v0". */ |
| " -fno-exceptions" |
| " -Wno-implicit-function-declaration"; |
| |
| /* See compile-c.h. */ |
| |
| gcc_type |
| compile_c_instance::convert_type (struct type *type) |
| { |
| /* 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); |
| |
| gcc_type result; |
| if (get_cached_type (type, &result)) |
| return result; |
| |
| result = convert_type_basic (this, type); |
| insert_type (type, result); |
| return result; |
| } |
| |
| |
| |
| /* C plug-in wrapper. */ |
| |
| #define FORWARD(OP,...) m_context->c_ops->OP(m_context, ##__VA_ARGS__) |
| #define GCC_METHOD0(R, N) \ |
| R gcc_c_plugin::N () const \ |
| { return FORWARD (N); } |
| #define GCC_METHOD1(R, N, A) \ |
| R gcc_c_plugin::N (A a) const \ |
| { return FORWARD (N, a); } |
| #define GCC_METHOD2(R, N, A, B) \ |
| R gcc_c_plugin::N (A a, B b) const \ |
| { return FORWARD (N, a, b); } |
| #define GCC_METHOD3(R, N, A, B, C) \ |
| R gcc_c_plugin::N (A a, B b, C c) const \ |
| { return FORWARD (N, a, b, c); } |
| #define GCC_METHOD4(R, N, A, B, C, D) \ |
| R gcc_c_plugin::N (A a, B b, C c, D d) const \ |
| { return FORWARD (N, a, b, c, d); } |
| #define GCC_METHOD5(R, N, A, B, C, D, E) \ |
| R gcc_c_plugin::N (A a, B b, C c, D d, E e) const \ |
| { return FORWARD (N, a, b, c, d, e); } |
| #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \ |
| R gcc_c_plugin::N (A a, B b, C c, D d, E e, F f, G g) const \ |
| { return FORWARD (N, a, b, c, d, e, f, g); } |
| |
| #include "gcc-c-fe.def" |
| |
| #undef GCC_METHOD0 |
| #undef GCC_METHOD1 |
| #undef GCC_METHOD2 |
| #undef GCC_METHOD3 |
| #undef GCC_METHOD4 |
| #undef GCC_METHOD5 |
| #undef GCC_METHOD7 |
| #undef FORWARD |