使用windbg抓取崩溃文件和分析的过程

本文介绍了一个多线程访问共享变量导致程序崩溃的典型案例。通过构造特定代码演示并发问题,并利用Windbg生成完整内存转储文件进行故障定位。
        在软件编程中,崩溃的场景比较常见的。且说微软技术再牛X,也是会出现崩溃的场景。网上有一段Win98当着比尔盖茨蓝屏的视频非常有意思。 (转载请指明出于breaksoftware的csdn博客)
        我们身边的很多软件都引入了dump生成和收集机制。但是一般情况下,它们都是生成minidump。因为minidump文件相对来说很小,方面我们收集上来进行分析。但是Minidump保存了很少的信息,在一些场景下,可能不能协助我们准确快速定位问题。

        但是,如果我们在测试过程中,发生了必现崩溃,而minidump又不能让我们发现什么,那该怎么办呢?我这儿举一个例子。我们看一下代码

// Dump.cpp : 定义控制台应用程序的入口点。
//
//////////////////////////////////////////////////////////////////////////
// 这是一个多线程访问全局变量导致崩溃的例子
//////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <Windows.h>
#include <vector>

#define INTPTR int* 
typedef std::vector<INTPTR> VecINTPTR;
typedef VecINTPTR::iterator VecINTPTRIter;
typedef VecINTPTR::const_iterator VecINTPTRCIter;

VecINTPTR g_VecInt;

static DWORD WINAPI ReadRoutine(LPVOID)
{
    // 读取线程
    for ( VecINTPTRIter it = g_VecInt.begin(); it != g_VecInt.end(); it++ ) {
        // 故意将读取时间设置长,这样更大概率导致崩溃
        Sleep(10);
        printf("%d %d\n", **it);
    }
    return 0;
}

static DWORD WINAPI WriteRoutine(LPVOID)
{
    // 写入线程
    for ( VecINTPTRIter it = g_VecInt.begin(); it != g_VecInt.end();  ) {
        // 故意将修改时间设置短,这样更大概率导致奔溃
        delete *it;
       *it = NULL;
    }
    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    // 初始填充数据
    for ( int n = 0; n < 128; n++ ) {
        int* p = new int();
        *p = n;
        g_VecInt.push_back(p);
    }
    system("pause");
    HANDLE hRead = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ReadRoutine, NULL, 0, NULL);
    HANDLE hWrite = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)WriteRoutine, NULL, 0, NULL);
    HANDLE hArray[] = {hRead, hWrite};
    WaitForMultipleObjects( ARRAYSIZE(hArray), hArray, TRUE, INFINITE);
    printf("Success");
         return 0;
}
        这个例子是典型的多线程访问共享变量,导致崩溃的问题。这个例子还是很清晰的,但是,如果这段逻辑揉入复杂的业务逻辑,问题的排查可能就没那么简单了。
        那我们看下如何分析这个问题。
  1. 运行程序(程序会暂停在system(“pause”))
  2. 安装windbg,使用“附加”功能
  3. 在windbg中输入g,让程序继续执行 
  4. 在dump.exe按任意键,重现崩溃路径
  5. 崩溃发生,windbg发现异常并中断
  6. 在windbg中输入.dump /f C:/dump.dmp,其中.dump是dump生成命令,/f是生成全信息dump,生成的dump文件会很大,C:/dump.dmp是路径
        至此,我们在客户机器上已经抓到了完整的dmp文件,现在我们回到我们自己的电脑上,配置windbg,并分析这个dump文件。在这个配置中,我们要涉及几块信息的填充。一般,我们发布的产品(release版)不是在我们开发者的机器上编译链接的,而是在某一个编译链接服务器上。在服务器上,我们工程的目录和我们本地的目录极有可能是不同的。一般情况下,最容易配置不正确的是下面的第3步。
  1. 将dump.exe符号文件拷贝到你希望的保存目录,我的目录是F:\TmpSymbol
  2. 用!analyze –v分析dump文件
  3. ctrl+P打开windbg代码目录(工程根目录)
  4. Ctrl+S打开windbg符号设置框,设置符号文件路径,并勾选reload
        这样windbg就准确定位到异常的位置

        这个流程非常适合于分析的场景是:

  1. 没有做通过异常方式做保护的程序(否则windbg挂载后会一直陷入中断,非常烦人。或者程序发现自己被调试,就直接退出了……)
  2. VS不便分析的dump
  3. 不破坏用户环境(windbg是个非常小巧独立的程序,试想如果我们给客户装个庞大的VS再去调试是非常难以接受的,且会破坏用户的环境)

