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

Daniel Berlin
2001-11-27T06:05:35Z

On Tue, 27 Nov 2001, Daniel Jacobowitz wrote:

> 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.
>
> I am exceedingly tempted to do this.
>
> > 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.
>
> I certainly can't explain it :) This code mostly mystifies me.

It's taking advantage of g++ magic.
I didn't add it, and have wanted to rid us of it for years.
It's evil.
It's a a field that g++ uses internally to track where the
virtual function table is.
If you want to see how fragile C++ support is in gdb, change the vfield
name in gcc/cp/cp-tree.h and watch what happens.

While you are there, notice that they don't use $ to begin it because it
confuses gdb (bad), and that it actually won't match the string we test
against, depending on what the assembler supports in terms of label names
(It might be __vptr_a instead of _vptr.a).
Cute, no?

> It seems that the vptr for a given class is always a field of the class,
Yes, it has to be, g++ generates them.

However, be aware that they may not always be correct at all times during
execution.
I see comments like this in the g++ code
/* If this class uses a different vtable than its primary base
then when we will need to initialize our vptr after the base
class constructor runs. */
Giving me the impression that it can be very dangerous to rely on them at
all times in gdb.
GCC knows when it's safe to use them, because it's generating the code.
We don't.

> and may actually overlap where the vptr for its first virtual base
> class.

It's going to depend on a number of factors.
> TYPE_VPTR_FIELDNO tells us where it is. For example, in GCC
> 2.x, this code:
>
> class Foo
> {
> int bar;
> public:
> virtual int thug() { return 1; }
> };
>
> class Foo2
> {
> int bar2;
> };
>
> class Baz : public Foo2, public Foo {
> int baz;
> public:
> virtual int thugs() { return 1; }
> };
>
> will cause vptr_fieldno for Baz to be 1, indicating its vptr is stored
> in memory at the beginning of field 1.
>
> Gnu v2 code handles this by casting the Baz to a Foo, at which point
> magic happens, and somehow the vptr is visible. This suggests that my
> fix is not the best way of doing it, and I should be using
> TYPE_VPTR_BASETYPE somehow instead. I may need to think some more.
>
> Upon further reflection, TYPE_VPTR_FIELDNO is supposed to be a field
> index in TYPE_VPTR_BASETYPE.

Yes.
> Interesting. I think there's something
> wrong here; more comments tomorrow.
Wouldn't surprise me a bit.
>
> > I wonder if that dereferencing code could be simplified with a
> > judicious use of `lookup_pointer_type (vtable_type)' and
> > `value_deref'...
>
> I suppose it would read simpler if I took a value_addr () and cast a
> bit. But magic happens in value casting that I don't want to happen.