public inbox for archer@sourceware.org
 help / color / mirror / Atom feed
* How to cast a pointer to a base class with multiple inheritance
@ 2009-07-31  7:21 Matthieu VIAL
  2009-07-31 18:03 ` Tom Tromey
  0 siblings, 1 reply; 7+ messages in thread
From: Matthieu VIAL @ 2009-07-31  7:21 UTC (permalink / raw)
  To: archer

Hello,

I would like to know if it is possible to cast a pointer the way the
compiler do for classes with multiple inheritance with archer. The this
pointer changes depending on the base class. So how to find the other
pointers with the top pointer ?

The following code show the problem:

--------------------------

#include <iostream>

using namespace std;

class A
{
public:
    A(int a);

    int m_intA;
};

class B 
{
public:
    B(int b);

    int m_intB;
};

class C : public A, B
{
public:
    C(int c);

    int m_intC;
};


A::A(int a)
{
    cout << "ctor A :" << hex << this << endl;
    m_intA = a;
}

B::B(int b)
{
    cout << "ctor B :" << hex << this << endl;
    m_intB = b;
}

C::C(int c) : A(c+1), B(c+2)
{
    cout << "ctor C :" << hex << this << endl;
    m_intC = c;
}


int main()
{
    C c(1);

    cout << "@C     :" << hex << &c << endl;
    cout << "@C as A:" << hex << (A*)&c << endl;
    cout << "@C as B:" << hex << (B*)&c << endl;

    return 0;
}

--------------------------

Output :
ctor A :0xbfd572d8
ctor B :0xbfd572dc
ctor C :0xbfd572d8
@C     :0xbfd572d8
@C as A:0xbfd572d8
@C as B:0xbfd572dc

--------------------------


Thanks,
Matthieu VIAL

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to cast a pointer to a base class with multiple inheritance
  2009-07-31  7:21 How to cast a pointer to a base class with multiple inheritance Matthieu VIAL
@ 2009-07-31 18:03 ` Tom Tromey
  2009-08-03  9:20   ` Matthieu VIAL
  0 siblings, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2009-07-31 18:03 UTC (permalink / raw)
  To: Matthieu VIAL; +Cc: archer

>>>>> "Matthieu" == Matthieu VIAL <matthieu.vial@orange-ftgroup.com> writes:

Matthieu> I would like to know if it is possible to cast a pointer the
Matthieu> way the compiler do for classes with multiple inheritance with
Matthieu> archer. The this pointer changes depending on the base
Matthieu> class. So how to find the other pointers with the top pointer
Matthieu> ?

I think Value.cast should do the right thing here.  I haven't tried this
myself, though... did you try it?  It wasn't clear from your message.

If it doesn't work, please file a bug report in the gdb bugzilla using
'archer' as the version, and one of us will fix it.

Tom

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to cast a pointer to a base class with multiple inheritance
  2009-07-31 18:03 ` Tom Tromey
@ 2009-08-03  9:20   ` Matthieu VIAL
  2009-08-03 18:30     ` Tom Tromey
  0 siblings, 1 reply; 7+ messages in thread
From: Matthieu VIAL @ 2009-08-03  9:20 UTC (permalink / raw)
  To: Tom Tromey; +Cc: archer


> Matthieu> I would like to know if it is possible to cast a pointer the
> Matthieu> way the compiler do for classes with multiple inheritance with
> Matthieu> archer. The this pointer changes depending on the base
> Matthieu> class. So how to find the other pointers with the top pointer
> Matthieu> ?
> 
> Tom> I think Value.cast should do the right thing here.  I haven't tried this
> Tom> myself, though... did you try it?  It wasn't clear from your message.
> 

Thank for your answer.

Sorry Value.cast seems to work but my problem is actually a bit more
complex.

I have many classes which implement an interface and inheritate a base
class.

I need to compare pointers to the interface with pointers to the base
class. But these classes are not directly related so Value.cast is
useless. The solution is to up cast the base class pointer to the final
class and then down cast to the interface. But i need run time type
information for that. The typeid operator doesn't seem to be available
in archer.

Here is a new code sample

#include <iostream>

using namespace std;

class BaseClass
{
public:
    BaseClass(int a);

    int m_intA;
};

class Interface
{
public:
    virtual void Method() = 0;
};

class Class1 : public Interface, public BaseClass
{
public:
    Class1(int c);
    
    virtual void Method();

    int m_intC;
};

class Class2 : public Interface, public BaseClass
{
public:
    Class2(int c);

    virtual void Method();

    int m_intC;
};


BaseClass::BaseClass(int a)
{
    cout << "ctor BaseClass :" << hex << this << endl;
    m_intA = a;
}

Class1::Class1(int c) : BaseClass(c+1)
{
    cout << "ctor Class1 :" << hex << this << endl;
    m_intC = c;
}