<think> 首先,用户的问题是关于使用Windbg分析dump文件来定位当前异常上下文信息的具体方法。用户引用了三个站内引用,我需要参考这些引用来构建答案。 回顾用户提供的引用: - 引用[1]:提到Windbg加载dump文件符号文件,帮助定位异常,并建议参考官方文档。 - 引用[2]:强调使用CrashReport库捕获异常信息并生成dump文件,然后用Windbg分析。 - 引用[3]:讨论Windbg版本问题(6.0可能不兼容VS2017生成的pdb文件),并提到使用“.ecxr”命令切换到异常的上下文。 用户的核心问题是:“如何使用windbg分析dump文件并定位当前异常的上下文信息”。 关键点是从引用[3]中,提到“.ecxr”命令用于切换到异常的上下文。这似乎是用户需求的核心。 我的回答需要: - 使用中文回答。 - 结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠(基于提供的引用)。 - 在回答中引用的段落末尾自然地添加引用标识,例如:[^1]。 - 生成相关问题(在末尾添加“相关问题”部分)。 - 对于LaTeX:行内数学表达式用$...$,独立公式用$$...$$(但在这个主题可能不需要数学公式,除非涉及计算)。 - 回答基于系统指令用户提供的引用。 结构化回答: 1. **介绍Windbg的基本步骤**:基于引用[1][2],简要说明Windbg的作用加载dump文件的步骤。 2. **详细解释定位异常上下文的方法**:重点在“.ecxr”命令上,基于引用[3]。 3. **提供操作步骤**:一步步指导用户。 4. **注意事项**:如Windbg版本兼容性问题(从引用[3])。 5. **结尾**:鼓励参考官方文档。 6. **添加相关问题**:生成相关的问题在末尾。 确保回答真实可靠:我主要基于提供的引用,避免添加外部知识,除非必要。 添加引用标识: - 当提及引用中的内容,在段落末尾添加[^1]、[^2]或[^3]。 生成相关问题:在末尾添加“相关问题”部分,类似示例中的格式。 回答框架: - 开头:确认用户查询。 - 主体:分步解释。 - 结尾:总结建议。 - 相关问题列表。 具体步骤(基于引用): 1. 加载dump文件Windbg打开dump文件。 2. 加载符号文件:设置符号路径(.sympath)以访问pdb文件。 3. 分析异常:使用命令如“.ecxr”来切换到异常上下文。 4. 查看上下文:使用命令如“k”显示堆栈,或“dv”查看局部变量。 从引用[3]:“使用.ecxr命令切换到异常的上下文”。这是关键。 其他可能命令: - !analyze -v:自动分析异常。 - .exr:显示异常记录。 但用户专注于“定位当前异常的上下文信息”,所以我将集中于“.ecxr”。 最终回答结构: 1. 引言:简述过程。 2. 步骤: a. 打开dump文件。 b. 设置符号路径。 c. 使用.ecxr命令切换到异常上下文。 d. 检查上下文信息(如寄存器、堆栈)。 3. 注意事项:版本兼容性(从引用[3])。 4. 总结。 5. 相关问题。 添加引用: - 引用[1]用于Windbg基本用途。 - 引用[2]用于生成dump文件。 - 引用[3]用于.ecxr命令版本问题。 相关问题生成: - 如何设置Windbg的符号路径? - 如何处理Windbg版本不兼容pdb文件的问题? - 还有哪些命令用于分析dump文件? </think> ### 使用Windbg分析dump文件定位异常上下文信息的方法 Windbg是一个强大的调试工具,用于分析Windows应用程序崩溃生成的dump文件,帮助开发人员快速定位异常上下文(如寄存器状态、堆栈跟踪等)。以下步骤基于引用内容,并结合最佳实践,指导您如何操作。步骤清晰可靠,确保您能准确找到当前异常的上下文信息。 #### 步骤1: 准备dump文件符号文件 - **加载dump文件**:启动Windbg,通过菜单或命令行加载dump文件(例如,`.open -a D:\crash.dmp`)。这允许Windbg读取崩溃的内存快照。[^1] - **设置符号路径**:使用`.sympath`命令配置符号路径(例如,`.sympath srv*https://msdl.microsoft.com/download/symbols;D:\pdb`),确保Windbg能访问对应的pdb文件(符号文件),这对解析函数名变量至关重要。如果符号加载失败,检查pdb文件是否与编译环境兼容(如VS2017生成的pdb可能需要新版本Windbg)[^3]。 - **验证符号加载**:运行`.reload -f`强制刷新符号,并用`lm`命令检查模块是否加载成功。引用[2]中提到,使用CrashReport库生成dump文件,确保符号文件匹配编译版本,否则分析可能失败。[^2] #### 步骤2: 切换到异常上下文 - **核心命令:`.ecxr`**:加载dump文件后,输入`.ecxr`命令(Exception Context Record),这会自动切换到异常发生的上下文。此命令基于异常记录(Exception Record)恢复寄存器堆栈状态,是定位当前异常的关键。[^3] - **示例操作**: ``` WinDbg> .ecxr ``` 执行后,Windbg输出寄存器指令指针(eip/rip)信息,显示异常点(如访问违例的地址)。 #### 步骤3: 分析上下文信息 - **查看堆栈跟踪**:运行`k`命令(例如,`kb`或`kn`)显示调用堆栈,这会列出函数调用序列,帮助识别异常源头。结合`.ecxr`的输出,您可以定位到触发异常的具体函数位置。[^1] - **检查寄存器状态**:使用`r`命令查看寄存器值(如`eax`, `ebp`),识别异常的内存地址或参数。 - **查看局部变量**:运行`dv`命令显示当前函数的局部变量值,辅助分析数据异常原因。 - **自动分析**:可选运行`!analyze -v`命令,Windbg会尝试自动诊断异常类型(如`ACCESS_VIOLATION`)并提供建议,但`.ecxr`是手动切换到上下文的基础。[^3] #### 注意事项 - **Windbg版本兼容性**:如引用[3]所述,旧版Windbg(如6.0)可能无法加载VS2017+生成的pdb文件。推荐使用最新Windbg版本(可从Microsoft官网下载),或确保编译环境调试工具版本一致。[^3] - **符号文件问题**:如果符号无法加载,检查`.sympath`设置或使用`.symfix`自动连接Microsoft符号服务器。复杂问题可参考[Windbg官方文档](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugging-using-windbg)。[^1] - **上下文验证**:`.ecxr`仅适用于异常上下文。如果dump文件不是由异常生成(如手动抓取),使用`.cxr`命令加载上下文记录。 通过上述步骤,您可以高效定位异常上下文信息,缩短调试间。引用[2]强调,在代码中集成CrashReport等库捕获dump文件,能大幅提升事后分析效率。[^2] 如遇更深层问题,建议结合日志代码回查。 ### 相关问题 1. 如何处理Windbg无法加载符号文件(pdb)的问题? 2. 除了`.ecxr`,Windbg中有哪些常用命令用于分析堆栈寄存器? 3. 如何配置应用程序自动生成dump文件?(例如,使用CrashReport库)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

breaksoftware

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值