应用程序崩溃时自动内存转储
配置自动内存转储并手动遍历堆栈。
引言
我们可以让调试器在应用程序崩溃时自动弹出。这种调试器称为事后调试器(post mortem debugger)或即时(JIT)调试器,它们还可以自动生成崩溃内存转储。一些事后调试器包括 WinDbg、VS 6.0/NET 和 Dr. Watson。在本文中,我们将使用 WinDbg 调试器并解释如何
- 将其配置为事后调试器,
- 自动生成内存转储文件,以及
- 在应用程序崩溃时遍历其内存堆栈。
将 WinDbg 配置为事后调试器
- 从 Microsoft 调试器网站 此处下载 WinDbg。
- 将其安装到合适的目录。
- 要将事后调试器更改为 WinDbg,请运行
WinDbg -I
。(请注意,I
必须大写。)此命令在使用后会显示成功或失败消息。当 WinDbg 是事后调试器时,它会在应用程序崩溃时激活。
(如果您尚未重新配置 Windows 的事后调试设置,则默认使用 Dr. Watson 作为事后调试器。此设置可以通过编程方式或通过注册表更改;任何更改都会立即生效。)
配置自动内存转储
要将 WinDbg 设置为在程序崩溃时自动生成内存转储文件,需要编辑注册表。在 x86 计算机上,事后调试设置存储在 \\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug
键下。这些键下应该有两个注册表值:
Debugger
:此REG_SZ
值指定将处理事后调试的调试器。必须列出调试器的*完整路径*,除非调试器位于默认路径中的某个目录中。Auto
:此REG_SZ
值始终为0
或1
。如果设置为0
,则在事后调试之前会显示一个消息框。
当发生未处理的应用程序错误时,Windows 会检查 Debugger
和 Auto
注册表值是否存在。如果 Auto
值为 0
,则会显示一个消息框。在 Windows NT 和 Windows 2000 上,消息框将具有以下格式之一:
- 如果
Debugger
值包含有效调试器或 Dr. Watson 的名称,则消息框将有两个按钮:OK
和Cancel
。如果按下OK
按钮,应用程序将终止。如果按下Cancel
按钮,将启动Debugger
值中指定的工具。 - 如果
Debugger
值为空,则消息框将只有一个OK
按钮,并且不会启动调试器。
注册表示例
更改之前,注册表项可能为
Debugger = "Path\windbg.exe" -p %ld -e %ld -g
要自动生成转储文件,请按所示修改注册表 Debugger
项。
Debugger = "Path\WinDbg.exe" -p %ld –c ".dump /ma /u C:\CrashDump.dmp" -e %ld –g
注释
- 请小心进行注册表更改。执行 test.exe 以验证注册表更改是否正确。运行 test.exe 时,应用程序将自动打开调试器并在 C:\ 目录中生成 crashdump.dmp 文件。
-c
选项应紧跟在-p %ld
之后。- 信息摘自“使用 Windows 调试工具”帮助文件。
-c "command"
指定启动时运行的初始调试器命令。此命令必须用引号括起来。多个命令可以用分号分隔。(如果您有一长串命令,则可能更容易将它们放入脚本,然后使用-c
选项配合$<(Run Script File)
命令。)
参数
您可以根据需要更改命令的参数。
选项可以是以下任意数量的组合:
/o
- 允许调试器覆盖同名的先前转储文件。如果未包含此选项且文件名已被使用,则不会写入转储文件。/f
- 内核模式:使调试器创建完整的内存转储。
- 用户模式:使调试器创建完整的用户模式转储。
. dump /mf
或. dump /ma
将创建比. dump /f
更大、更完整的转储文件。/m [MiniOptions]
- 使调试器创建小型内存转储(内核模式)或迷你转储(用户模式)。如果未指定/f
或/m
,则默认为/m
。在用户模式下,
/m
后面可以跟额外的 MiniOptions,用于指定应包含在转储中的额外数据。如果没有包含 MiniOptions,则转储将包含模块、线程和堆栈信息,但没有额外数据。以下任何 MiniOptions 都可以添加以更改转储文件的内容;它们区分大小写。
MiniOption Effect a
创建带有所有可选附加信息的迷你转储。 /ma
选项等同于/mfhuFt
— 它为迷你转储添加了完整的内存数据、句柄数据、已卸载的模块信息、基本内存信息和线程时间信息。f
为迷你转储添加完整的内存数据。将包含目标应用程序拥有的所有可访问的已提交页面。 F
为迷你转储添加所有基本内存信息。这会向迷你转储添加一个流,其中包含所有基本内存信息,而不仅仅是有效内存的信息。这允许调试器在调试迷你转储时重建进程的完整虚拟内存布局。 h
为迷你转储添加与目标应用程序相关的句柄数据。 u
为迷你转储添加已卸载的模块信息。这仅在 Windows Server 2003 中可用。 t
为迷你转储添加额外的线程信息。这包括线程时间,可以使用 .ttime
(显示线程时间)在调试迷你转储时显示。i
为迷你转储添加辅助内存。辅助内存是通过堆栈或后备存储上的指针引用的任何内存,以及该地址周围的一小块区域。 p
为迷你转储添加进程环境块 (PEB) 和线程环境块 (TEB) 数据。如果您需要访问有关应用程序进程和线程的 Windows 系统信息,这会很有用。 w
为迷你转储添加所有已提交的读写私有页面。 d
为迷你转储添加可执行映像中的所有读写数据段。 r
从迷你转储中删除对重构堆栈跟踪无用的堆栈和存储内存部分。局部变量和其他数据类型值也会被删除。此选项不会使迷你转储变小(因为这些内存部分被简单地清零),但如果您想保护其他应用程序的隐私,它很有用。 R
从迷你转储中删除完整的模块路径。只包含模块名称。如果您想保护用户目录结构的隐私,这是一个有用的选项。 /m
说明符之后。/u
- 使转储文件名附加日期、时间和 PID。这确保了转储文件名是唯一的。/a
- 为所有当前正在调试的进程生成转储。如果使用/a
,则还应包含/u
选项以确保每个文件都有唯一的文件名。/b[a]
- 创建一个 .cab 文件。如果包含此选项,则 FileName 被视为 CAB 文件名,而不是转储文件名。将创建一个临时转储文件,该文件将被打包到 CAB 中,然后删除转储文件。如果b
选项后面跟着a
,则所有符号和映像文件也将被打包到 CAB 中。/c "Comment"
- 指定一个将被写入转储文件的注释字符串。如果 Comment 包含空格,则必须用双引号括起来。加载转储文件时,将显示 Comment 字符串。/kpmf File
(仅在创建内核模式完整内存转储时使用)- 指定一个包含物理内存页数据的文件的名称。FileName
- 指定转储文件的名称。您可以指定完整的路径和文件名,或仅文件名。如果文件名包含空格,则应将其用引号括起来。如果未指定路径,则使用当前目录。
检查应用程序崩溃时的内存堆栈
使用命令 KV
显示堆栈。如果堆栈已损坏,则可以使用以下步骤手动遍历堆栈:
lm
- 加载所有模块,记下所有模块的地址范围。dd esp
– 转储堆栈。堆栈包含堆栈中所有函数的返回地址。- 猜测可能导致崩溃的模块,并记下其地址范围。
- 查看堆栈转储,并找到一个地址,该地址位于可疑地址范围内。
ln 'address'
- 这提供了该地址附近函数的信息。u 'address'
- 如果函数看起来可疑,则可以反汇编该地址范围附近的汇编代码。- 如果未找到有关可疑函数的信息,请重复步骤 4-7。
- 如果未找到有关可疑模块的信息,请重复步骤 3-8。
WinDbg 中的有用命令
(摘自“使用 Windows 调试工具”帮助文件)
- LN(列出最近的符号)
LN 命令显示给定地址或其附近的符号。- 语法:LN address
- 参数:
- address - 开始搜索符号的地址。将显示 address 或其附近的最接近的符号。
- .dump(创建转储文件)
.dump
命令创建用户模式或内核模式的崩溃.dump
文件。- 语法:
.dump
Options FileName
- 语法:
- D, DA, DB, DC, Dd, DD, DF, DP, DQ, DU, DW, DYb, DYd(显示内存)
D* 命令显示给定范围内的内存内容。- 语法:
- d{a|b|c|d|D|f|p|q|u|w} [range]
- dy{b|d} [range]
- d [range]
- 参数:
range
- 要显示的内存区域。有关更多语法详细信息,请参阅地址和地址范围语法。如果省略range
,命令将显示从上次显示命令的结束位置开始的内存。如果省略range
且未使用之前的显示命令,则显示将从当前指令指针开始。
- 语法:
- U(反汇编)
U 命令显示内存中指定程序代码的汇编翻译。此命令不应与 ~U(解冻线程)命令混淆。- 语法:u [Range]
- 参数:
Range
- 包含要反汇编的指令的内存区域。如果未指定Range
,则反汇编从当前地址开始。如果未指定范围大小,则在 x86 处理器上默认为八条指令,在 Itanium 处理器上默认为九条指令。
- LM(列出已加载模块)
LM 命令列出指定的已加载模块。输出包括模块的状态和路径。- 语法:lm Options [a Address] [m Pattern]
- K, KB, KD, KP, Kp, KV(显示堆栈回溯)
K*
命令显示给定线程的堆栈帧以及相关信息。
参考
- “使用 Windows 调试工具”帮助文件