Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Visual Studio not able to show the value of 'this' in release mode (with debug information)

Original question:

Why is the this pointer 0 in a VS c++ release build?

When breaking in a Visual Studio 2008 SP1 release build with the /Zi (Compiler: Debug Information Format - Program Database) and /DEBUG (Linker: Generate Debug Info, yes) options, why are 'this'-pointers always 0x00000000?

EDIT: Rephrased question:

My original question was quite unclear, sorry for that. When using the Visual Studio 2008 debugger to step through a program I can see all variables, except the local object's member variables. This is probably cause the debugger derives these from the this pointer, but VS always says it's 0x00000000, so it cannot derive the current object's member variables (it does not know the memory position of the object)

When loading a megadump (Like a Windows minidump, but containing the entire memory space of the process), I can look at all my local variables (defined in the function) and entire tree-structures on the heap even I have pointers to.

For example: when breaking in A::foo() in Release mode

'this' will have value 0x00000000
'f_' will show garbage

Somehow this information needs to be available to the process. Is this a missing feature in VS2008? Any other debugger that does handle this properly?

class A
{
  void foo() { /*break here*/ }
  int f_;
};
like image 428
Pieter Avatar asked Jan 11 '11 11:01

Pieter


1 Answers

As some others have mentioned, compiling in Release mode makes certain optimizations (especially eliminating the use of ebp/rbp as a frame pointer) that break assumptions on which the debugger relies for figuring out your local variables. However, knowing why it happens isn't very helpful for debugging your program!

Here's a way you can work around it: at the very beginning of a method call (breaking on the first line of the function, not the opening brace), the this pointer will always be found in a specific register (ecx on 32-bit systems or rcx on 64-bit systems). The debugger knows that and so you should be able to see the value of this right at the start of your method call. You can then copy the address from the Value column and watch that specifically (as (MyObject *)0x003f00f0 or whatever), which will allow you to see into this later in the method.

If that's not good enough (for example, because you only want to stop when a bug manifests itself, which is a very small percentage of the time the given method is called), you can try this slightly more advanced (and less reliable) trick. Usually, the this pointer is taken out of ecx/rcx very early in a function call, because that is a "caller-saves" register, meaning that its value may be clobbered and not restored by function calls your method makes (it's also needed for some instructions that can only use that register for their operand, like REP* and some of the shift instructions). However, if your method uses the this pointer a lot (including the implicit use of referring to member variables or calling virtual member functions), the compiler will probably have saved this in another register, a "callee-saves" register (meaning that any function that clobbers it must restore it before returning).

The practical upshot of this is that, in your watch window, you can try looking at (MyObject *) ebp, (MyObject *) esi, and so on with other registers, until you find that you're looking at a pointer that is probably the correct one (because the member variables line up with your expectation of the contents of this at the time of your breakpoint). On x86, the calle-saved registers are ebp, esi, edi, and ebx. On x86-64, they are rbp, rsi, rdi, rbx, r12, r13, r14, and r15. If you don't want to search all those, you could always try looking at the disassembly of your function prologue to see what ecx (or rcx) is being copied into.

like image 121
Jonathan Klabunde Tomer Avatar answered Oct 12 '22 08:10

Jonathan Klabunde Tomer