How to determine if an object is an instance of certain derived C++ class from a pointer to a base class in GDB?

C++TypesGdbSuperclassInstanceof

C++ Problem Overview


I'm debugging a C++ program with GDB.

I have a pointer to an object of certain class. The pointer is declared to be of some super class which is extended by several sub-classes.

There is no fields in the object to specify the precise class type of this object but some virtual functions (e.g. bool is_xxx()) are defined to tell the class type at runtime.

Is there some way to tell the precise class type of an object in GDB without calling these virtual functions. Calling such functions in GDB may generate confusing result when the program is multi-threaded.

C++ Solutions


Solution 1 - C++

Use ptype. If you use it by itself, you get the declared type of the pointer:

(gdb) ptype ptr
type = class SuperClass {
  // various members
} *

To get the actual type of the object pointed to, set the "print object" variable:

(gdb) set print object on
(gdb) ptype ptr
type = /* real type = DerivedClass * */
class SuperClass {
  // various members
} *

Solution 2 - C++

On my system ptype or whatis also only show the obvious.

(gdb) whatis pObject
type = QObject *

But printing the first entry of the vtable helped me:

(gdb) p /a (*(void ***)pObject)[0]
$4 = 0xb4b4cdf4 <QMessageBox::metaObject() const>

Here the pObject pointed to a QMessageBox which is derived from QObject. This only works if vtable-entry points to a method that is overridden by the derived class.

See also: https://stackoverflow.com/questions/6191678/print-c-vtables-using-gdb

Edit: Printing only the pointer to the vtable works more reliable (though the output uses the mangled name and is not so readable):

(gdb) p /a (*(void ***)pObject)
$5 = 0xb4af33a0 <_ZTV11QMessageBox+8>

Solution 3 - C++

GDB 7.11

As of GDB 7.11, GCC 5.3.1, Ubuntu 16.04, doing just:

p *myBase

on something compiled with:

gcc -O0 -ggdb3

may be enough as it already shows:

$1 = {_vptr.MyBase = 0x400c00 <vtable for MyDerived1+16>}

where MyDerived1 is the current derived class we are looking for.

But if you do in addition:

set print object on

the output is even clearer and looks like:

$1 = (MyDerived1) {<MyBase> = {_vptr.MyBase = 0x400c00 <vtable for MyDerived1+16>}, <No data fields>}

This also affects other commands like:

ptype myBase

which shows:

type = /* real type = MyDerived1 * */
class MyBase {
  public:
    virtual int myMethod(void);
} *

instead of:

type = class MyBase {
  public:
    virtual int myMethod(void);
} *

In this case, there was no indication of the derived type without set print object on.

whatis is similarly affected:

(gdb) whatis myBase
type = MyBase *
(gdb) set print object on
(gdb) whatis myBase
type = /* real type = MyDerived1 * */
MyBase *

Test program:

#include <iostream>

class MyBase {
    public:
        virtual int myMethod() = 0;
};

class MyDerived1 : public MyBase {
    public:
        virtual int myMethod() { return 1; }
};

class MyDerived2 : public MyBase {
    public:
        virtual int myMethod() { return 2; }
};

int main() {
    MyBase *myBase;
    MyDerived1 myDerived1;
    MyDerived2 myDerived2;
    myBase = &myDerived1;
    std::cout << myBase->myMethod() << std::endl;
    myBase = &myDerived2;
    std::cout << myBase->myMethod() << std::endl;
}

Solution 4 - C++

You do not need to call the virtual functions, you can just see the address of the virtual function or vtable. Another way is to use RTTI

Solution 5 - C++

For those who can't get the desired result out of ptype or whatis, you may try to use C++ operator typeid in conjunction with GDB's print.

Here's an example of how to get this working in GDB 9.2:

(gdb) n
19	    Base* pb = new Derived{};
(gdb) p typeid(*pb)
$1 = {_vptr.type_info = 0x7ffff7f9bc98 <vtable for __cxxabiv1::__si_class_type_info+16>, __name = 0x555555556008 <typeinfo name for Derived> "7Derived"}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1101096View Question on Stackoverflow
Solution 1 - C++BetaView Answer on Stackoverflow
Solution 2 - C++JoachimView Answer on Stackoverflow
Solution 3 - C++Ciro Santilli Путлер Капут 六四事View Answer on Stackoverflow
Solution 4 - C++user685684View Answer on Stackoverflow
Solution 5 - C++i cantView Answer on Stackoverflow