WinDbg没有显示寄存器值

时间:2016-03-12 17:52:22

标签: debugging windbg

基本上,这是here提出的问题。

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

的消息框

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

这种行为的原因是什么,可以修复吗?

1 个答案:

答案 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方法。

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

  1. 致电IDebugRegisters::GetNumberRegisters以获取寄存器总数。
  2. 调用IDebugRegisters::GetValuesCount参数设置为寄存器总数,Indices参数设置为NULLStart参数设置为0
  3. 但是有一个小问题:第二次调用失败了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。否则,它传播失败。该扩展支持运行时卸载,因此如果遇到问题,您可以随时禁用挂钩。

    就是这样,玩得开心!