Back in December, I had one post about optimized code debugging. Today I wanted to follow up, and talk about one technique that I have found helpful when debugging native optimized code.

One of the most annoying aspects of native optimized code debugging is that it is difficult to find your objects. Even though the C++ compiler is not allowed to rearrange the fields of your types, it can be extremely difficult to find a pointer to your object or to validate that the pointer is correct, so looking at your object hierarchy can be difficult.

What I want to do is to take advantage of the fact that the debugger can understand vtables. So, for instance, if I have a class 'C' that implements 'I1' and 'I2', and when I look at a pointer (pC) that is supposed to be 'C*', and it shows me something like this:

pC
   I1 {...}
      __vfptr 0x00418b14 const C::`vftable'{for `I1'} *
   I2 {...}
      __vfptr 0x00418afc const C::`vftable'{for `I2'} *

Then I can be pretty sure that 'pC' really is a pointer to a 'C'. On the other hand if either of those vtable pointers look screwy, then the debugger probably can't find pC on the stack.

So if pC is wrong, what should you do? Well, what I do is ask the debugger to pretend that the stack is just a big array of IUnknown pointers, and then I can easily troll through the array looking for what I want.

Quick example:

int __stdcall f(IUnknown* p1, IUnknown* p2, IUnknown* p3)

{

      int f = 12;

      int j = 17;

      IUnknown* l1 = new TComObjectClass<21>();

      IUnknown* l2 = new TComObjectClass<22>();

      IUnknown* l3 = new TComObjectClass<23>();

      IUnknown* l4 = new TComObjectClass<24>();

      IUnknown* l5 = new TComObjectClass<25>();

      IUnknown* l6 = new TComObjectClass<26>();

 

      ...

};

Where TComObjectClass is a template that I whipped together to quickly produce a bunch of types which are COM objects.

To find COM pointers that are around where parameters are normally passed, evaluate: (LPUNKNOWN*)@vframe,10

You can tell that [0] and [1] are not COM objects because the __vfptr is not reasonable. However, [2], [3], and [4] probably are COM objects because their vtable looks like a vtable. You can then dive into the other vtable pointers and other member variables to decide if you really do have a pointer to a COM object.

To find COM pointers around where locals are normally stored, try: (LPUNKNOWN*)esp,40

If 'esp' doesn't look reasonable, you can always try subtracting a bit of @vframe to get into what should be the data area.

Happy debugging…