基本上,这是在这里提出的问题.
当使用WinDbg 6.2及更高版本对运行Windows 7或更早版本的计算机执行内核调试时,调试器不会在寄存器窗口中显示任何内容.按下Customize...按钮会显示一个读取的消息框Registers are not yet known.
同时,发出r命令会导致打印出完全有效的寄存器值.
这种行为的原因是什么,可以修复吗?
Mic*_*sky 15
TL; DR:我写了一个修复bug的扩展DLL.可在这里.
要理解这个问题,我们首先需要了解WinDbg基本上只是微软Windows符号调试器引擎的一个前端,在内部实现dbgeng.dll.其他前端包括命令行kd.exe(内核调试器)和cdb.exe(用户模式调试器).
引擎实现了我们对调试器的所有期望:使用符号文件,读写内存和寄存器,设置breakpoitns等.引擎然后通过类似COM的接口公开所有这些功能(它们实现IUnknown但不是注册组件) .例如,这允许我们编写自己的调试器(就像这个人一样).
有了这些知识,我们现在可以对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).据对最后评论此页面,这个指令需要从操作系统的一些支持.虽然评论声明Windows 7(我正在测试的VM正在运行)确实支持此指令,但似乎手头的问题无论如何都与操作系统有关,因为当目标是Windows 8时,一切正常.
实际上,不清楚这个错误是否在调试器引擎内,它报告的寄存器数量多于它可以检索的值,或者在WinDbg中,如果引擎无法生成所有这些错误,它将拒绝显示任何值.
当然,我们可以咬紧牙关,只需使用旧版本的WinDbg来调试旧的Windows版本.但那里的挑战在哪里?
相反,我向您展示了一个解决此问题的调试器扩展.它通过挂钩(在此库的帮助下)相关的调试器引擎方法并返回S_OK失败的唯一寄存器来实现xcr0.否则,它传播失败.该扩展支持运行时卸载,因此如果遇到问题,您可以随时禁用挂钩.
就是这样,玩得开心!
| 归档时间: |
|
| 查看次数: |
1695 次 |
| 最近记录: |