使用伪寄存器调试MSVC++程序的介绍--An introduction to debugging in MSVC++ using Pseudoregisters
对于伪寄存器,百度到的结果很少,翻译此篇供各位同学参考吧。
原文链接:
http://www.codeproject.com/KB/debug/pseudoregister.aspx
介绍:
下面介绍一下我写这篇文章的原因。今天我的一个同事让我帮他调试一个他遇到的问题。我看他单步他的程序的时候,发现了下面的代码:
int test = GetLastError();
他这样做因为他希望如果之前的函数失败了能够知道错误码。我建议他移除这些行并且在Watch Window中使用伪寄存器@ERR。他不知道这是什么,并且问周围的同事,周围的很多人也不知道。所以我决定为那些从来没有听说过伪寄存器的人们写这篇文章。
到底什么是伪寄存器呢?
伪寄存器不是真正的硬件寄存器,但是他显示起来就像硬件寄存器一样。使用伪寄存器你可以在调试器中看到并使用一些值(错误码,线程模块信息)。
让我们来开看一看伪寄存器@ERR。调试任意一个你写好的应用程序。在你的代码中添加一个断点。打开Watch Window(如果没有的话),右击工具条的空白处,选择Watch。在Watch Window中添加@ERR。这是你会在Value那一列看到0。这时再单步你的程序,来观察他的值。它总是会显示当前线程的GetLastError()的数值。所以,如果任何地方有问题的话,它的值会改变。
如果你想测试一下,但是你的代码缺没有任何的错误,我建议你加上一些代码(但是别忘了之后将他们移除)。你可以插入下面这样的代码:
FILE *fp = fopen("c://a_file_that_does_not_exist.txt", "r");
如果你单步过这一行,你会看到@ERR的值变为2.到Tools->Error Lookup去查错误码到底是什么意思。("The system cannot find the file specified" 系统找不到指定的文件)。还有一些像我一样的懒人,或者聪明的家伙会将@ERR 伪寄存器改成@ERR,hr,这样做将会把伪寄存器的值变为错误字符串。这样你就不用去查错误码了。我总是将@ERR,hr保留在watch window中。
条件表达式
伪寄存器可以用来作为条件表达式。要试一下的话,在fopen之后添加下面几行代码:
if (fp)
{
fclose(fp);
}
在if (fp) 这一行加一个断点。Go to Edit->Breakpoints(或者按F9)选择你刚添加的断点。并且单击"Condition"按钮。在这输入条件 @ERR==2。这是再启动调试器。这是调试器只会在fopen()因为找不到文件失败的情况下被断下。如果他遇到了其他的错误(比如4:could not open the file,不能打开文件)。尝试在创建文件之后运行代码,然后删除c:/下的文件"a_file_that_does_not_exist.txt"。
仅仅是因为好奇(否则完全与这篇文章无关);@ERR做了些什么?它是怎样获得错误码的。事实上,@ERR做了和GetLastError() 相同的事情。这些函数只有三行汇编代码:
mov eax,fs:[00000018h]
mov eax,dword ptr [eax+34h]
ret
所以 @ERR 获取了当前线程环境中指向fs:[18h]的偏移0x34的DWORD 值
伪寄存器@TIB
@ERR伪寄存器不是唯一存在的伪寄存器。另一个重要的伪寄存器是@TIB.这是当前的线程信息块。并且在多线程程序的调试中非常有用。如果你在一个会被多个线程调用的函数中添加一个断点。调试器会在每次函数被调用的时候都断下而不管调用的是哪个线程。如果你想单步进入你的代码,调试器会跳到断点,当别的线程调用这个函数的时候。为了解决这个问题,你需要这样来做。要在你期望的线程进入断点,你需要做下面的一些事情。添加@TIB到watch window。你会看到一些值"0x7ffa6000" or "2147115008"。到断点菜单(Alt-F9),选择你设置的断点。添加@TIB==0x7ffa6000条件过滤。这样,你的调试器就只会在执行到这个线程的时候才会进入断点。其它的调用这个线程函数不会触发断点。
这对Windows 98不行。对Windows 98,你需要查看CPU FS寄存器。它对每个线程都是不同的。你可以使用条件:@FS==value 。