void Class1::Method()
{
}

Class2::Class2(int c) : BaseClass(c+2)
{
    cout << "ctor Class2 :" << hex << this << endl;
    m_intC = c;
}

void Class2::Method()
{
}


int main()
{
    Class1 c1(1);
    Class2 c2(1);

    Interface* pIc1 = &c1;
    Interface* pIc2 = &c2;
    BaseClass* pBc1 = &c1;
    BaseClass* pBc2 = &c2;

    cout << "@C1 :" << hex << &c1 << endl;
    cout << "@C1 as Interface :" << hex << pIc1 << endl;
    cout << "@C1 as BaseClass :" << hex << pBc1 << endl;
    cout << "@C2 :" << hex << &c2 << endl;
    cout << "@C2 as Interface :" << hex << pIc2 << endl;
    cout << "@C2 as BaseClass :" << hex << pBc2 << endl;

    return 0;
}

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to cast a pointer to a base class with multiple inheritance
  2009-08-03  9:20   ` Matthieu VIAL
@ 2009-08-03 18:30     ` Tom Tromey
  2009-08-04  8:42       ` Richard Ward
  0 siblings, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2009-08-03 18:30 UTC (permalink / raw)
  To: Matthieu VIAL; +Cc: archer

>>>>> "Matthieu" == Matthieu VIAL <matthieu.vial@orange-ftgroup.com> writes:

Matthieu> Sorry Value.cast seems to work but my problem is actually a bit more
Matthieu> complex.

Ok.

Matthieu> I need to compare pointers to the interface with pointers to
Matthieu> the base class. But these classes are not directly related so
Matthieu> Value.cast is useless. The solution is to up cast the base
Matthieu> class pointer to the final class and then down cast to the
Matthieu> interface. But i need run time type information for that. The
Matthieu> typeid operator doesn't seem to be available in archer.

Nope.  The Python API just exposes things that already exist in gdb.
typeid is not implemented yet, there's a bug for it:

http://sourceware.org/bugzilla/show_bug.cgi?id=9065


However, gdb does have "set print object on"... if this prints the right
thing for you, I think we could hook up the internal code to find the
"real object" as a Value method.

Tom

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to cast a pointer to a base class with multiple inheritance
  2009-08-03 18:30     ` Tom Tromey
@ 2009-08-04  8:42       ` Richard Ward
  2009-08-04 11:40         ` Matthieu VIAL
  2009-08-10 21:12         ` Tom Tromey
  0 siblings, 2 replies; 7+ messages in thread
From: Richard Ward @ 2009-08-04  8:42 UTC (permalink / raw)
  To: archer

I have a patch I've been meaning to submit for a while, it adds
gdb.Value.rtti_type which returns the run time type of an object (as a
gdb.Type) using similar code to `set print object on'. The object can
then be cast using gdb.Value.cast.
I'm not at the right pc just now, but I'll try and mail it to this
list later today.

Just in case it helps in the mean time, it is possible to look at the
first 4 (8 on 64-bit) bytes of an object which has a vtable (which
should be a pointer to the vtable), and run `addr2line -Cfe
name-of-executable 0xBLAHBLAH' which should then say something like
`0xBLAHBLAH: vtable for class FOO'. I think you can also find the
vtable this way using nm or objdump, there may be a similar way to do
this within gdb, but I wouldn't know how. Sorry if these instructions
are rough/wrong, I'm at a non gnu/linux machine at the moment.

Richard Ward.


