mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-21 15:33:33 +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:
parent
87728fa060
commit
d48cc9dd6f
@ -1,3 +1,22 @@
|
||||
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.
|
||||
|
||||
2009-11-12 Paul Brook <paul@codesourcery.com>
|
||||
Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
|
@ -761,6 +761,9 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show,
|
||||
}
|
||||
else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
|
||||
{
|
||||
struct type *basetype;
|
||||
int vptr_fieldno;
|
||||
|
||||
cp_type_print_derivation_info (stream, type);
|
||||
|
||||
fprintf_filtered (stream, "{\n");
|
||||
@ -848,12 +851,16 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show,
|
||||
do not print the field that it occupies. */
|
||||
|
||||
len = TYPE_NFIELDS (type);
|
||||
vptr_fieldno = get_vptr_fieldno (type, &basetype);
|
||||
for (i = TYPE_N_BASECLASSES (type); i < len; i++)
|
||||
{
|
||||
QUIT;
|
||||
/* Don't print out virtual function table. */
|
||||
if (strncmp (TYPE_FIELD_NAME (type, i), "_vptr", 5) == 0
|
||||
&& is_cplus_marker ((TYPE_FIELD_NAME (type, i))[5]))
|
||||
|
||||
/* If we have a virtual table pointer, omit it. Even if
|
||||
virtual table pointers are not specifically marked in
|
||||
the debug info, they should be artificial. */
|
||||
if ((type == basetype && i == vptr_fieldno)
|
||||
|| TYPE_FIELD_ARTIFICIAL (type, i))
|
||||
continue;
|
||||
|
||||
/* If this is a C++ class we can print the various C++ section
|
||||
|
@ -4484,6 +4484,7 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
|
||||
pointer or virtual base class pointer) to private. */
|
||||
if (dwarf2_attr (die, DW_AT_artificial, cu))
|
||||
{
|
||||
FIELD_ARTIFICIAL (*fp) = 1;
|
||||
new_field->accessibility = DW_ACCESS_private;
|
||||
fip->non_public_fields = 1;
|
||||
}
|
||||
@ -4803,6 +4804,18 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
|
||||
else
|
||||
dwarf2_complex_location_expr_complaint ();
|
||||
}
|
||||
else
|
||||
{
|
||||
attr = dwarf2_attr (die, DW_AT_virtuality, cu);
|
||||
if (attr && DW_UNSND (attr))
|
||||
{
|
||||
/* GCC does this, as of 2008-08-25; PR debug/37237. */
|
||||
complaint (&symfile_complaints,
|
||||
_("Member function \"%s\" (offset %d) is virtual but the vtable offset is not specified"),
|
||||
fieldname, die->offset);
|
||||
TYPE_CPLUS_DYNAMIC (type) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the vector of member function fields, and attach it to the type. */
|
||||
|
@ -1277,7 +1277,8 @@ lookup_struct_elt_type (struct type *type, char *name, int noerr)
|
||||
If not found, return -1 and ignore BASETYPEP.
|
||||
Callers should be aware that in some cases (for example,
|
||||
the type or one of its baseclasses is a stub type and we are
|
||||
debugging a .o file), this function will not be able to find the
|
||||
debugging a .o file, or the compiler uses DWARF-2 and is not GCC),
|
||||
this function will not be able to find the
|
||||
virtual function table pointer, and vptr_fieldno will remain -1 and
|
||||
vptr_basetype will remain NULL or incomplete. */
|
||||
|
||||
|
@ -775,6 +775,13 @@ struct cplus_struct_type
|
||||
int line;
|
||||
}
|
||||
*localtype_ptr;
|
||||
|
||||
/* One if this struct is a dynamic class, as defined by the
|
||||
Itanium C++ ABI: if it requires a virtual table pointer,
|
||||
because it or any of its base classes have one or more virtual
|
||||
member functions or virtual base classes. Minus one if not
|
||||
dynamic. Zero if not yet computed. */
|
||||
int is_dynamic : 2;
|
||||
};
|
||||
|
||||
/* Struct used in computing virtual base list */
|
||||
@ -861,6 +868,7 @@ extern void allocate_cplus_struct_type (struct type *);
|
||||
#define TYPE_BASECLASS_BITPOS(thistype,index) TYPE_FIELD_BITPOS(thistype,index)
|
||||
#define BASETYPE_VIA_PUBLIC(thistype, index) \
|
||||
((!TYPE_FIELD_PRIVATE(thistype, index)) && (!TYPE_FIELD_PROTECTED(thistype, index)))
|
||||
#define TYPE_CPLUS_DYNAMIC(thistype) TYPE_CPLUS_SPECIFIC (thistype)->is_dynamic
|
||||
|
||||
#define BASETYPE_VIA_VIRTUAL(thistype, index) \
|
||||
(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
|
||||
|
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;
|
||||
|
19
gdb/varobj.c
19
gdb/varobj.c
@ -3103,16 +3103,21 @@ cplus_number_of_children (struct varobj *var)
|
||||
static void
|
||||
cplus_class_num_children (struct type *type, int children[3])
|
||||
{
|
||||
int i;
|
||||
int i, vptr_fieldno;
|
||||
struct type *basetype = NULL;
|
||||
|
||||
children[v_public] = 0;
|
||||
children[v_private] = 0;
|
||||
children[v_protected] = 0;
|
||||
|
||||
vptr_fieldno = get_vptr_fieldno (type, &basetype);
|
||||
for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); i++)
|
||||
{
|
||||
/* If we have a virtual table pointer, omit it. */
|
||||
if (TYPE_VPTR_BASETYPE (type) == type && TYPE_VPTR_FIELDNO (type) == i)
|
||||
/* If we have a virtual table pointer, omit it. Even if virtual
|
||||
table pointers are not specifically marked in the debug info,
|
||||
they should be artificial. */
|
||||
if ((type == basetype && i == vptr_fieldno)
|
||||
|| TYPE_FIELD_ARTIFICIAL (type, i))
|
||||
continue;
|
||||
|
||||
if (TYPE_FIELD_PROTECTED (type, i))
|
||||
@ -3199,6 +3204,10 @@ cplus_describe_child (struct varobj *parent, int index,
|
||||
find the indexed field. */
|
||||
int type_index = TYPE_N_BASECLASSES (type);
|
||||
enum accessibility acc = public_field;
|
||||
int vptr_fieldno;
|
||||
struct type *basetype = NULL;
|
||||
|
||||
vptr_fieldno = get_vptr_fieldno (type, &basetype);
|
||||
if (strcmp (parent->name, "private") == 0)
|
||||
acc = private_field;
|
||||
else if (strcmp (parent->name, "protected") == 0)
|
||||
@ -3206,8 +3215,8 @@ cplus_describe_child (struct varobj *parent, int index,
|
||||
|
||||
while (index >= 0)
|
||||
{
|
||||
if (TYPE_VPTR_BASETYPE (type) == type
|
||||
&& type_index == TYPE_VPTR_FIELDNO (type))
|
||||
if ((type == basetype && type_index == vptr_fieldno)
|
||||
|| TYPE_FIELD_ARTIFICIAL (type, type_index))
|
||||
; /* ignore vptr */
|
||||
else if (match_accessibility (type, type_index, acc))
|
||||
--index;
|
||||
|
Loading…
Reference in New Issue
Block a user