Viewing types, part 2: the manual way

Compiling with /d1reportAllClassLayout, even an empty file, dumps many compiler-intrinsic types. Six of these are interesting in the present context:  _PMD, _TypeDescriptor, _s__RTTIBaseClassDescriptor2, _s__RTTIBaseClassArray, _s__RTTIClassHierarchyDescriptor, and _s__RTTICompleteObjectLocator.

Most of this machinery exists solely for multiple inheritance, and virtual inheritance in particular – which modern languages eschew and is considered (I hope) a painful legacy by all current C++ professionals, and so I won’t go further in. Go here for an excellent survey on these deep internals of multiple inheritance and RTTI.

Turns out that for viewing types in sane (== single inheritance) code, two of these intrinsic types suffice:

1> class _TypeDescriptor    size(8):
1>      +—
1>   0    | pVFTable
1>   4    | spare
1>   8    | name
1>      +—
1>
1> class _s__RTTICompleteObjectLocator    size(20):
1>      +—
1>   0    | signature
1>   4    | offset
1>   8    | cdOffset
1>  12    | pTypeDescriptor
1>  16    | pClassDescriptor
1>      +—

The gem mentioned above tells us that an RTTICompleteObjectLocator pointer is placed right before the vftable. (This struct is responsible for locating the adjoint vftable within a larger vftable in the case of multiple inheritence, where method dispatching requires adjustor thunks, dynamic-casts require traversal of the full inheritance tree and things get hairy in general.  Not another word on that, I swear).

RTTICompleteObjectLocator contains a pointer to a TypeDescriptor, which happily points to a name!   To view this in the debugger, take a typed pointer (say, pb -sticking with the setup from last time), and type at a watch window

(_s__RTTICompleteObjectLocator**)((int*)pb->__vfptr – 1)

Here’s what you’d see:

image

That is (naturally) a decorated name, so pop open a VS command prompt and call undname.exe with the 0x2000 flag (decipher types) and that name string, omitting the leading ‘.’ :

image

And now, for something completely useful.

All the above may seem like a very roundabout – albeit cool – way of seeing what the debugger already shows, but this does present a very useful trick:

What if you don’t have symbols?

It is very easy to recognize dispatching of virtual functions (call on a register argument), and typically a few instructions before that $ecx would be populated with the ‘this’ pointer.  Now, you can know the name of the type whose methods you call, even without symbols!   (assuming the code was built with RTTI on).

E.g., around this virtual method call:

image

Type this at a watch window:

(_s__RTTICompleteObjectLocator**)(*(uintptr_t*)$ecx-sizeof(int*))

(some complexity added to conform also to x64 systems, thanks @Martin Ridgers!), and you’ll be greeted be a magnificent view:

image

About these ads

3 comments on “Viewing types, part 2: the manual way

  1. […] Last time a way was shown to use internal RTTI mechanics to view C++ type names without direct debugger aid. There is one place in particular where such type names carry substantial information, and that is c++ exceptions. These can also require some additional treatment. […]

  2. Martin Ridgers says:

    Interesting trick.

    One small comment – you should really cast to uintptr_t* rather than int*. Then the technique doesn’t make assumptions about pointer size and will work for both x86 and x64 code.

    • Ofek Shilon says:

      True, thanks. The ‘4’ offset should also really be ‘sizeof(int*)’. I was actually aware of this when writing but decided to drop the extra generality. I’ll fix it soon.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s