分析 dump 文件崩溃栈信息

发布于 2022-09-20


Windows 上常见的几个分析 dump 文件崩溃栈信息的方法有以下几种。

windbg 和 cdb

我们可以给 windbg 或者 cdb 传递命令行参数来分析 dump 文件。

首先是 windbg。windbg 功能很强大,但是我们想自动化的批量分析 dump 文件,使用它则是很笨拙。因为微软符号仓库的原因,windbg 分析 dump 文件的时候,会下载 dump 文件里所包含所有模块的调试符号信息文件,这个过程可能耗时几分钟甚至几十分钟。

一个加速 windbg 分析 dump 速度的办法是通过环境变量 _NT_SYMBOL_PROXY 设置一个快速的网络代理,加快符号文件的下载。但是因其内部下载调试符号文件是串行的,所以其速度仍然不够快。

cdb 的功能与 windbg 类似, cdb 是个命令行工具。

breakpad

Google 的 breakpad 项目里包含了一个 processor 工具,它也可以分析 dump 文件。

processor 使用的调试符号文件不是 Windows 上的 pdb 格式,而是通过工具把 pdb 格式转换成 sym 文本格式的调试符号文件。processor 的优点是可以跨平台,它不仅可以分析 windows 平台,可以分析 linux 和 mac 平台生成的崩溃 dump 文件。它的缺点则是如果仅在 windows 平台使用它,维护符号仓库略有些麻烦,不仅需要转换符号文件格式,依赖到的微软符号,也需要自己下载。

processor 分析一个 dump 文件非常快,几秒之内就可以完成。

dbgeng

dbgeng 提供了接口从 dump 文件获得崩溃栈信息,也支持符号仓库,但是依赖到的微软符号,也需要自己下载。

dbghelp

dbghelp 可以使用 StackWalk64 来读取进程里某个线程的调用栈信息,实际上它也是可以应用到 dump 文件中的。

BOOL IMAGEAPI StackWalk64(
  [in]           DWORD                            MachineType,
  [in]           HANDLE                           hProcess,
  [in]           HANDLE                           hThread,
  [in, out]      LPSTACKFRAME64                   StackFrame,
  [in, out]      PVOID                            ContextRecord,
  [in, optional] PREAD_PROCESS_MEMORY_ROUTINE64   ReadMemoryRoutine,
  [in, optional] PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
  [in, optional] PGET_MODULE_BASE_ROUTINE64       GetModuleBaseRoutine,
  [in, optional] PTRANSLATE_ADDRESS_ROUTINE64     TranslateAddress
);

StackWalk64 读取 dump 文件的崩溃栈信息实现比较复杂,需要自己处理实现 ReadMemoryRoutineFunctionTableAccessRoutineGetModuleBaseRoutineTranslateAddress 几个函数,几乎没有资料可以参考。

在 github 上有个 DbgHelpUtils 项目,对其有实现。

stack_tracer

最近写了一个分析 dump 文件崩溃栈信息的工具 stack_tracer。它是调用 dbgeng、dbghelp 和 DIA 接口实现的,有以下优点:

  1. 支持使用符号仓库
  2. 分析速度快,在不下载微软符号的情况下,可以在几秒之内分析出崩溃栈信息
  3. 支持自动并行下载微软符号,速度相比 windbg 提高几十倍
  4. 支持微软符号网络代理,进一步加快符号下载速度

它首先通过 dbghelp 获得 dump 文件里所有模块的信息,然后检查本地符号仓库是否已经存在这些模块对应的符号文件,并通过 DIA 库校验是否符号是否匹配。对那些符号仓库缺失的符号,通过网络去 https://msdl.microsoft.com/download/symbols 微软符号仓库并行下载。准备好符号之后,再通过 dbgeng 接口去获得 dump 文件崩溃栈信息。

它支持的命令行参数如下:

  • --dump-file-path,指定 dump 文件的路径
  • --symbol-path,可选,指定符号仓库的路径
  • --proxy,可选,指定网络代理,用于下载微软符号,如 --proxy=socks5://127.0.0.1:8806

运行的效果如下图所示:

stack tracer result