470 lines
13 KiB
C
470 lines
13 KiB
C
/* Convert types from GDB to GCC
|
||
|
||
Copyright (C) 2014-2017 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 "objfiles.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;
|
||
|
||
if (TYPE_VECTOR (type))
|
||
return C_CTX (context)->c_ops->error (C_CTX (context),
|
||
_("variably-sized vector type"
|
||
" is not supported"));
|
||
|
||
std::string 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.c_str ());
|
||
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);
|
||
|
||
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_OBJFILE_OWNED (type))
|
||
target_type = objfile_type (TYPE_OWNER (type).objfile)->builtin_int;
|
||
else
|
||
target_type = builtin_type (TYPE_OWNER (type).gdbarch)->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 = convert_type (context, target_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);
|
||
|
||
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_OBJFILE_OWNED (type))
|
||
fallback = objfile_type (TYPE_OWNER (type).objfile)->builtin_int;
|
||
else
|
||
fallback = builtin_type (TYPE_OWNER (type).gdbarch)->builtin_int;
|
||
warning (_("variable has unknown type; assuming int"));
|
||
return convert_int (context, fallback);
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|