65.9K
CodeProject 正在变化。 阅读更多。
Home

应用程序崩溃时自动内存转储

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.06/5 (32投票s)

2004 年 2 月 27 日

CPOL

9分钟阅读

viewsIcon

136394

downloadIcon

1110

配置自动内存转储并手动遍历堆栈。

引言

我们可以让调试器在应用程序崩溃时自动弹出。这种调试器称为事后调试器(post mortem debugger)或即时(JIT)调试器,它们还可以自动生成崩溃内存转储。一些事后调试器包括 WinDbg、VS 6.0/NET 和 Dr. Watson。在本文中,我们将使用 WinDbg 调试器并解释如何

  • 将其配置为事后调试器,
  • 自动生成内存转储文件,以及
  • 在应用程序崩溃时遍历其内存堆栈。

将 WinDbg 配置为事后调试器

  1. 从 Microsoft 调试器网站 此处下载 WinDbg。
  2. 将其安装到合适的目录。
  3. 要将事后调试器更改为 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 值始终为 01。如果设置为 0,则在事后调试之前会显示一个消息框。

当发生未处理的应用程序错误时,Windows 会检查 DebuggerAuto 注册表值是否存在。如果 Auto 值为 0,则会显示一个消息框。在 Windows NT 和 Windows 2000 上,消息框将具有以下格式之一:

  • 如果 Debugger 值包含有效调试器或 Dr. Watson 的名称,则消息框将有两个按钮:OKCancel。如果按下 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 
注释
  1. 请小心进行注册表更改。执行 test.exe 以验证注册表更改是否正确。运行 test.exe 时,应用程序将自动打开调试器并在 C:\ 目录中生成 crashdump.dmp 文件。
  2. -c 选项应紧跟在 -p %ld 之后。
  3. 信息摘自“使用 Windows 调试工具”帮助文件。
  4. -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 从迷你转储中删除完整的模块路径。只包含模块名称。如果您想保护用户目录结构的隐私,这是一个有用的选项。
    这些 MiniOptions 只能在创建用户模式迷你转储时使用。它们应跟在 /m 说明符之后。
  • /u - 使转储文件名附加日期、时间和 PID。这确保了转储文件名是唯一的。
  • /a - 为所有当前正在调试的进程生成转储。如果使用 /a,则还应包含 /u 选项以确保每个文件都有唯一的文件名。
  • /b[a] - 创建一个 .cab 文件。如果包含此选项,则 FileName 被视为 CAB 文件名,而不是转储文件名。将创建一个临时转储文件,该文件将被打包到 CAB 中,然后删除转储文件。如果 b 选项后面跟着 a,则所有符号和映像文件也将被打包到 CAB 中。
  • /c "Comment" - 指定一个将被写入转储文件的注释字符串。如果 Comment 包含空格,则必须用双引号括起来。加载转储文件时,将显示 Comment 字符串。
  • /kpmf File(仅在创建内核模式完整内存转储时使用)- 指定一个包含物理内存页数据的文件的名称。
  • FileName - 指定转储文件的名称。您可以指定完整的路径和文件名,或仅文件名。如果文件名包含空格,则应将其用引号括起来。如果未指定路径,则使用当前目录。

检查应用程序崩溃时的内存堆栈

使用命令 KV 显示堆栈。如果堆栈已损坏,则可以使用以下步骤手动遍历堆栈:

  1. lm - 加载所有模块,记下所有模块的地址范围。
  2. dd esp – 转储堆栈。堆栈包含堆栈中所有函数的返回地址。
  3. 猜测可能导致崩溃的模块,并记下其地址范围。
  4. 查看堆栈转储,并找到一个地址,该地址位于可疑地址范围内。
  5. ln 'address' - 这提供了该地址附近函数的信息。
  6. u 'address' - 如果函数看起来可疑,则可以反汇编该地址范围附近的汇编代码。
  7. 如果未找到有关可疑函数的信息,请重复步骤 4-7。
  8. 如果未找到有关可疑模块的信息,请重复步骤 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 调试工具”帮助文件
© . All rights reserved.