内核调试的EXDI方式
除了串行口、1394和USB 2.0这些链接方式外,WinDBG还支持一种很特殊的连接方式来做内核调试。这种方式被称为EXDI,通常写为eXDI。简单来说,EXDI是WinDBG与硬件调试器协同工作的一个接口。
《软件调试》的第7章介绍了JTAG调试协议和Intel CPU的JTAG支持,即ITP/XDP接口。ITP调试器借助专用的硬件设备(ITP调试仪)通过CPU的专用信号引脚与CPU通信,实施调试任务。
ITP/XDP调试器都有自己的软件,可以观察内存、设置断点、接收CPU的事件等。但如果使用ITP调试器调试Windows操作系统或者其中的驱动程序时,一个明显的问题便是难以处理调试符号和支持操作系统相关的观察功能,比如WinDBG的那么多个扩展命令所提供的功能。于是,一种很自然的想法便是把ITP调试器当作一种读写数据的特殊连接方式,让其为WinDBG传递数据。
如何实现这一目标呢?这便是设计EXDI接口的起因。EXDI是基于COM技术的,ITP调试器需要实现一个COM服务组件(称为EXDI服务器,EXDI Server),实现规定的接口函数,例如读写内存、IO、设置断点、运行跟踪等。
IeXdiServer : public IUnknown
{
virtual HRESULT Run( void) = 0;
virtual HRESULT Halt( void) = 0;
virtual HRESULT DoSingleStep( void) = 0;
virtual HRESULT ReadVirtualMemory( ... ) = 0;
virtual HRESULT STDMETHODCALLTYPE WriteVirtualMemory( ... ) = 0;
....
};
在WinDBG的启动参数中,支持以EXDI方式来连接内核调试目标,即格式为:
windbg -kx exdi:clsid={EXDI服务组件的类ID}
WinDBG看到此命令行开关后,会初始化COM库,并创建指定的COM组件,也就是以COM客户端的形式来请求EXDI服务组件的服务。创建成功后,便可以调用接口中定义的方法来访问目标系统了。
上图显示了WinDBG通过EXDI成功连接目标系统后的工作场景,命令结果区显示的是执行内存观察命令的结果。
使用以上方式可以在Windows的调试引擎尚未初始化时就开始调试,也可以在操作系统僵死的情况下来继续观察目标系统,例如内存、寄存器和PCI空间等。这种方法的局限是需要硬件调试器(价格在数千美金),而且要求目标系统的主板上要有ITP/XDP接头(或者特制的转接头-interposer)。