首先下载最新的windbg,然后下载symbols
在windbg的快捷方式的“目标”处填上 "D:/Program Files/Debugging Tools for Windows/windbg.exe" -y C:/ -b -k com:port=//./pipe/com_1,baud=115200,pipe
设置vmware虚拟机,虚拟一个串口,把主机,虚拟机的波特率都设置为115200
先打开虚拟机,在boot.ini里加上 multi(0)disk(0)rdisk(0)partition(1)/WINDOWS="Microsoft Windows XP Professional" /debug /debugport=com1 /baudrate=115200
然后选择调试运行,虚拟机会停止,等待windbg发出 g 命令。
打开windbg,出现断点提示,输入 g,虚拟机继续运行。
在需要调试的驱动工程选项里,选择linker,进入debugging,选中generate debug info,在generate program database里输入 $(TargetDir)$(TargetName).pdb,然后编译工程。
把驱动和应用程序考到虚拟机,
进入windbg,输入 bu driverName!DriverEntry, 其中driverName是驱动的名字,DriverEntry是需要中断的函数名,这样如果驱动运行,就会在DriverEntry处停止。
启动驱动,虚拟机会停止,windbg会自动响应,打开这个驱动的源码文件,并且停止在DriverEntry处。这时,可以单步运行调试。
几种添加断点的命令:
? 普通断点
最简单的设置断点的方法就是通过bp (“Breakpoint”)命令。例如:
bp MyDriver!xyz
bp f89adeaa
第一行,这个断点设在模块中的一个名字(<module>!<name>);第二行,它被设置在一个给出的地址。当运行到其中一个断点时,操作系统就会挂起,并且把控制权交给WinDbg。(你可以在“寻找名字”看看如何为第二个命令取得地址。)
注意:第一个命令的语法假定操作系统已经加载该模块,以及在symbol文件或者外部名定义有足够可用信息关于识别xyz。如果不能在模块中找到xyz,调试器会这么告诉你这些。
? 延迟断点
说到驱动程序没有被加载,你最初的哪个断点,使用bu(见上述开始调试示例驱动)设置的是一个“可延迟的”断点。Bu命令的参数是一个模块及它里面的名字,例如:
bu sioctl!SioctlDeviceControl
? 另外一个设置一般断点的方法是通过source窗口。当你中断于DriverEntry,将光标移动到需要停止的代码,按下F9,这样驱动就会在这停止。
你可以使用bl (“Breakpoint List”)查看所有已设置的断点:每个断点都有一个号码并且显示出断点状态,“e”是“enabled”,而“d”是“disabled”。
当程序停止时,可以使用dv 查看一个已知变量(Irp是查看的变量。):
kd> dv Irp,显示 Irp = 0xff70fbc0,该响应的意思是,Irp 变量包含0xFF70FBC0。该响应基于变量内容,而不是地址。你可以确认它:
kd> ?? Irp
struct _IRP * 0xff70fbc0
?? 总是以C++ 为基础
kd> ? Irp
Evaluate expression: -141181880 = f795bc48
这表示变量Irp 位于0XF795BC48。你可以通过使用dd (详见 dd 命令)显示内存数据,确认该变量真的包含数据0xFF70FBC0。
kd> dd f795bc48 l1
f795bc48 ff70fbc0
以及内存指向这里:
kd> dd 0xff70fbc0
ff70fbc0 00940006 00000000 00000070 ff660c30
ff70fbd0 ff70fbd0 ff70fbd0 00000000 00000000
ff70fbe0 01010001 04000000 0006fdc0 00000000
ff70fbf0 00000000 00000000 00000000 04008f20
ff70fc00 00000000 00000000 00000000 00000000
ff70fc10 ff73f4d8 00000000 00000000 00000000
ff70fc20 ff70fc30 ffb05b90 00000000 00000000
ff70fc30 0005000e 00000064 0000003c 9c402408
查看象IRP这样的变量,
kd> dt Irp
Local var @ 0xf795bc48 Type _IRP*
0xff70fbc0
+0x000 Type : 6
+0x002 Size : 0x94
+0x004 MdlAddress : (null)
+0x008 Flags : 0x70
+0x00c AssociatedIrp : __unnamed
+0x010 ThreadListEntry : _LIST_ENTRY [ 0xff70fbd0 - 0xff70fbd0 ]
+0x018 IoStatus : _IO_STATUS_BLOCK
+0x020 RequestorMode : 1 ''
+0x021 PendingReturned : 0 ''
+0x022 StackCount : 1 ''
+0x023 CurrentLocation : 1 ''
+0x024 Cancel : 0 ''
+0x025 CancelIrql : 0 ''
+0x026 ApcEnvironment : 0 ''
+0x027 AllocationFlags : 0x4 ''
+0x028 UserIosb : 0x0006fdc0
+0x02c UserEvent : (null)
+0x030 Overlay : __unnamed
+0x038 CancelRoutine : (null)
+0x03c UserBuffer : 0x04008f20
+0x040 Tail : __unnamed
? 在当前例程中显示一个变量(当前的“scope”),使用dv
kd> dv
DeviceObject = 0x82361348
Irp = 0xff70fbc0
outBufLength = 0x64
buffer = 0x00000000 ""
irpSp = 0xff70fc30
data = 0xf886b0c0 "This String is from Device Driver !!!"
ntStatus = 0
mdl = 0x00000000
inBufLength = 0x3c
datalen = 0x26
outBuf = 0x00000030 ""
inBuf = 0xff660c30 "This String is from User Application; using METHOD_BUFFERED"
这是一个参数变量列表以及一些在断点位置已知的变量。“已知”是一个重要的限定词。例如如果一个变量优化成一个寄存器,它将不会被显示,尽管可以反汇编它(View=>Disassembly 打开反汇编窗口)并且检查寄存器。
如果只关心一个变量,你可以:
kd> dv outBufLength
outBufLength = 0x64
显示结构体内的某个值 kd> ?? irp->type
显示当前线程的错误值:!gle会显示当前线程的上一个错误值和状态值。!error命令可以解码HRESULT。