|
|
/* Convert types from GDB to GCC
|
|
|
|
|
|
Copyright (C) 2014-2022 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 (i).loc_bitpos ());
|
|
|
}
|
|
|
|
|
|
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 (i).loc_enumval ());
|
|
|
}
|
|
|
|
|
|
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
|