[RFA/c++] Fix printing classes with virtual base classes

Daniel Jacobowitz
2001-11-27T01:19:40Z

Whew. Finally tracked this down.

The problem is in the layout of a class whose base class has a virtual
table. Given:

class Bar {
virtual int thunk ();
};

class Foo : public Bar {
int test;
};

A Foo will look like this:

/-----------------------\
| Foo | test |
\-----------------------/

Its own vptr will be conveniently Foo's vptr. But the type of Bar's field 0
(which is marked as having the vptr in it) is Foo, not some pointer type.
If I explicitly cast to pointer, everything works more-or-less OK.

I'm pretty sure of the C++ side of this. If there's a more appropriate
function for doing the cast to pointer I'd love to hear about it; otherwise,
OK to commit?

Can't really tell what effect it has on the testsuite, as just about
everything else in the relevant tests is failing anyway. I have a few more
low-hanging bugs in this area that I'm debugging now.

--
Daniel Jacobowitz Carnegie Mellon University
MontaVista Software Debian GNU/Linux Developer

2001-11-26 Daniel Jacobowitz <drow@mvista.com>

* gnu-v3-abi.c (gnuv3_rtti_type): Explicitly cast
the vtable pointer to a pointer before loading it.
(gnuv3_virtual_fn_field): Likewise.

Index: gnu-v3-abi.c
===================================================================
RCS file: /cvs/src/src/gdb/gnu-v3-abi.c,v
retrieving revision 1.4
diff -u -p -r1.4 gnu-v3-abi.c
--- gnu-v3-abi.c 2001/10/16 01:58:07 1.4
+++ gnu-v3-abi.c 2001/11/27 00:21:44
@@ -188,7 +188,7 @@ gnuv3_rtti_type (struct value *value,
struct type *vtable_type = gdbarch_data (vtable_type_gdbarch_data);
struct type *value_type = check_typedef (VALUE_TYPE (value));
CORE_ADDR vtable_address;
- struct value *vtable;
+ struct value *vtable, *vtable_addr_value;
struct minimal_symbol *vtable_symbol;
const char *vtable_symbol_name;
const char *class_name;
@@ -207,9 +207,17 @@ gnuv3_rtti_type (struct value *value,
return NULL;

/* Fetch VALUE's virtual table pointer, and tweak it to point at
- an instance of our imaginary gdb_gnu_v3_abi_vtable structure. */
+ an instance of our imaginary gdb_gnu_v3_abi_vtable structure.
+ The type of the field may not be a pointer type. In a derived
+ class with a virtual base class, it will be the type of the base
+ class. Thus we need to cast. */
+ vtable_addr_value =
+ value_at (builtin_type_void_data_ptr,
+ VALUE_ADDRESS (value_field (value,
+ TYPE_VPTR_FIELDNO (value_type))),
+ VALUE_BFD_SECTION (value));
vtable_address
- = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (value_type)));
+ = value_as_address (vtable_addr_value);
vtable = value_at_lazy (vtable_type,
vtable_address - vtable_address_point_offset (),
VALUE_BFD_SECTION (value));
@@ -277,7 +285,7 @@ gnuv3_virtual_fn_field (struct value **v
struct type *value_type = check_typedef (VALUE_TYPE (value));
struct type *vfn_base;
CORE_ADDR vtable_address;
- struct value *vtable;
+ struct value *vtable, *vtable_addr_value;
struct value *vfn;

/* Some simple sanity checks. */
@@ -309,9 +317,16 @@ gnuv3_virtual_fn_field (struct value **v
value = value_ind (value_cast (vfn_base, value_addr (value)));

/* Now value is an object of the appropriate base type. Fetch its
- virtual table. */
+ virtual table. As in gnuv3_rtti_type, the type of the field may
+ not be a pointer type. In a derived class with a virtual base class,
+ it will be the type of the base class. Thus we need to cast. */
+ vtable_addr_value =
+ value_at (builtin_type_void_data_ptr,
+ VALUE_ADDRESS (value_field (value,
+ TYPE_VPTR_FIELDNO (vfn_base))),
+ VALUE_BFD_SECTION (value));
vtable_address
- = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base)));
+ = value_as_address (vtable_addr_value);
vtable = value_at_lazy (vtable_type,
vtable_address - vtable_address_point_offset (),
VALUE_BFD_SECTION (value));