使用伪寄存器在 MSVC++ 中进行调试的介绍






4.94/5 (78投票s)
2002 年 9 月 26 日
4分钟阅读

307010
对调试器伪寄存器(如 @ERR、@TIB)的解释
引言
让我们从我写这篇文章的原因开始。有一天,一位同事请我帮助他调试他遇到的一个问题。当我看着他单步调试代码时,我注意到下面这行代码:
int test = GetLastError();
他这样做是因为他想知道上一个函数是否失败,以及失败时的错误代码。他每次想知道错误代码时都会添加这行代码。我建议他删除所有这些行,并在他的监视窗口中使用 @ERR
伪寄存器。他不知道这是什么,询问办公室里的其他人,很多人也不知道。因此,我为从未听说过伪寄存器的朋友们写了这篇文章。
到底什么是伪寄存器?
伪寄存器不是实际的硬件寄存器,但它显示起来就像硬件寄存器一样。通过伪寄存器,您可以在调试器中查看和使用某些值(错误代码、线程信息块等)。
让我们来看一下 @ERR
伪寄存器。用您最喜欢的自编应用程序启动调试器。在您的代码中设置一个断点,以便调试器会中断执行。如果监视窗口尚未打开,请打开它(右键单击工具栏上的空白区域,然后从列表中选择“监视”)。在监视窗口中添加 @ERR
。您应该会在“值”列中看到 0
。现在单步执行您的代码,并观察这个值。它将始终显示当前线程的 GetLastError()
号码。因此,如果您的代码中出现问题,这个值就会改变。
如果您想测试这一点,但您的代码中没有任何错误,我建议您添加一些错误(但别忘了事后删除)。您可以插入类似这样的代码:
FILE *fp = fopen("c:\\a_file_that_does_not_exist.txt", "r");
如果您单步执行这行代码,您将看到 @ERR
的值变为 2
。转到“工具 -> 错误查找”可以查看此错误值表示的含义(如果您想知道的话,“系统找不到指定的文件
”)。像我一样懒惰的人,以及像您一样聪明的人,可以将 @ERR
伪寄存器更改为 @ERR,hr
。这样做会将伪寄存器的值更改为错误字符串。这样您甚至不必查找错误。我一直将 @ERR,hr
保留在监视窗口中。
条件表达式
伪寄存器也可以用于条件表达式。要尝试这一点,请在 fopen
之后添加以下行:
if (fp)
{
fclose(fp);
}
在 if (fp)
行上设置一个断点。转到“编辑 -> 断点”(或按 Alt-F9)。选择您刚刚插入的断点,然后按“条件”按钮。在这里,您可以输入 @ERR==2
条件。现在启动调试器。如果 fopen()
因找不到文件而失败,调试器将在该断点处中断。如果文件确实存在,即使它遇到了其他错误(例如错误 4:无法打开文件),调试器也不会中断。通过创建和删除 c:\ 上的“a_file_that_does_not_exist.txt”文件,然后运行(而不是单步执行)代码来测试这一点。
仅为非常好奇(并且与本文无关)的朋友们:@ERR
是做什么的?它如何获取错误号?结果发现,@ERR
所做的与 GetLastError()
所做的完全相同。这些函数只有大约 3 行汇编代码:
mov eax,fs:[00000018h]
mov eax,dword ptr [eax+34h]
ret
因此,@ERR
会从指向 fs:[18h]
的线程环境块中偏移量为 0x34 的 DWORD
值中获取信息。
@TIB 伪寄存器
@ERR
伪寄存器并非唯一存在的。另一个重要的伪寄存器是 @TIB
。这是当前线程的线程信息块,在多线程调试中非常有用。如果您在一个被多个线程调用的函数中设置断点,无论哪个线程经过断点,调试器都会中断执行。即使您正在单步调试代码,如果另一个线程调用了该函数,调试器也可能会跳转到断点。要解决这个问题,您需要执行以下操作。如果执行中断在您想要的线程中,请在监视窗口中添加 @TIB
。您将看到一个值,例如“0x7ffa6000
”或“2147115008
”(普通显示)。转到断点菜单(Alt-F9)并选择断点。现在您可以添加 @TIB==0x7ffa6000
条件过滤器。这样做,调试器将只为该线程中断执行。使用相同函数的所有其他线程都不会导致中断。
这在 Windows 98 中不起作用。对于 Windows 98,您需要查看 Intel CPU 的 FS 寄存器,该寄存器对每个线程都是唯一的。您可以使用表达式 @FS==value
。
伪寄存器完整列表
伪寄存器 | 描述 |
@ERR | 最后一个错误值;与 GetLastError() API 函数返回的值相同 |
@TIB | 当前线程的线程信息块;这是必需的,因为调试器不处理“FS:0”格式 |
@CLK | 未文档化的时钟寄存器;只能在监视窗口中使用 |
@EAX , @EBX , @ECX , @EDX , @ESI , @EDI , @EIP , @ESP , @EBP , @EFL | Intel CPU 寄存器 |
@CS , @DS , @ES , @SS , @FS , @GS | Intel CPU 段寄存器 |
@ST0 , @ST1 , @ST2 , @ST3 , @ST4 , @ST5 , @ST6 , @ST7 | Intel CPU 浮点寄存器 |
[摘自 John Robbins 的《调试应用程序》]
致谢
- John Robbins 的《调试应用程序》一书
许可证
本文未明确附加许可证,但可能包含文章正文或下载文件本身的使用条款。如有疑问,请通过下方的讨论板与作者联系。作者可能使用的许可证列表可在此处找到:here。