65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (78投票s)

2002 年 9 月 26 日

4分钟阅读

viewsIcon

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

© . All rights reserved.