基本上,这是here提出的问题。
在运行Windows 7或更早版本的计算机上执行内核调试时,使用WinDbg 6.2及更高版本,调试器不会在寄存器窗口中显示任何内容。按Customize...
按钮会弹出一个显示Registers are not yet known
。
同时,发出r
命令会导致打印出完全有效的寄存器值。
这种行为的原因是什么,可以修复吗?
答案 0 :(得分:15)
TL; DR :我写了一个修复bug的扩展DLL。可用here。
要理解这个问题,我们首先需要了解WinDbg基本上只是在dbgeng.dll
内实现的Microsoft Windows Symbolic Debugger Engine 的前端。其他前端包括命令行kd.exe
(内核调试器)和cdb.exe
(用户模式调试器)。
引擎实现了我们对调试器的所有期望:使用符号文件,读写内存和寄存器,设置breakpoitns等。引擎然后通过类似COM的接口公开所有这些功能(它们实现IUnknown但不是注册组件)。例如,这允许我们编写自己的调试器(如this person所做的那样)。
有了这些知识,我们现在可以对WinDbg如何获取目标机器上的寄存器值做出有根据的猜测。
引擎公开IDebugRegisters
接口以操作寄存器。此接口声明GetValues
方法,用于一次性检索多个寄存器的值。但WinDbg如何知道有多少寄存器?这就是为什么我们有GetNumberRegisters
方法。
因此,要检索目标上所有寄存器的值,我们必须执行以下操作:
IDebugRegisters::GetNumberRegisters
以获取寄存器总数。IDebugRegisters::GetValues
,Count
参数设置为寄存器总数,Indices
参数设置为NULL
,Start
参数设置为0
。但是有一个小问题:第二次调用失败了E_INVALIDARG
。
其中一个寄存器的索引值大于目标机器上的寄存器数。
但我刚问你有多少个寄存器,那么这个值怎么会超出范围呢?好吧,让我们继续阅读文档,或许有些事情会变得清晰:
如果返回值不是S_OK,则仍可能已读取某些寄存器。如果目标不可访问,则返回类型为E_UNEXPECTED且值不变; 否则,值将包含部分结果,无法读取的寄存器将具有DEBUG_VALUE_INVALID类型。
(强调我的。)
啊哈!所以也许引擎无法读取其中一个寄存器!但是哪一个?结果发动机在xcr0
寄存器上发出阻塞声。来自 Intel 64和IA-32架构软件开发人员手册:
扩展控制寄存器
XCR0
包含一个状态组件位图,用于指定软件已启用要管理的XSAVE
功能集的用户状态组件。如果在XCR0
中清除了与状态组件对应的位,则无论指令掩码的值如何,XSAVE
功能集中的指令都不会对该状态组件进行操作。
好的,寄存器控制XSAVE
指令的操作,这保存了CPU扩展功能的状态(如XMM和AVX)。根据{{3}}页面上的最后一条评论,该指令需要操作系统的一些支持。虽然评论指出Windows 7(我正在测试的VM正在运行)确实支持此指令,但似乎手头的问题无论如何都与操作系统有关,因为当目标是Windows 8时,一切正常。< / p>
真的,目前还不清楚这个错误是否在调试器引擎中,它报告的寄存器数量多于它可以检索的值,或者在WinDbg中,如果引擎发生故障,它会拒绝显示任何值生成所有。
当然,我们可以咬紧牙关,只需使用旧版本的WinDbg来调试旧版Windows。但那里的挑战在哪里?
相反,我向您呈现一个解决此问题的this。它通过挂钩(在debugger extension的帮助下)相关的调试器引擎方法并返回S_OK
,如果唯一失败的寄存器是xcr0
。否则,它传播失败。该扩展支持运行时卸载,因此如果遇到问题,您可以随时禁用挂钩。
就是这样,玩得开心!