60

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.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
user1101096
  • 699
  • 2
  • 6
  • 7
  • I'm no gdb wiz, but you might be able to traverse the v-table pointer (which is what your base class pointer is literally pointing to) and resolve the name of the functions. – selbie Dec 16 '11 at 02:06
  • @selbie consulting the v-table is exactly what ptype does under the hood if {set print object on} is active, as Beta pointed out in his/her answer – Tom Regner Dec 16 '11 at 15:35

5 Answers5

67

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
} *
Beta
  • 96,650
  • 16
  • 149
  • 150
23

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: 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>
Community
  • 1
  • 1
Joachim
  • 891
  • 9
  • 12
  • The [second entry in the vtable](http://stackoverflow.com/questions/5712808/understanding-the-vtable-entries) points at the `type_info`. This is always overriden. – MSalters Jun 02 '15 at 14:49
8

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;
}
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
1

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"}
i cant
  • 401
  • 2
  • 9
1

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

user685684
  • 182
  • 7