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

Daniel Jacobowitz
2001-11-26T23:08:00Z

On Mon, Nov 26, 2001 at 11:39:34PM -0500, Jim Blandy wrote:
>
> I'm with you on VALUE_OFFSET and VALUE_EMBEDDED_OFFSET. I'm pretty
> sure VALUE_OFFSET can be eliminated from GDB entirely, with some minor
> changes to the representation of subvalues of registers and
> convenience variables.

Whew. I'd like to reiterate my comment on VALUE_EMBEDDED_OFFSET. See
the patch below.

> Can you explain exactly what TYPE_VPTR_FIELDNO means, and how it works
> in heavily derived classes? What I think you're basically doing there
> is taking the address of the field indicated by TYPE_VPTR_FIELDNO,
> casting that to a void *, and then casting that to the `struct
> gdb_gnu_v3_abi_vtable' type. I have this vague memory that maybe
> using TYPE_VPTR_FIELDNO correctly would fix that.

The important things to understand, now that I understand them:
- TYPE_VPTR_FIELDNO is an index into TYPE_VPTR_BASETYPE. Not into
any of the other things we try to index with it.
- value_cast from "pointer to struct" to "struct's base class" is not
correct. The comment about value_cast not finding superclasses
correctly is also not correct.

How does this patch look? With this patch, every virtual function call
that we think we know how to make (i.e. that we don't hit the "virtual
baseclass botch" that I'll look at with Daniel Berlin's suggestions
tomorrow) is now correct. We don't call random offsets in the wrong
vtables any more.

I think these fixes also apply to gnu-v2-abi.c. I'll check tomorrow.
I'm tired :)

There are some multiple inheritance issues I'm not quite sure of that
I'd like to check, also. They may require saving a tree of
superclasses rather than an absolute superclass, and while loops
walking/casting up the vptr_basetype chain. I'll think about it.

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

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

* values.c (value_primitive_field): Add embedded_offset to the
address of structure members.
* gnu-v3-abi.c (gnuv3_rtti_type): Cast to base type before
attempting to access vtable pointer. Set using_enc_p if we cast.
(gnuv3_virtual_fn_field): Call value_cast with structure rather than
structure pointer. Cast to base type before attempting to access
vtable pointer.

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 06:57:48
@@ -194,6 +194,7 @@ gnuv3_rtti_type (struct value *value,
const char *class_name;
struct symbol *class_symbol;
struct type *run_time_type;
+ struct type *base_type;
LONGEST offset_to_top;

/* We only have RTTI for class objects. */
@@ -206,8 +207,18 @@ gnuv3_rtti_type (struct value *value,
if (TYPE_VPTR_FIELDNO (value_type) == -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. */
+ an instance of our imaginary gdb_gnu_v3_abi_vtable structure. */
+ base_type = check_typedef (TYPE_VPTR_BASETYPE (value_type));
+ if (value_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, TYPE_VPTR_FIELDNO (value_type)));
vtable = value_at_lazy (vtable_type,
@@ -260,8 +271,6 @@ gnuv3_rtti_type (struct value *value,
>= TYPE_LENGTH (run_time_type)));
if (top_p)
*top_p = - offset_to_top;
- if (using_enc_p)
- *using_enc_p = 0;

return run_time_type;
}
@@ -303,15 +312,17 @@ gnuv3_virtual_fn_field (struct value **v
function, cast our value to that baseclass. This takes care of
any necessary `this' adjustments. */
if (vfn_base != value_type)
- /* It would be nicer to simply cast the value to the appropriate
- base class (and I think that is supposed to be legal), but
- value_cast only does the right magic when casting pointers. */
- value = value_ind (value_cast (vfn_base, value_addr (value)));
+ value = value_cast (vfn_base, value);

/* Now value is an object of the appropriate base type. Fetch its
virtual table. */
+ /* It might be possible to do this cast at the same time as the above.
+ Does multiple inheritance affect this? */
+ if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base)
+ value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value);
vtable_address
= value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base)));
+
vtable = value_at_lazy (vtable_type,
vtable_address - vtable_address_point_offset (),
VALUE_BFD_SECTION (value));
Index: values.c
===================================================================
RCS file: /cvs/src/src/gdb/values.c,v
retrieving revision 1.27
diff -u -p -r1.27 values.c
--- values.c 2001/11/09 16:41:50 1.27
+++ values.c 2001/11/27 06:57:50
@@ -929,7 +929,8 @@ value_primitive_field (register value_pt
memcpy (VALUE_CONTENTS_RAW (v),
VALUE_CONTENTS_RAW (arg1) + offset,
TYPE_LENGTH (type));
- VALUE_OFFSET (v) = VALUE_OFFSET (arg1) + offset;
+ VALUE_OFFSET (v) = VALUE_OFFSET (arg1) + offset
+ + VALUE_EMBEDDED_OFFSET (arg1);
}
VALUE_LVAL (v) = VALUE_LVAL (arg1);
if (VALUE_LVAL (arg1) == lval_internalvar)