如何使用WinDbg分析VC++应用程序的崩溃转储?

48

如何使用WinDbg分析转储文件?

4个回答

74

以下是一些通用步骤,可帮助您开始:

首先,您必须更改编译器的设置,以便即使在发布版本中也创建PDB文件。最新版本的Visual C++编译器默认情况下会执行此操作,但在许多旧版本的Visual C++中,您必须自己完成此操作。创建程序数据库文件,然后将这些文件的存档与每个应用程序构建一起保存。每个应用程序构建都必须有自己的一组PDB非常重要。例如,您不能仅使用使用第10次构建时生成的相同PDB来检查由第15次构建生成的转储。在项目的整个生命周期中,您将拥有大量的PDB,请为此做好准备。

接下来,您需要能够确定生成转储文件的应用程序的确切版本。如果您正在创建自己的MiniDump(例如通过调用 MiniDumpWriteDump()),那么最简单的方法可能是将MiniDump文件名中的部分作为应用程序的完整版本号。您需要有一个合理的版本编号方案才能使此方法起作用。在我的商店中,每次自动构建器创建构建时,我们将构建编号在所有分支上递增一次。
现在,您已经从客户那里收到了转储文件,知道了创建转储的应用程序的精确版本,并找到了此版本的PDB文件。
现在,您需要浏览源代码控制的历史记录并找到与该软件精确版本相对应的源代码。做到这一点的最佳方法是每次进行构建时将“标签”应用于您的分支。将标签值设置为精确版本号,就可以在历史记录中轻松找到它。
您已经准备好启动WinDbg / Visual C++:
  1. 获取您应用程序的该版本的完整源代码树。将其放在硬盘上的另一个位置,例如 c:\app_build_1.0.100,表示应用程序版本1.0构建#100。
  2. 获取该确切版本的应用程序二进制文件并将它们放在硬盘上的某个位置。最简单的方法可能是安装该应用程序的该版本以获取二进制文件。
  3. 将PDB文件放在步骤2中二进制文件的同一位置。

现在您有两种查看转储文件的选项。您可以使用Visual Studio或WinDbg。使用Visual Studio更容易,但WinDbg更加强大。大多数情况下,Visual Studio中的功能就足够了。

要使用Visual Studio,您只需像打开项目一样打开转储文件即可。一旦打开,“运行”转储文件(默认情况下为F5),如果所有路径都设置正确,它将带您直接到崩溃的代码,提供调用堆栈等信息。

要使用WinDbg,您必须跨过几个障碍:

  1. 启动 WinDbg
  2. 打开转储文件。(默认情况下按 Ctrl + D
  3. 告诉 WinDbg 获取正确的 Microsoft 符号文件。键入 .symfix。这可能需要一些时间,因为它会从互联网上下载大量内容。
  4. 告诉 WinDbg 符号(PDB 文件)的位置。键入 .sympath+ c:\pdblocation,将 PDB 文件的路径名替换为您放置它们的位置。确保在 .sympath+ 之间没有空格,并且加号在那里,否则您将破坏第3步。
  5. 告诉 WinDbg 源代码的位置。键入 .srcpath c:\app_build_1.0.100,将获取软件此版本的源代码的路径替换为该路径。
  6. 告诉 WinDbg 分析转储文件。键入 !analyze -v

几秒钟后,如果一切都配置正确,WinDbg将带您直接到崩溃位置。此时,您有无数选项来深入挖掘应用程序的内存空间、关键部分的状态、窗口等等。但这超出了本文的范围。

祝好运!


非常感谢您提供的详细信息。我会尝试按照您的步骤操作,那么.symfix命令会有任何输出吗?我们如何知道命令是否执行完成? - Hara
状态栏中有一个“繁忙”指示器,告诉您WinDbg正在忙于处理您的命令。除此之外,除非您收到错误消息,否则您将不会收到表示命令已完成的响应。但是,请注意来自!analyze -v的输出。如果您没有任何模块的正确PDB,则它会抱怨。 - John Dibling
使用符号索引和源代码索引将有助于定位匹配的PDB文件和源代码。此外,该索引支持Visual Studio和WinDbg。 - Thomson
@Thomson:我不确定我知道你在说什么,但如果你能通过回答详细说明一下,我相信这会极大地增强这个问题。这个问题得到了很多关注。 - John Dibling
@JohnDibling,谢谢。这个链接(http://blogs.msdn.com/b/buckh/archive/2011/04/11/making-debugging-easier-source-indexing-and-symbol-server.aspx)将有助于解释索引概念。简而言之,图像和PDB可以通过在编译时生成的GUID关联起来,因此将所有发布二进制文件的PDB存储到某个结构中,然后WinDbg可以正确地定位正确的版本。源代码索引是将源代码版本和源代码控制服务器记录到PDB中,因此当加载具有私有符号的PDB时,WinDbg可以自动打开正确的版本。 - Thomson
1
能否在不同时向二进制文件添加大量调试信息的情况下创建.PDB文件? - Violet Giraffe

42

(请参见下面的“转储”部分)

WinDbg基本教程和演示

不同的“启动”/附加WinDBG方式

工作区

了解工作区的工作原理...

Cmdtree

"cmdtree"允许您定义一个“菜单”,以便轻松访问常用命令,而无需记住简短的命令名称。

您不必将所有命令定义放入同一个cmdtree文本文件中...如果您愿意,可以将它们分开并加载多个文件(然后它们就会有自己的窗口)。

启动脚本

您可以在命令行上使用-c选项,在启动WinDBG时自动运行WinDBG脚本。
该选项可以打开DML(调试器标记语言)模式,加载特定扩展程序,设置.NET异常断点,设置内核标志(例如,在内核调试时,您可能需要更改DbgPrint掩码以便查看跟踪信息....ed nt!Kd_DEFAULT_Mask 0xffffffff),加载cmdtrees等。
以下是示例脚本:
$$ Include a directory to search for extensions
$$ (point to a source controlled or UNC common directory so that all developers get access)
.extpath+"c:\svn\DevTools\WinDBG\Extensions"
$$ When debugging a driver written with the Windows Driver Framework/KMDF
$$ load this extension that comes from the WinDDK.
!load C:\WinDDK\7600.16385.1\bin\x86\wdfkd.dll
!wdftmffile C:\WinDDK\7600.16385.1\tools\tracing\i386\wdf01009.tmf
$$ load some extensions
.load msec.dll
.load byakugan.dll
.load odbgext.dll
.load sosex
.load psscor4
$$ Make commands that support DML (Debugger Markup Language) use it
.prefer_dml 1
.dml_start
$$ Show NTSTATUS codes in hex by default
.enable_long_status 1
$$ Set default extension
.setdll psscor4
$$ Show all loaded extensions
.chain /D
$$ Load some command trees
.cmdtree c:\svn\DevTools\WinDBG\cmdtree\cmdtree1.txt
.cmdtree c:\svn\DevTools\WinDBG\cmdtree\cmdtree2.txt
$$ Show some help for the extensions
!wdfkd.help
!psscor4.help
.help /D

命令速查表

扩展

“扩展”允许您扩展WinDBG支持的命令/功能范围。


3
我刚刚为了你的答案收藏了这个页面..!! :) - Bharathi

5

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接