2009/8/3 Tom Tromey <tromey@redhat.com>:
>>>>>> "Matthieu" == Matthieu VIAL <matthieu.vial@orange-ftgroup.com> writes:
>
> Matthieu> Sorry Value.cast seems to work but my problem is actually a bit more
> Matthieu> complex.
>
> Ok.
>
> Matthieu> I need to compare pointers to the interface with pointers to
> Matthieu> the base class. But these classes are not directly related so
> Matthieu> Value.cast is useless. The solution is to up cast the base
> Matthieu> class pointer to the final class and then down cast to the
> Matthieu> interface. But i need run time type information for that. The
> Matthieu> typeid operator doesn't seem to be available in archer.
>
> Nope.  The Python API just exposes things that already exist in gdb.
> typeid is not implemented yet, there's a bug for it:
>
> http://sourceware.org/bugzilla/show_bug.cgi?id=9065
>
>
> However, gdb does have "set print object on"... if this prints the right
> thing for you, I think we could hook up the internal code to find the
> "real object" as a Value method.
>
> Tom
>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to cast a pointer to a base class with multiple inheritance
  2009-08-04  8:42       ` Richard Ward
@ 2009-08-04 11:40         ` Matthieu VIAL
  2009-08-10 21:12         ` Tom Tromey
  1 sibling, 0 replies; 7+ messages in thread
From: Matthieu VIAL @ 2009-08-04 11:40 UTC (permalink / raw)
  To: Richard Ward; +Cc: archer

Your explanations sound interesting because for the moment I store rtti
from g++ in my code (with mangling problem).

Then I use the bitpos attribute of gdb.Field to find the appropriate
class in the inheritance tree.

I wrote the following code to have dynamic upcast feature not available
with gdb.Value.cast
May be this kind of feature could be useful in archer ?


--CODE--

def find_class_offset(init, src, dst):
    if str(src) == str(dst):
        return [True, init]
    
    for field in src.fields():
        if field.is_base_class:
            result = find_class_offset(init - field.bitpos / 8,
field.type, dst)
            if result[0]:
                return result
    
    return [False, init]
    

def dynamic_upcast(cast_type, value):
    assert(value.type.code == gdb.TYPE_CODE_PTR)
    
    if (cast_type.code == gdb.TYPE_CODE_PTR) or (cast_type.code ==
gdb.TYPE_CODE_REF):
        src = cast_type.target()
    else:
        src = cast_type
    dst = value.type.target()
    
    result = find_class_offset(0, src, dst)
    
    if not result[0]:
        raise Exception('Invalid dynamic cast')
    else:
        addr = int(str(value), 16)
        addr += result[1]
        eval_str = '(\'%s\'*)0x%X' % (src.tag, addr)
        return gdb.parse_and_eval(eval_str)

-- CODE --


Matthieu



Le mardi 04 août 2009 à 09:41 +0100, Richard Ward a écrit :
> I have a patch I've been meaning to submit for a while, it adds
> gdb.Value.rtti_type which returns the run time type of an object (as a
> gdb.Type) using similar code to `set print object on'. The object can
> then be cast using gdb.Value.cast.
> I'm not at the right pc just now, but I'll try and mail it to this
> list later today.
> 
> Just in case it helps in the mean time, it is possible to look at the
> first 4 (8 on 64-bit) bytes of an object which has a vtable (which
> should be a pointer to the vtable), and run `addr2line -Cfe
> name-of-executable 0xBLAHBLAH' which should then say something like
> `0xBLAHBLAH: vtable for class FOO'. I think you can also find the
> vtable this way using nm or objdump, there may be a similar way to do
> this within gdb, but I wouldn't know how. Sorry if these instructions
> are rough/wrong, I'm at a non gnu/linux machine at the moment.
> 
> Richard Ward.
> 
> 
> 2009/8/3 Tom Tromey <tromey@redhat.com>:
> >>>>>> "Matthieu" == Matthieu VIAL <matthieu.vial@orange-ftgroup.com> writes:
> >
> > Matthieu> Sorry Value.cast seems to work but my problem is actually a bit more
> > Matthieu> complex.
> >
> > Ok.
> >
> > Matthieu> I need to compare pointers to the interface with pointers to
> > Matthieu> the base class. But these classes are not directly related so
> > Matthieu> Value.cast is useless. The solution is to up cast the base
> > Matthieu> class pointer to the final class and then down cast to the
> > Matthieu> interface. But i need run time type information for that. The
> > Matthieu> typeid operator doesn't seem to be available in archer.
> >
> > Nope.  The Python API just exposes things that already exist in gdb.
> > typeid is not implemented yet, there's a bug for it:
> >
> > http://sourceware.org/bugzilla/show_bug.cgi?id=9065
> >
> >
> > However, gdb does have "set print object on"... if this prints the right
> > thing for you, I think we could hook up the internal code to find the
> > "real object" as a Value method.
> >
> > Tom
> >

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to cast a pointer to a base class with multiple inheritance
  2009-08-04  8:42       ` Richard Ward
  2009-08-04 11:40         ` Matthieu VIAL
@ 2009-08-10 21:12         ` Tom Tromey
  1 sibling, 0 replies; 7+ messages in thread
From: Tom Tromey @ 2009-08-10 21:12 UTC (permalink / raw)
  To: Richard Ward; +Cc: archer

>>>>> "Richard" == Richard Ward <richard.j.ward1@googlemail.com> writes:

Richard> I have a patch I've been meaning to submit for a while, it adds
Richard> gdb.Value.rtti_type which returns the run time type of an object (as a
Richard> gdb.Type) using similar code to `set print object on'. The object can
Richard> then be cast using gdb.Value.cast.

Sounds useful.  I'm not sure about the method name, but this is exactly
what I was picturing.

Tom

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2009-08-10 21:12 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-07-31  7:21 How to cast a pointer to a base class with multiple inheritance Matthieu VIAL
2009-07-31 18:03 ` Tom Tromey
2009-08-03  9:20   ` Matthieu VIAL
2009-08-03 18:30     ` Tom Tromey
2009-08-04  8:42       ` Richard Ward
2009-08-04 11:40         ` Matthieu VIAL
2009-08-10 21:12         ` Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).