mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-01 11:59:27 +08:00
2009-11-12 Daniel Jacobowitz <dan@codesourcery.com>
Paul Brook <paul@codesourcery.com> * c-typeprint.c (c_type_print_base): Skip artificial fields. Use get_vptr_fieldno to skip the vtable pointer. * dwarf2read.c (dwarf2_add_field): Set FIELD_ARTIFICIAL on artificial fields. (dwarf2_add_member_fn): Complain about virtual member functions without DW_AT_vtable_elem_location and force TYPE_CPLUS_DYNAMIC. * gdbtypes.c (get_vptr_fieldno): Update comment. * gdbtypes.h (struct cplus_struct_type): Add is_dynamic. (TYPE_CPLUS_DYNAMIC): New macro. * gnu-v3-abi.c (gnuv3_dynamic_class): New. (gnuv3_get_vtable): Rewrite to use gnuv3_dynamic_class. Move higher. (gnuv3_rtti_type, gnuv3_get_virtual_fn, gnuv3_baseclass_offset): Use gnuv3_get_vtable. * varobj.c (cplus_class_num_children, cplus_describe_child): Skip artificial fields. Use get_vptr_fieldno to skip the vtable pointer.
This commit is contained in:
185
gdb/gnu-v3-abi.c
185
gdb/gnu-v3-abi.c
@ -190,23 +190,96 @@ vtable_address_point_offset (struct gdbarch *gdbarch)
|
||||
}
|
||||
|
||||
|
||||
/* Determine whether structure TYPE is a dynamic class. Cache the
|
||||
result. */
|
||||
|
||||
static int
|
||||
gnuv3_dynamic_class (struct type *type)
|
||||
{
|
||||
int fieldnum, fieldelem;
|
||||
|
||||
if (TYPE_CPLUS_DYNAMIC (type))
|
||||
return TYPE_CPLUS_DYNAMIC (type) == 1;
|
||||
|
||||
ALLOCATE_CPLUS_STRUCT_TYPE (type);
|
||||
|
||||
for (fieldnum = 0; fieldnum < TYPE_N_BASECLASSES (type); fieldnum++)
|
||||
if (BASETYPE_VIA_VIRTUAL (type, fieldnum)
|
||||
|| gnuv3_dynamic_class (TYPE_FIELD_TYPE (type, fieldnum)))
|
||||
{
|
||||
TYPE_CPLUS_DYNAMIC (type) = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++)
|
||||
for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum);
|
||||
fieldelem++)
|
||||
{
|
||||
struct fn_field *f = TYPE_FN_FIELDLIST1 (type, fieldnum);
|
||||
|
||||
if (TYPE_FN_FIELD_VIRTUAL_P (f, fieldelem))
|
||||
{
|
||||
TYPE_CPLUS_DYNAMIC (type) = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
TYPE_CPLUS_DYNAMIC (type) = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find the vtable for a value of CONTAINER_TYPE located at
|
||||
CONTAINER_ADDR. Return a value of the correct vtable type for this
|
||||
architecture, or NULL if CONTAINER does not have a vtable. */
|
||||
|
||||
static struct value *
|
||||
gnuv3_get_vtable (struct gdbarch *gdbarch,
|
||||
struct type *container_type, CORE_ADDR container_addr)
|
||||
{
|
||||
struct type *vtable_type = gdbarch_data (gdbarch,
|
||||
vtable_type_gdbarch_data);
|
||||
struct type *vtable_pointer_type;
|
||||
struct value *vtable_pointer;
|
||||
CORE_ADDR vtable_address;
|
||||
|
||||
/* If this type does not have a virtual table, don't read the first
|
||||
field. */
|
||||
if (!gnuv3_dynamic_class (check_typedef (container_type)))
|
||||
return NULL;
|
||||
|
||||
/* We do not consult the debug information to find the virtual table.
|
||||
The ABI specifies that it is always at offset zero in any class,
|
||||
and debug information may not represent it.
|
||||
|
||||
We avoid using value_contents on principle, because the object might
|
||||
be large. */
|
||||
|
||||
/* Find the type "pointer to virtual table". */
|
||||
vtable_pointer_type = lookup_pointer_type (vtable_type);
|
||||
|
||||
/* Load it from the start of the class. */
|
||||
vtable_pointer = value_at (vtable_pointer_type, container_addr);
|
||||
vtable_address = value_as_address (vtable_pointer);
|
||||
|
||||
/* Correct it to point at the start of the virtual table, rather
|
||||
than the address point. */
|
||||
return value_at_lazy (vtable_type,
|
||||
vtable_address - vtable_address_point_offset (gdbarch));
|
||||
}
|
||||
|
||||
|
||||
static struct type *
|
||||
gnuv3_rtti_type (struct value *value,
|
||||
int *full_p, int *top_p, int *using_enc_p)
|
||||
{
|
||||
struct gdbarch *gdbarch;
|
||||
struct type *vtable_type;
|
||||
struct type *values_type = check_typedef (value_type (value));
|
||||
CORE_ADDR vtable_address;
|
||||
struct value *vtable;
|
||||
struct minimal_symbol *vtable_symbol;
|
||||
const char *vtable_symbol_name;
|
||||
const char *class_name;
|
||||
struct type *run_time_type;
|
||||
struct type *base_type;
|
||||
LONGEST offset_to_top;
|
||||
struct type *values_type_vptr_basetype;
|
||||
int values_type_vptr_fieldno;
|
||||
|
||||
/* We only have RTTI for class objects. */
|
||||
if (TYPE_CODE (values_type) != TYPE_CODE_CLASS)
|
||||
@ -214,33 +287,15 @@ gnuv3_rtti_type (struct value *value,
|
||||
|
||||
/* Determine architecture. */
|
||||
gdbarch = get_type_arch (values_type);
|
||||
vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);
|
||||
|
||||
/* If we can't find the virtual table pointer for values_type, we
|
||||
can't find the RTTI. */
|
||||
values_type_vptr_fieldno = get_vptr_fieldno (values_type,
|
||||
&values_type_vptr_basetype);
|
||||
if (values_type_vptr_fieldno == -1)
|
||||
return NULL;
|
||||
|
||||
if (using_enc_p)
|
||||
*using_enc_p = 0;
|
||||
|
||||
/* Fetch VALUE's virtual table pointer, and tweak it to point at
|
||||
an instance of our imaginary gdb_gnu_v3_abi_vtable structure. */
|
||||
base_type = check_typedef (values_type_vptr_basetype);
|
||||
if (values_type != base_type)
|
||||
{
|
||||
value = value_cast (base_type, value);
|
||||
if (using_enc_p)
|
||||
*using_enc_p = 1;
|
||||
}
|
||||
vtable_address
|
||||
= value_as_address (value_field (value, values_type_vptr_fieldno));
|
||||
vtable
|
||||
= value_at_lazy (vtable_type,
|
||||
vtable_address - vtable_address_point_offset (gdbarch));
|
||||
|
||||
vtable = gnuv3_get_vtable (gdbarch, value_type (value),
|
||||
value_as_address (value_addr (value)));
|
||||
if (vtable == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Find the linker symbol for this vtable. */
|
||||
vtable_symbol
|
||||
= lookup_minimal_symbol_by_pc (value_address (vtable)
|
||||
@ -282,45 +337,9 @@ gnuv3_rtti_type (struct value *value,
|
||||
>= TYPE_LENGTH (run_time_type)));
|
||||
if (top_p)
|
||||
*top_p = - offset_to_top;
|
||||
|
||||
return run_time_type;
|
||||
}
|
||||
|
||||
/* Find the vtable for CONTAINER and return a value of the correct
|
||||
vtable type for this architecture. */
|
||||
|
||||
static struct value *
|
||||
gnuv3_get_vtable (struct gdbarch *gdbarch, struct value *container)
|
||||
{
|
||||
struct type *vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);
|
||||
struct type *vtable_pointer_type;
|
||||
struct value *vtable_pointer;
|
||||
CORE_ADDR vtable_pointer_address, vtable_address;
|
||||
|
||||
/* We do not consult the debug information to find the virtual table.
|
||||
The ABI specifies that it is always at offset zero in any class,
|
||||
and debug information may not represent it. We won't issue an
|
||||
error if there's a class with virtual functions but no virtual table
|
||||
pointer, but something's already gone seriously wrong if that
|
||||
happens.
|
||||
|
||||
We avoid using value_contents on principle, because the object might
|
||||
be large. */
|
||||
|
||||
/* Find the type "pointer to virtual table". */
|
||||
vtable_pointer_type = lookup_pointer_type (vtable_type);
|
||||
|
||||
/* Load it from the start of the class. */
|
||||
vtable_pointer_address = value_as_address (value_addr (container));
|
||||
vtable_pointer = value_at (vtable_pointer_type, vtable_pointer_address);
|
||||
vtable_address = value_as_address (vtable_pointer);
|
||||
|
||||
/* Correct it to point at the start of the virtual table, rather
|
||||
than the address point. */
|
||||
return value_at_lazy (vtable_type,
|
||||
vtable_address - vtable_address_point_offset (gdbarch));
|
||||
}
|
||||
|
||||
/* Return a function pointer for CONTAINER's VTABLE_INDEX'th virtual
|
||||
function, of type FNTYPE. */
|
||||
|
||||
@ -328,8 +347,12 @@ static struct value *
|
||||
gnuv3_get_virtual_fn (struct gdbarch *gdbarch, struct value *container,
|
||||
struct type *fntype, int vtable_index)
|
||||
{
|
||||
struct value *vtable = gnuv3_get_vtable (gdbarch, container);
|
||||
struct value *vfn;
|
||||
struct value *vtable, *vfn;
|
||||
|
||||
/* Every class with virtual functions must have a vtable. */
|
||||
vtable = gnuv3_get_vtable (gdbarch, value_type (container),
|
||||
value_as_address (value_addr (container)));
|
||||
gdb_assert (vtable != NULL);
|
||||
|
||||
/* Fetch the appropriate function pointer from the vtable. */
|
||||
vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions),
|
||||
@ -389,18 +412,13 @@ gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr,
|
||||
CORE_ADDR address)
|
||||
{
|
||||
struct gdbarch *gdbarch;
|
||||
struct type *vtable_type;
|
||||
struct type *ptr_type;
|
||||
struct value *vtable;
|
||||
struct type *vbasetype;
|
||||
struct value *vbase_array;
|
||||
CORE_ADDR vtable_address;
|
||||
long int cur_base_offset, base_offset;
|
||||
int vbasetype_vptr_fieldno;
|
||||
|
||||
/* Determine architecture. */
|
||||
gdbarch = get_type_arch (type);
|
||||
vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);
|
||||
ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
|
||||
|
||||
/* If it isn't a virtual base, this is easy. The offset is in the
|
||||
@ -422,29 +440,8 @@ gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr,
|
||||
error (_("Misaligned vbase offset."));
|
||||
cur_base_offset = cur_base_offset / ((int) TYPE_LENGTH (ptr_type));
|
||||
|
||||
/* We're now looking for the cur_base_offset'th entry (negative index)
|
||||
in the vcall_and_vbase_offsets array. We used to cast the object to
|
||||
its TYPE_VPTR_BASETYPE, and reference the vtable as TYPE_VPTR_FIELDNO;
|
||||
however, that cast can not be done without calling baseclass_offset again
|
||||
if the TYPE_VPTR_BASETYPE is a virtual base class, as described in the
|
||||
v3 C++ ABI Section 2.4.I.2.b. Fortunately the ABI guarantees that the
|
||||
vtable pointer will be located at the beginning of the object, so we can
|
||||
bypass the casting. Verify that the TYPE_VPTR_FIELDNO is in fact at the
|
||||
start of whichever baseclass it resides in, as a sanity measure - iff
|
||||
we have debugging information for that baseclass. */
|
||||
|
||||
vbasetype = check_typedef (TYPE_VPTR_BASETYPE (type));
|
||||
vbasetype_vptr_fieldno = get_vptr_fieldno (vbasetype, NULL);
|
||||
|
||||
if (vbasetype_vptr_fieldno >= 0
|
||||
&& TYPE_FIELD_BITPOS (vbasetype, vbasetype_vptr_fieldno) != 0)
|
||||
error (_("Illegal vptr offset in class %s"),
|
||||
TYPE_NAME (vbasetype) ? TYPE_NAME (vbasetype) : "<unknown>");
|
||||
|
||||
vtable_address = value_as_address (value_at_lazy (ptr_type, address));
|
||||
vtable
|
||||
= value_at_lazy (vtable_type,
|
||||
vtable_address - vtable_address_point_offset (gdbarch));
|
||||
vtable = gnuv3_get_vtable (gdbarch, type, address);
|
||||
gdb_assert (vtable != NULL);
|
||||
vbase_array = value_field (vtable, vtable_field_vcall_and_vbase_offsets);
|
||||
base_offset = value_as_long (value_subscript (vbase_array, cur_base_offset));
|
||||
return base_offset;
|
||||
|
Reference in New Issue
Block a user