Visual Studio无法在发布模式下显示“this”的值(带有调试信息) [英] Visual Studio not able to show the value of 'this' in release mode (with debug information)

查看:100
本文介绍了Visual Studio无法在发布模式下显示“this”的值(带有调试信息)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

原始问题:



为什么在VS c ++版本构建中此指针为0?



在使用/ Zi(编译器:调试信息格式 - 程序数据库)和/ DEBUG(链接器:生成调试信息,是)选项的Visual Studio 2008 SP1版本构建中打开时,为什么'指针总是0x00000000?



EDIT:改写的问题:



很不清楚,对不起。当使用Visual Studio 2008调试器来浏览一个程序时,我可以看到除了本地对象的成员变量之外的所有变量。这可能是因为调试器从这个指针导出这些,但VS总是说它是0x00000000,所以它不能导出当前对象的成员变量(它不知道对象的内存位置)



当加载一个megadump(像一个Windows minidump,但包含整个进程的内存空间),我可以看看我的所有局部变量(在函数中定义)和堆上的整个树结构我有指针。



例如:当在释放模式下打开A :: foo this的值将为0x00000000

'f_'将显示垃圾



不知何故,此信息需要可用于进程。这是VS2008中缺少的功能吗?

  class A 
{
void foo(){/ * break here * /}
int f_;
};


解决方案

正如其他人提到的,某些优化(特别是消除了使用ebp / rbp作为帧指针),它们破坏了调试器依赖于找出局部变量的假设。但是,知道为什么会发生这种情况对于调试程序并不是很有帮助。



这里有一种方法可以解决它:在方法调用的开始在函数的第一行,而不是开始括号), this 指针将始终位于特定寄存器(ecx在32位系统上,或rcx在64位系统上)位系统)。调试器知道,所以你应该能够在方法调用开始时看到 this 的值。然后,您可以从Value列复制地址,并具体地观察(作为(MyObject *)0x003f00f0 或其他),这将允许你看到

如果这还不够好(例如,因为你只想在错误显示时停止,这是给定方法被调用的时间的非常小的百分比),你可以尝试这个稍微更高级(和更不可靠)的伎俩。通常,在函数调用中非常早就从ecx / rcx中取出 this 指针,因为这是一个调用者保存寄存器,意味着它的值可能被破坏并且不会通过您的方法调用的函数调用恢复(对于某些可以使用该寄存器作为其操作数的指令,如REP *和一些移位指令也需要这样做)。但是,如果你的方法使用这个指针很多(包括隐含地使用引用成员变量或调用virtual成员函数),编译器可能会保存 this 在另一个寄存器,callee-saves寄存器(意味着任何函数,clobbers它必须恢复它在返回之前)。



这实际的结果是,在你的观察窗口,你可以尝试看看(MyObject *)ebp (MyObject *)esi ,等等与其他寄存器,直到你发现你正在看一个指针,可能是正确的(因为成员变量符合你的期望的内容 this 在你的断点时)。在x86上,calle保存的寄存器是ebp,esi,edi和ebx。在x86-64上,它们是rbp,rsi,rdi,rbx,r12,r13,r14和r15。如果你不想搜索所有这些,你总是可以尝试看你的函数prologue的反汇编看看什么ecx(或rcx)被复制到


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_;
};

解决方案

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.

这篇关于Visual Studio无法在发布模式下显示“this”的值(带有调试信息)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