WinDbg 不显示寄存器值

WinDbg not showing register values

基本上,这与 here 提出的问题相同。

当使用 WinDbg 版本 6.2 及更高版本对机器 运行 Windows 7 或更早版本执行内核调试时,调试器不会在寄存器 window 中显示任何内容。按 Customize... 按钮会出现一个显示 Registers are not yet known.

的消息框

同时,发出 r 命令会导致打印出完全有效的寄存器值。

这种行为的原因是什么,可以解决吗?

TL;DR: 我写了一个扩展 DLL 来修复这个错误。可用 here.

问题

要理解这个问题,我们首先需要了解 WinDbg 基本上只是 Microsoft Windows 符号调试器引擎 的前端,在 dbgeng.dll 中实现.其他前端包括命令行 kd.exe(内核调试器)和 cdb.exe(用户模式调试器)。

引擎实现了我们期望从调试器获得的一切:使用符号文件、读写内存和寄存器、设置断点等。引擎然后通过类似 COM 的接口公开所有这些功能(它们实现 IUnknown 但不是注册组件)。例如,这允许我们编写自己的调试器(就像 this person 那样)。

有了这些知识,我们现在可以对 WinDbg 如何获取目标机器上寄存器的值做出有根据的猜测。

引擎公开了 IDebugRegisters interface for manipulating registers. This interface declares the GetValues method for retrieving the values of multiple registers in one go. But how does WinDbg know how many registers are there? That why we have the GetNumberRegisters 方法。

因此,要检索目标上所有寄存器的值,我们必须执行如下操作:

  1. 调用IDebugRegisters::GetNumberRegisters获取寄存器总数。
  2. 调用IDebugRegisters::GetValuesCount参数设置为寄存器总数,Indices参数设置为NULLStart参数设置为 0.

不过有一个小问题:第二次调用失败 E_INVALIDARG

嗯,打扰一下?怎么会失败呢?特别令人费解的是这个 return 值的文档:

The value of the index of one of the registers is greater than the number of registers on the target machine.

可是我刚才问你寄存器有多少个,怎么会是那个值越界呢?好的,让我们继续阅读文档,也许事情会变得清晰:

If the return value is not S_OK, some of the registers still might have been read. If the target was not accessible, the return type is E_UNEXPECTED and Values is unchanged; otherwise, Values will contain partial results and the registers that could not be read will have type DEBUG_VALUE_INVALID.

(强调我的。)

啊哈!所以也许引擎只是无法读取其中一个寄存器!但是哪一个?结果是引擎在 xcr0 寄存器上阻塞了。来自 Intel 64 和 IA-32 架构软件开发人员手册

Extended control register XCR0 contains a state-component bitmap that specifies the user state components that software has enabled the XSAVE feature set to manage. If the bit corresponding to a state component is clear in XCR0, instructions in the XSAVE feature set will not operate on that state component, regardless of the value of the instruction mask.

好的,所以寄存器控制 XSAVE 指令的操作,它保存 CPU 的扩展功能(如 XMM 和 AVX)的状态。根据 this 页面上的最后评论,该指令需要操作系统的一些支持。尽管评论指出 Windows 7(我正在测试的 VM 运行)确实支持此指令,但手头的问题似乎与 OS 相关,当目标是 Windows 8 时一切正常。

真的,不清楚这个错误是在调试器引擎中,它报告的寄存器多于它可以检索的值,还是在 WinDbg 中,它拒绝在以下位置显示 任何 值如果引擎无法生成 所有 个。

解决方案

当然,我们可以硬着头皮使用旧版本的 WinDbg 来调试旧的 Windows 版本。但这其中的挑战在哪里?

相反,如果唯一失败的寄存器是 xcr0,我会向您展示 debugger extension that solves this problem. It does so by hooking (with the help of this library) 相关的调试器引擎方法和 returning S_OK。否则,它传播失败。该扩展支持运行时卸载,因此如果您遇到问题,您可以随时禁用挂钩。

就是这样,玩得开心!