如何用WinDbg帮你诊断应用程序或系统故障
关键字: Debug WinDbg Dump Crash ShutDown
摘要:本文首先介绍了WinDbg的使用基础,包括安装配置、基本命令和网络支持;然后介绍其主要工作过程:Attach、Dump两种工作方式和Kernel-mode、User-mode两种调试模式;最后给出几个典型案例,演示如何用WinDbg解决问题。
1 关于WinDbg
1.1 简介
WinDbgis a multipurposed debugger for MicrosoftWindows, distributed on the web by Microsoft. It can be used todebuguser modeapplications, drivers, and theoperatingsystem itself inkernel mode. It is aGUI application, but haslittle in common with the more well-known, but less powerful,Visual Studio Debugger.
——from http://en.wikipedia.org
WinDbg与KD,CDB,andNTSD属于DebuggingTools for Windows工具集合,许多命令写法一致,但它们的适用场合不同,详见MSDN。
WinDbg可以进行内核态和用户态调试,可以在线调试(Attach方式)、离线分析(Dump方式)。即使是用户态也很多调试功能是VS没有的,因而WiKi才有“It is aGUIapplication, but has little in common with the more well-known, but lesspowerful,Visual Studio Debugger.”。
个人认为WinDbg主要优势在于解决下列问题:
(1) Kernel模式:系统问题,无论大小,都要找WinDbg;
(2) User模式:偶发性故障、隐藏较深的问题、多线程、缺乏源代码等;
更多介绍:
Wiki
http://en.wikipedia.org/wiki/WinDbg
Debugging Tools and Symbols: GettingStarted(建议直接从本地Help文档进入)
http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx
A word for WinDbg(写得深入浅出,作者谦虚了)
http://mtaulty.com/communityserver/blogs/mike_taultys_blog/archive/2004/08/03/4656.aspx
1.2 安装
选择正确的版本,新版的WinDbg都归DebuggingTools for Windows旗下:
Debugging Tools for Windows 32-bit Version
http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx
Debugging Tools for Windows 64-bit Versions
http://www.microsoft.com/whdc/devtools/debugging/install64bit.mspx
安装很简单,一路Next即可。
2使用基础
2.1 配置Symbols路径
我们来看看为什么要Symbols?怎样加载Symbols?
Symbols是你调试程序、分析Dump的重要基础,否则你无法查看Stack Trace、变量内容、设置断点,所以要为你分析的模块加载正确的Symbol文件。对于个人模块,若采用VC++、VS编译,就是你项目的.pdb文件;而系统的一些模块,需要从微软的符号服务器上下载。
Symbols分为几种类型:
Symbolsare typically either private symbols (include variable information),retailsymbols (function information but not variable information) orexportsymbols(generally not so useful for debugging purposes). If you’re debugging with“export” symbols it’s not usually enough to actually work out what’s going on.
——from A word for WinDbg
配置方法有多种,这里介绍最简便的:
在File->Symbol FilePath里设置
MyCodeSymbolDir; SRV* MyLocalSymbolDir*http://msdl.microsoft.com/download/symbols
当然不是直接复制,要根据你自己的情况稍作修改,MyCodeSymbolDir配置成你自有模块的.pdb文件路径,也可以加多个目录,用分号分开即可;MyLocalSymbolDir是你下载系统符号文件目录,建议通过官网一次性下载到你指定的目录;至于分号后面长的怪怪的一串也自有用处SRV* MyLocalSymbolDir*http://msdl.microsoft.com/download/symbols,告诉WinDbg到哪里下载缺失的Symbol文件。如果你是调试自己的应用程序的话,建议你将自己应用程序的*.pdb文件的路径放在前面这样对Windbg来说查找起来比较快。
你可能会遇到点小困难,常常无法加载符号表。运气好,按下面的方法操作即可,运气差些,你可能需要重启机器才能解决问题,运气更差的话请求助网络支持(参考http://www.189works.com/article-14826-1.html)。
另外,若有源文件,还可以配置一下源文件路径:
File->Symbol File Path,在弹出的窗口里指定你的源代码文件的路径,路径格式只要符合Windows操作系统的格式即可,可以指定多个,中间以分号间隔。
2.2 基础命令
(1)断点指令:BP,BM,BA,BL,BC,BD,BE
BP 在指定的地址设置断点。bpnotepad!WinMain,在Notepad的WinMain函数处下断点。断点的位置可以用符号表示,也以直接使用地址及Windbg的Pseudo-Register(虚拟寄存器),如$exentry表示进程的入口点,可以使用bp@$exentry在进程的入口点设置断点,对于Notepad当前入口点为01006420,也可以直接 bp 01006420,等效于bp notepad!WinMainCRTStartup.
BM 使用模式匹配设置断点。需要符号表支持。bm值一提,在符号表合法的情况下(符号表中包含私有符号的时候),bm可能通过模式一次下多个断点,bmmydriver!FastIo*指定可以将所有与FastIo*模式相匹配的函数下断点,如FastIoRead,FastIoWrite等。但是bm需要full or export symbols支持,Microsoft的提供的符号表不是都支持的,通常我们自己编译的程序的符号表(Windbg显示为private pdb symbols)默认是支持的。
BA (Break on Access)。顾名思义,对内存访问下断点。对于在多核或多处理器调试的时候很有用,对于调试多线程也很有用,应该说用处很多,比如对一个全局变量设置断点,ba mydriver!gMonitoredDevices,如果你认为这个变量的值被莫名的修改了,相信通过BA设置的断点,你很快就能找到是谁修改的。
BL(List),BC(Clear),BE(Enable),BD(Disable)
这四个指令是分别用于列表,清除,开启和禁用断点,也是使用非常频繁的指令。
条件断点(BP + J)
以上所提到的断点指令通过与J指令很容易形成条件断点。比如:
bpUSER32!GetMessageW "r $t1=poi(esp+4);r $t2=poi(@$t1+4); j(@$t2 = 0x102 )'du @$t1+8 L2;gc';'gc'"
这个条件断点,截取WM_CHAR消息,并将字符(包括中文)显示出来。条件断点的最简形式:
bp Address"j (Condition) 'OptionalCommands'; 'gc' "
Address是指令的地址,Condition是一个条件表达式,如果@eax=1,'OptionalCommands'是在断点被击中并且表达式成立时要执行的指令;gc指定是从一个条件断点返回,是不可少的一部分。
(2)数据查看指令 d{a|b|c|d|D|f|p|q|u|w|W}
这些指令区分大小。
d{b|c|d|D|f|p|q}分别是显示以下数据:
db: byte&ASCII,
dc: double-word&ASCII,
dd: double-word,
dD: double-precision,
df: float,
dp: pointer-sized,
dq: quad-word;
DA: 用于显示ASCII,
DU: 用于显示UNICODE;
BYB: 显示binary和Byte
BYD: 显示binary和DWORD
另外,DV,用于查看本地变量用。
(3)栈指令k[b|p|P|v|d]
这些指令区分大小(仅第二个字母区分)。
这四条指令显示的内容类似,但是每个指令都有特色。kb显示三个参数,kp显示所有的参数,但需要Full Symbols或Private PDB Symbols支持。kP与kp相似,只是kP将参数换行显示了。kv用于显示FPO和调用约定。kd用于显示Stack的Dump,在跟踪栈时比较有用。
(4)数据修改指令e{b|d|D|f|p|q|w}
详见WinDbg帮助文档。
(5)反汇编指令u,uf
u Address L10 从Address处反汇编十条指令
0:001> u@$exentry L10
uf Function 汇编整个Function函数
0:000> ufGe