调试器一览
下面大概介绍了你可以从微软网站上下载到的调试器:
· KD-内核调试器。你可以用它来调试蓝屏一类的系统问题。如果是开发设备驱动程序是少不了它的。
· CDB-命令行调试器。这是一个命令行程序
· NTSD-NT调试器。这是一个用户模式调试器,可以用来调试用户模式应用程序。它实际上是一个CDB的windows UI增强。
· WinDbg-用一个漂亮的UI包装了KD和NTSD。WinDbg即可以调试内核模式,也可以调试用户模式程序。
· VS, VS.net-使用同KD和NTSD相同的调试引擎,并且相比于同样用于调试目的的WinDbg,提供了功能更丰富的界面。
调试器之间的比较
功能 |
KD |
NTSD |
WinDbg |
Visual Studio .NET |
内核模式调试 |
Y |
N |
Y |
N |
用户模式调试 |
Y |
Y |
Y |
|
非托管调试 |
Y |
Y |
Y |
Y |
托管调试 |
Y |
Y |
Y |
|
远程调试 |
Y |
Y |
Y |
Y |
附加到进程 |
Y |
Y |
Y |
Y |
从进程分离 |
Y |
Y |
Y |
Y |
SQL调试 |
N |
N |
N |
Y |
winDbg是一个强大的基于windows平台的调试工具,它可以进行内核模式和用户模式的调试。
winDbg提供源码级的基于Windows内核、内核模式的驱动、系统服务、用户模式的应用程序和驱动调试。
winDbg源码级调试使用的是Microsoft VisualStudio符号格式,它可以访问PDB符号文件中的任何符号或者变量,可以访问COFF符号文件模块中的外部函数名。
winDbg可以查看源码、设置断点、查看变量值(包括C++目标文件)、堆栈跟踪和内存。它的命令窗口可以接受很多命令。
对于内核模式的调试,winDbg需要2台机器(宿主机和目标机),这种调试模式仅支持基于NT的Windows操作系统。
winDbg同时也支持变量的远程调试在用户模式和内核模式的目标机下。
WinDbg还可以调试Dump文件。
Debugging Tools and Symbols: Getting Started
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
Common WinDbg Commands (Thematically Grouped)
http://windbg.info/doc/1-common-cmds.html
Getting started with WinDbg and Sos.dll
http://rynsim.spaces.live.com/blog/cns!1DA5A63F849536B6!671.entry
二、WinDbg Download And Install:
Install Debugging Tools for Windows 32-bit Version
http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx
Install Debugging Tools for Windows 64-bit Versions
http://www.microsoft.com/whdc/devtools/debugging/install64bit.mspx
windbg有个好处,随便找个机器下载下来后,直接copy到同样32或64位机器上就可以用了,这点在某些客户那里很管用。因为server上一般不许访问internet,你可以在其他机器上下载下来,然后copy到server上即可。
三、WinDbg Configuration:
1、Set Symbols Path:
winDbg本身不会自动识别符号文件,需要我们手动配置符号文件的位置。
Symbol File Path...... Ctrl+S
Source File Path...... Ctrl+P
Image File Path...... Ctrl+I
可以从http://msdn.microsoft.com/en-us/windows/hardware/gg463028或者http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx下载对应操作系统版本的符号文件并安装,然后设置其路径。
c:\winnt\symbols;SRV*c:\winnt\symbols*http://msdl.microsoft.com/download/symbols
其中c:\winnt\symbols为你的符号文件安装的位置,这样winDbg会先从这里面查找符号文件,如果找不到则会到http://msdl.microsoft.com/download/symbols符号文件库查找并下载。
(这里要注意下载的Symbols的版本一定要正确)否则提示提示“PDB symbol for mscorwks.dll not loaded;Defaulted to export symbols for ntdll.dll”的错误。
source file path 和imagefile path 就是源码文件和可执行文件的路径。
首先需要通过环境变量_NT_SYMBOL_PATH来配置符号文件的定位,可以从微软的网站上去下载,也可直接指定网站地址,让CDB和Windbg需要时自己去找,各自如此设置:
set _NT_SYMBOL_PATH = D:\debug\symbols;D:\debug\WindowsXP-KB835935-SP2-symbols
set _NT_SYMBOL_PATH = srv*c:\symbols*http://msdl.microsoft.com/download/symbols
注意:除了操作系统符号文件的定位,你也需要设置自己的程序的调试信息(*.pdb文件)的定位,如上例中的D:\debug\symbols。
2、Check Symbols Set:
打开windbg.检查环境变量设置是否成功:
Method One:
1) file->open Executable操作中打开c:\windows\notepad程序。
2)在windbg的命令窗口中录入"lm”命令,列出进程加载的dll.
3)找到ntdll行,如果如下显示,则表明成功,否则需要重新设置环境变量。【注意Pdb文件的位置根据环境变量不同,可能不一样。】
7c920000 7c9b6000 ntdll (pdb symbols) F:\symbol\ntdll.pdb\99192024C5EB4830AC602195086637082\ntdll.pdb
Method Two:
1)检查sympath是否正确
.sympath
2)查找相应的模块信息
!lmi truecrypt
3)检查符号表加载详细情况
!sym noisy
3、Load sos.dll:
SOS.dll中提供的 Son of Strike 扩展 (SOS),用于调试 WinDbg 中的托管代码。SOS是为了方便调试.NET程序的一个add-in。
在启动了调试程序并将其附加到托管进程(或加载故障转储)后,可以通过键入以下代码加载 SOS.dll:
.loadby sos mscorwks
如果您正在调试的应用程序使用的是不同版本的 mscorwks.dll,则该命令无法执行,那么应找到该应用程序使用的 mscorwks.dll 版本的 SOS.dll,然后运行以下命令:
.load <path_to_sos>\sos.dll
SOS.dll 随 .NET Framework 安装在 %windir%\microsoft.net\framework\<.NET 版本> 目录下。SOS.dll 扩展提供了大量用于检查托管堆的有用命令。有关所有这些命令的文档,请参阅SOS 调试扩展 (SOS.dll)。
在.net framework 1.x下面,直接在windbg的命令行里面,执行.load clr10\sos.dll即可。
在.net framework 2.0里,可以到%windir%\microsoft.net\framework\v2.0.50727下面,把sos.dll,复制到windbg安装目录下面。
我一般是这样:在windbg目录下面,创建一个目录叫做clr20,然后copy sos.dll %programfiles%\debugg~1\clr20。弄好后,加载命令是一样的:.load clr20\sos.dll即可。
So the problem here is that we do not guarantee that newer versions of SOS will be able to debug older versions of CLR. You must match the version of SOS
to the version of the runtime (unless we are explicitly giving them private bits for SOS to fix a bug in it). From the output below, !eeversion is telling you that the one that won’t walk the stack does not match the runtime’s version. This is why it won’t
walk the stack.
We always try to make SOS backwards compatible, but it’s not something we guarantee.
4、Check SOS Load:
加载SOS后,使用命令.chain来查看调试链中是否已经成功包含SOS扩展
!DumpAllExceptions
!DumpHeap -type Exception
5、Load Silverlight SOS:
调试.NET程序,需要在Windbg中加载调试扩展项sos.dll。Silverlight的运行时(runtime)是CoreCLR,因此必须加载CoreCLR对应的sos.dll(不能使用.NET Framework自带的sos.dll)。获得正确sos.dll的方法是安装Silverlight Tools for Visual Studio(3.0,4.0)。如果安装了正确的sos.dll,在Windbg中可用如下命令将其加载。0:023>.loadby sos coreclr
四、WinDbg Command:
WindDbg主要以命令方式工作,主要有三类命令:标准命令,元命令和扩展命令。
1. 标准命令
通常是一到二个字符或符号。
a: 调试
g----------恢复运行
t--------- 单步步入
p----------单步步过
b: 观察修改寄存器
r---------观察修改寄存器
c: 观察栈的命令
k---------观察栈调用
d: 断点
BP----------软件断点
BA----------硬件断点
BL----------列出所有断点
BC----------清除断点
BD---------禁止断点
BE---------重新启用断点
e: 显示和控制现场: ~
f:显示进程: |
g: 显示表达式: ? 显示C++表达式: ??
h: 汇编: a, 反汇编: u
i: 显示段选择字: dg
j: 符号命令:
检查符号---------x
搜索符号---------ln
显示块列表------lm
k: 结束----------q
l: dd,db,dw命令和od中的一样
2. 元命令
内建在windug中。
3.扩展命令
在动态加载的扩展模块实现
4. 基本要点
-
直接回车可以重复上一条命令
-
使用;号可以在同一行输入多条命令
-
使用上下方向键可以浏览和选择以前输入过的命令
-
元命令以.号开始,扩展命令以!号开始
-
使用Ctrl+Break来终止一个长时间未完成的命令。
5. 注释
winDbg支持两种方法加入注释。 一是使用*命令, 二是使用$$命令。使用前应该在前一条命令后加分号作为分隔。*后所有的命令都会被注释, $$可以用分号结束。
五. 使用WinDbg:
可以参考:Help->Contents->Debugging Tools for Windows->Debuggers->Debugger Reference,该目录下列集了所有指令机器功能说明。
调试场景
远程调试
使用WinDbg进行远程调试是很容易的,而且有很多种可行的方法。在下文中,’调试服务器’指的是运行在你所要调试的远程机器上的调试器。’调试客户端’指的是控制当前会话的调试器。
· 使用调试器:你需要CDB, NTSD或者WinDbg已经安装在远程机器上。WinDbg客户端可以连接到CDB, NTSD或者WinDbg中的任何一个作为服务器,反之亦然。在客户端和服务器直接可以选择TCP或者命名管道作为通讯协议。
o 在服务器端的启动过程:
§ WinDbg –server npipe:pipe=pipename(注:可以允许多个客户端连或
§ 从WinDbg内部: .server npipe:pipe=pipename(注,连接单个客户端)
你可以用多种协议开启不同的服务会话。并且可用密码来保护一个会话。
o 从客户端连接:
§ WinDbg -remote npipe:server=Server, pipe=PipeName[,password=Password]
§ 从WinDbg内部: File->Connect to Remote Session: for connection string, enter npipe:server=Server, pipe=PipeName [,password=Password]
· 使用Remote.exe:Remote.exe使用命名管道作为通讯的方式。如果你使用的是一个命令行接口的程序,比如KD,CDB或者NTSD。你可以使用remote.exe来远程调试。注意:使用@q(不是q)来退出客户端,不用关掉服务端。
o 要启动一个服务端:
§ Remote.exe /s “cdp –p <pid>” test1
o 从客户端连接:
§ Remote.exe /c <machinename> test1
上面的test1是我们所选择的命名管道的名字。
服务端会显示那个客户端从那个服务器连接以及执行过的命令。你可以使用‘qq’命令来退出服务端;或者使用File->Exit来退出客户端。另外,如果要进行远程调试,你必须属于远程机器的”Debugger User”组并且服务器必须允许远程连接。
即时调试
在WinDbg的文档的”Enabling Postmorten Debugging”部分对此有很详细的讨论。简而言之,你可以把WinDbg设置成默认的即时调试器,命令就是:Windbg –I。这个命令实际上是把注册表中 HKLM/Software/Microsoft/Windows NT/CurrentVersion/AeDebug的键值设置成WinDbg。如果要把WinDbg设置成为默认的托管调试器,你需要显示设置如下的注册表键值:
- HKLM/Software/Microsoft/.NETFramework/DbgJITDebugLaunchSetting 设置成 2
- HKLM/Software/Microsoft/.NETFramework/DbgManagedDebugger 设置成Windbg.(注意其中的启动参数设置)
通过JIT的设置,当一个应用程序在不是调试的状态下抛出了未处理的异常之时,WinDbg就会被启动。
64位调试
所有这些调试器均支持在AMD64和IA64上的64位调试环境。
托管应用程序的调试
WinDbg 6.3以后的版本支持在Widbey(VS2005和.net 2.0的内部开发代号) .net CLR托管调试。在文档中针对托管调试有很好的讨论。需要注意的是,对于托管程序来说,没有刚才所说的PDB(译注:托管代码实际上也是有PDB的,但是这个PDB实际上记录了C#代码和IL代码的对应关系以及相关的一些信息)的概念,因为所有的程序都是编译成为ILASM。调试器通过CLR来查询所需的附加信息。
有几点需要注意:
你只能在托段函数的代码被执行过至少一次之后才能设置断点。只有这样它才能被编译成汇编代码。记住以下的几点:
· 关于函数的地址的复杂化以及对应的断点设置:
o CLR有可能丢弃已经编译好的代码,所以函数的入口地址有可能改变。
o 同样的代码有可能被多次编译,如果多个应用程序域没有共享这段代码的话。如果你设置了一个断点,它就会被设置在当前线程(译注:CLR的逻辑线程)所在的应用程序域内。
o 泛型的特殊实例可能导致同一个函数有不同的地址。.
· 数据存储布局的复杂化以及对应的数据检查:
- CLR可能会在运行的时候任意改变数据的存储布局,所以一个结构体成员的偏移量可能会被改变掉. (译注:实际上是在一个类型被加载的时候决定的数据布局,之后是不会改变的。)
- 一个类型的信息是在第一次使用的时候被加载,所以你可能不能够查看一个数据成员如果它还没有被使用过.
· 调试器命令的复杂化
o 当跟踪托管代码的时候,你会需要穿越大段的CLR自己的代码比如JIT编译器的代码,原因可能是你第一次进入一个函数,或者是你在托管和非托管代码之间进行切换。
调试Windows服务
使用WinDbg,你可以像调试其它应用程序那样调试Windows服务程序。即可以通过附加进程的方法启动Windows服务,也可以把WinDbg当作一个即时调试器,并且在代码中调用DbgBreakPoint
或者DebugBreak
,或者在
x86
机器上加入一条
int 3
汇编指令。
调试异常
一个调试器会得到两次的异常通知-第一次在应用程序有机会处理异常之前(‘first chance exception’);如果应用程序没有处理这个异常,这时候调试器就会有机会来处理异常(‘second-chance exception’)。如果调试器没有处理二次机会的异常,应用程序就会退出。
.lastevent或者,!analyze –v命令会给你显示异常的记录以及异常抛出所在函数的堆栈跟踪信息。
你也可以使用 .exr, .cxr以及 .ecxr命令来显示异常和上下文记录。同时需要注意的是,你也可以改变first-chance的处理选项。对应的命令就是:sxe, sxd, sxn和sxi。
在live debugging一个托管进程时, BPMD无法定下断点的问题的解决方案
SharePoint 2010的某些DLL会被进行一种叫做Pre-compiling的优化, 所使用的工具叫做Ngen.exe. 优化过后, 托管的dll会被制作为native image, 之后呢Runtime每次都会使用native image, 而不是传统的托管DLL. 这种优化可以加快DLL的加载, 因为需要执行代码的很多动作都被提前做好了.
然而, 这样的优化会给在WinDBG中Live Debugging这样的任务制造困难. 由于使用的是native image, 像BPMD这样的命令就无法定义断点了.
解决方案
================
修改注册表键值, 关掉这种优化.
1) 打开如下的注册表键值: HKLM\Software\Microsoft\.NET Framework\
2) 添加一个 DWORD 值, 名字叫做"ZapDisable”, 然后赋值为 1
3) 重启目标进程
关于Native Image的更多信息
===============
Native Image Generator (Ngen.exe)
http://msdn.microsoft.com/en-us/library/6t9t5wcf%28VS.71%29.aspx
在WinDBG中, 使用.shell命令来搜索字符串
对于我来说, 使用WinDGB时最有用的命令之一就是.shell命令了.
Debugging Tools For Windows帮助文件说:
.shell命令能加载一个shell进程, 并重定向它的输出到debugger中, 或者重定向到一个指定的文件里.
那么为什么我觉得加载一个shell进程会对日常工作有帮助呢? 加载shell进程最简单最常用的功能就是搜索字符串. 你也许会想, 为什么不在debugger里使用Ctrl + F来寻找字符串呢? 因为这样用会节省你的时间.
在shell里查找字符串, 我们需要使用DOS中的命令Find这个老朋友. 使用命令find /?来查看帮助文件.
下面的命令就是一个例子: 在lm命令的结果中搜索一个字符串"SharePoint".
本来lm (List Loaded Modules)命令会列出所有的module的, 结果又几十条, 查找起来非常不便. 用.shell命令Find一下子就找到了自己想要的模块.
.shell -ci "lm" find /I "SharePoint"
参数-ci用于指定命令"lm"的输出结果被用来做find命令的输入.
摘译自:
Windbg: Using .shell to search text
http://blogs.msdn.com/b/baleixo/archive/2008/09/06/using-shell-to-search-text.aspx
如何在进程创建的过程中Attach上WinDBG
在排查服务启动时错误的时候, debugger会运行在后台, 我们无法与之交互. 因为服务是运行在一个不同的winstation里的, 这意味着我们不能通过desktop与它们交互. 这也意味着, 已经加载了的debugger即使在运行, 也是运行在后台, 我们无法与它交互.
解决方案是进入services.msc, 找到这个服务的属性, 让它使用local system账号运行, 然后勾选选项"allow interact with the desktop".
但是, IIS的工作者进程worker process与服务进程一样, 都是在后台诞生的, 要命的是, 我们没有机会去勾选什么allow interact with the desktop. 这意味着debugger也会在后台被加载, 我们还是无法与它交互.
解决方案不止一种, 但是下面这种比较有趣.
cdb.exe和windbg.exe都能够创建TCP sockets(或者说是named pipes connection), 然后监听它们, 这样前台的debugger就能够连接到后台被debug的进程的debugger上, 它们共享一个debugging session. 这里我们就用这种socket的特性来在后台的winstation和w3wp.exe一起的debugger和前台的debugger之间创建一个隧道.
让我们一步一步来:
第一步:
设置应用程序image的执行选项, 从而允许在这个image的实例诞生的时候, 我们的第一个debugger能够附着到worker process上.
要做到这一点, 我们需要在注册表中创建下面的键值对:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\w3wp.exe
SZ Debugger = “c:\debuggers\cdb.exe –cf c:\debuggers\cmds.txt”
这里假设, 你的Debugging Tools For Windows安装在c:\debuggers文件夹.
第二步:
配置debugger自动地开启一个socket供以后使用.
注意上面cdb.exe命令行中的 "-cf " 选项, 它会告诉cdb.exe在debugger刚刚attach到目标进程的时候, 从某个指定的文件中读取并执行一些初始化的命令. 所以我们需要创建一个叫做cmds.txt的文本文件, 把它放在c:\debuggers目录下. 这个文件的内容是像下面这样的.
.logopen c:\debuggers\debugging.log
.server tcp:port=9999
g
保存文件. 关于debugger使用的这些命令, 请查看下面的说明.
.logopen - 任何在这个debugging session中发生的事情都会记录在这个新开启的日志文件中.
.server tcp:port=9999 - 监听在9999端口上的TCP Socket.
g - 继续执行
第三步:
开启应用程序池, 并发送个它至少一个请求.
当w3wp.exe进程创建出来之后, 你就能够通过任务管理器看出来你同时还有cdb.exe也在运行, 但是你不能直接的访问它.
第四步:
运行你的第二个debugger, 并连接到Socket上.
运行WinDGB.exe, 并传递给它一个像下面命令这样的-remote参数:
Windbg.exe -remote tcp:Port=9001,Server=MYSERVER
上面的MYSERVER应该被你的机器名所取代.
搞定啦~~~ windbg.exe已经连接到有cdb.exe创建出来的socket上了, 你现在可以从头开始对你w3wp.exe进行live debug了!
祝你debugging愉快~
翻译自:
How to attach a debugger from the creation time of the Worker Process (w3wp.exe)
Windbg 自动加载到启动的进程
有时候你的dll需要注入到别人的exe中,自己的dll注入到别人的exe中经常需要exe在启动的时候就能够使用windbg来查看当前情况,两步就可以完成。以要注入的exe名称为ABC.exe为例:
首先在注册表中创建一项,在HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Image File Execution Options/下创建名为 ABC.exe的项。
然后在新创建的这一项下创建一个字符串值Debugger,值为windbg的位置:"C:/Program Files/Debugging Tools for Windows/windbg.exe"。
ok,双击运行ABC.exe的时候windbg就会自动Attach它了。介绍SOS中的SaveModule命令
这个命令允许你把一个已经加载到内存中的一个镜像(DLL, EXE)写回到一个文件中. 这非常有用, 尤其是你在debugging一个full memory dump, 并且没有原始的exe或dll的时候. 这个命令通常用来保存一个托管二进制信息到一个文件中, 稍后你就可以使用Reflector来反汇编里面的代码了.
首先, 使用lm命令来获得image的base address.
0:000> lm
start end module name
00400000 00408000 image00400000 (deferred)
10200000 102ac000 MSVCR80D (deferred)
5a000000 5a0b1000 mscoree (deferred)
5a140000 5a29e000 mscorjit (deferred)
5b660000 5c440000 mscorlib_dll (deferred)
5d1d0000 5e13c000 mscorwks (deferred)
我们需要一份mscorwks.dll的拷贝, 我们可以运行:
0:000> !SaveModule 5d1d0000 c:\pub\out.tmp
4 sections in file
section 0 - VA=1000, VASize=e82da9, FileAddr=400, FileSize=e82e00
section 1 - VA=e84000, VASize=24d24, FileAddr=e83200, FileSize=ec00
section 2 - VA=ea9000, VASize=5a8, FileAddr=e91e00, FileSize=600
section 3 - VA=eaa000, VASize=c183c, FileAddr=e92400, FileSize=c1a00
在debugging第三方的托管组件时, 这个命令可以让你看一下第三方的组件的源代码, 以便你分析引发问题的可能的原因.
使用WinDBG排查应用程序加载时崩溃的问题
假设有个应用程序, 一启动就崩溃, 根本就来不及让你用Visual Studio来Attach, 并且该应用程序在使用Visual Studio直接lunch的情况下又不会出现这样的问题, 该怎么办呢?
除了使用<<在进程崩溃的时候自动抓取一个DUMP文件>>中的方法, 还可以使用WinDBG直接加载应用程序的可执行文件, 然后在应用程序退出的系统函数上下断点, 从而得到退出时的call stack.
让我们用notepad.exe作为例子吧.
首先, 使用Open Executable来打开notepad.exe的可执行文件.
然后, 运行下面的两条命令, 在程序退出的函数上设置断点.
bp Kernel32!ExitProcess
bp Kernel32!TerminateProcess
然后输入命令"g". 等待它异常退出时, 会进入断点, 然后是用"k"命令来得到call stack.
WinDbg Quick Links
Download: WinDbg (32-bit) WinDbg (64-bit)
Debugging Tools for Windows MSDN Help
Symbol Server (Microsoft):
srv*c:/mss*http://msdl.microsoft.com/download/symbols
Symbol Server (Citrix):
srv*c:/css*http://ctxsym.citrix.com/symbols
Use .symfix+ folder
for example, .symfix+ c:/mss
WinDbg cheat sheet for crash dump analysis
CMDTREE.TXT for .cmdtree WinDbg command corresponding to Crash Dump Analysis Checklist
Common WinDbg Commands (Thematically Grouped) by Robert Kuster
Command Checklist Sorted by Space (U - user; K - kernel; A - both; S - WinDbg scripts)
WinDbg Books
Windows Debugging: Practical Foundations
x64 Windows Debugging: Practical Foundations
Advanced Windows Debugging (The Addison-Wesley Microsoft Technology Series)
Memory Dump Analysis Anthology, Volume 1 (The OpenTask Crash Dump Analysis Series)
Memory Dump Analysis Anthology, Volume 2 (The OpenTask Crash Dump Analysis Series)
Memory Dump Analysis Anthology, Volume 3 (The OpenTask Crash Dump Analysis Series)
WinDbg: A Reference Poster and Learning Cards
Windows Internals: Including Windows Server 2008 and Windows Vista, Fifth Edition
Debugging Microsoft .NET 2.0 Applications