使用伪寄存器调试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()因为找不到文件失败的情况下被断下。如果他遇到了其他的错误(比如4could 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]的偏移0x34DWORD 

伪寄存器@TIB

@ERR伪寄存器不是唯一存在的伪寄存器。另一个重要的伪寄存器是@TIB.这是当前的线程信息块。并且在多线程程序的调试中非常有用。如果你在一个会被多个线程调用的函数中添加一个断点。调试器会在每次函数被调用的时候都断下而不管调用的是哪个线程。如果你想单步进入你的代码,调试器会跳到断点,当别的线程调用这个函数的时候。为了解决这个问题,你需要这样来做。要在你期望的线程进入断点,你需要做下面的一些事情。添加@TIBwatch window。你会看到一些值"0x7ffa6000" or "2147115008"。到断点菜单(Alt-F9),选择你设置的断点。添加@TIB==0x7ffa6000条件过滤。这样,你的调试器就只会在执行到这个线程的时候才会进入断点。其它的调用这个线程函数不会触发断点。

这对Windows 98不行。对Windows 98,你需要查看CPU FS寄存器。它对每个线程都是不同的。你可以使用条件:@FS==value

 

posted @ 2011-02-27 16:18  OYJJ  阅读(450)  评论(0编辑  收藏  举报