summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog19
-rw-r--r--gdb/c-typeprint.c13
-rw-r--r--gdb/dwarf2read.c13
-rw-r--r--gdb/gdbtypes.c3
-rw-r--r--gdb/gdbtypes.h8
-rw-r--r--gdb/gnu-v3-abi.c185
-rw-r--r--gdb/varobj.c19
7 files changed, 157 insertions, 103 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a2dbfaae42d..424383d308a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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>
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 807eec16781..a984e3ffcca 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -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
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 381350fe287..2f6e522f3f0 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -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. */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 299d0c515a2..ac126cd7b13 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -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. */
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index be6ed552363..451a94a7949 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -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 \
diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
index 0f9d44efc0d..7e4cb23028a 100644
--- a/gdb/gnu-v3-abi.c
+++ b/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;
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 8f22156e260..2e4cf43ca65 100644
--- a/gdb/varobj.c
+++ b/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;