VS2008调试dump文件

本文介绍如何在程序崩溃时创建Dump文件以保存程序状态,使用MiniDumpWriteDump函数实现Dump文件的创建,并通过示例代码展示具体实现过程。

让程序在崩溃时体面的退出之Dump文件 .

在我的那篇《让程序在崩溃时体面的退出之CallStack》中提供了一个在程序崩溃时得到CallStack的方法。可是要想得到CallStack,必须有pdb文件的支持。但是一般情况下,发布出去的程序都是Release版本的,都不会附带pdb文件。那么我们怎么能在程序崩溃的时候找到出错的具体位置呢?这个时候就该Dump文件出场了!Dump文件是进程的内存镜像,可以把程序运行时的状态完整的保存下来
        要想在程序崩溃的时候创建Dump文件,就需要用到DbgHelp.dll中Windows API的MiniDumpWriteDump()函数。该函数声明如下:

BOOL WINAPI MiniDumpWriteDump(
  __in  HANDLE hProcess,
  __in  DWORD ProcessId,
  __in  HANDLE hFile,
  __in  MINIDUMP_TYPE DumpType,
  __in  PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
  __in  PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
  __in  PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
具体的参数和返回值的解释可以查找MSDN,有很详细的说明。下面依然用上一篇文章中的例子代码来说明怎么在程序崩溃的时候创建Dump文件。  

// 处理Unhandled Exception的回调函数
//
LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException)
{ 
	// 这里弹出一个错误对话框并退出程序
	//
	FatalAppExit(-1,  _T("*** Unhandled Exception! ***"));

	return EXCEPTION_EXECUTE_HANDLER;
}

// 一个有函数调用的类
// 
class CrashTest
{
public:
	void Test() 
	{ 
	Crash(); 
	}

private:
	void Crash() 
	{ 
	// 除零,人为的使程序崩溃
	//
	int i = 13;
	int j = 0;
	int m = i / j;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	// 设置处理Unhandled Exception的回调函数
	// 
	SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);

	CrashTest test;
	test.Test();

	return 0;
}

 上面的程序运行后会调用以下提示框:

 

在上面的程序崩溃的时候,会调用函数ApplicationCrashHandler()。创建Dump文件的代码就需要添加到该函数中。下面就是一个创建Dump文件的函数。

// 创建Dump文件
// 
void CreateDumpFile(LPCWSTR lpstrDumpFilePathName, EXCEPTION_POINTERS *pException)
{
	// 创建Dump文件
	//
	HANDLE hDumpFile = CreateFile(lpstrDumpFilePathName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	// Dump信息
	//
	MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
	dumpInfo.ExceptionPointers = pException;
	dumpInfo.ThreadId = GetCurrentThreadId();
	dumpInfo.ClientPointers = TRUE;

	// 写入Dump文件内容
	//
	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);

	CloseHandle(hDumpFile);
}

  在上面的程序崩溃的时候,会调用函数ApplicationCrashHandler()。创建Dump文件的代码就需要添加到该函数中。下面就是一个创建Dump文件的函数。

// 创建Dump文件
// 
void CreateDumpFile(LPCWSTR lpstrDumpFilePathName, EXCEPTION_POINTERS *pException)
{
	// 创建Dump文件
	//
	HANDLE hDumpFile = CreateFile(lpstrDumpFilePathName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	// Dump信息
	//
	MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
	dumpInfo.ExceptionPointers = pException;
	dumpInfo.ThreadId = GetCurrentThreadId();
	dumpInfo.ClientPointers = TRUE;

	// 写入Dump文件内容
	//
	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);

	CloseHandle(hDumpFile);
}

  在函数ApplicationCrashHandler()用类似下面的代码来调用上面的函数,就可以在程序崩溃的时候创建Dump文件。

1.CreateDumpFile(_T("C:\\Test.dmp"), pException); 

        下面简单说一下Dump文件的用法。将Dump文件拷贝到含有应用程序和对应的pdb文件的目录,在VS里面打开Dump文件(或者直接双击Dump文件),VS会自动创建一个Solution,直接调试运行,代码就会停到使程序崩溃的那一行上。就跟在VS里面调试代码一摸一样。(VS2008)



        在VS2010里打开Dump文件,会显示一个Minidump File Summary,并且可以进行下面图中的操作。








用vs2008分析dump文件

注意:此方法要求代码与.pdb文件严格对应,严格加载不了PDB文件。(如果代码重新从SVN上下来,由于时间CUO变化,所以不能调试)。

它可以解决以下问题:

Debug时不出错,但直接运行就出错的情况。


  1. 双击minidump文件(*.dmp)。默认会启动vs2008。
  2. 菜单Tools/Options, Debugging/Symbols,增加PDB文件路径。注:如果minidump文件与pdb文件在同一目录,就不用设置这个了。
  3. 若调试的程序需要微软基础库的PDB信息,可以增加一个路径为:
  4. http://msdl.microsoft.com/download/symbols
  5. 在界面下方Cache Symbol From symbol…选择本地存储这些Symbols的路径。 注:如果本地已存储过微软基础库的pdb,就直接按照此步操作设置本地路径,不必执行上一步操作了。
  6. 设置代码路径:

设置代码路径:

刚打开的dmp工程,进入解决方案的属性。在这里输入源程序的代码路径。注:一定是sln所在的路径,而不是vcproj的路径!



按F5,debug吧。

 

//

PS:或者可以这样加载符号路径,如果没有加载本应用程序的符号表,可以在加载模块里面修改符号表的路径.(也是弹出菜单Tools/Options, Debugging/Symbols)







调试dump文件(如Windows的`.dmp`或Linux的`core dump`)是分析程序崩溃、异常或性能问题的关键步骤。以下是针对不同系统的详细调试方法: --- ### **一、Windows系统调试(使用WinDbg)** #### **1. 准备工作** - **安装工具**: - 下载并安装 [WinDbg Preview](https://aka.ms/windbgpreview)(推荐)或旧版WinDbg。 - 安装Windows SDK(包含调试符号和工具)。 - **获取Dump文件**: - 崩溃时自动生成:通过任务管理器→右键进程→“创建转储文件”。 - 手动生成:使用`procdump`工具(Sysinternals套件): ```cmd procdump -ma <PID> output.dmp ``` #### **2. 配置符号路径** - 在WinDbg中设置微软符号服务器(自动下载PDB符号): ```cmd .symfix .reload ``` 或手动指定路径: ```cmd .sympath srv*C:\Symbols*https://msdl.microsoft.com/download/symbols ``` #### **3. 加载Dump文件** - 启动WinDbg,选择 **File → Open Crash Dump**,加载`.dmp`文件。 - 或命令行直接打开: ```cmd windbg -y <符号路径> -i <符号缓存路径> -z <dump文件路径> ``` #### **4. 常用调试命令** | 命令 | 作用 | |---------------------|----------------------------------------------------------------------| | `!analyze -v` | 自动分析崩溃原因(显示异常代码、调用栈等)。 | | `kv` | 显示当前线程的完整调用栈(含参数)。 | | `~*kv` | 显示所有线程的调用栈。 | | `!thread` | 显示当前线程信息。 | | `!peb` | 显示进程环境块(PEB),查看加载的DLL。 | | `lm` | 列出所有加载的模块(DLL/EXE)。 | | `dd <地址> L<长度>` | 显示内存内容(如`dd poi(esp+4) L4`查看栈参数)。 | | `u <地址>` | 反汇编指定地址的代码。 | | `.load by sos` | 加载.NET调试扩展(用于托管代码)。 | #### **5. 典型场景分析** - **访问冲突(Access Violation)**: ```cmd !analyze -v kv ``` 检查调用栈中是否有空指针解引用或越界访问。 - **死锁**: ```cmd ~*kv !locks ``` 查看所有线程的调用栈和锁状态。 - **堆损坏**: ```cmd !heap -p -a <损坏地址> ``` 使用`PageHeap`或`Application Verifier`提前捕获堆错误。 --- ### **二、Linux系统调试(使用GDB)** #### **1. 生成Core Dump** - 临时启用core dump: ```bash ulimit -c unlimited echo "core.%e.%p" > /proc/sys/kernel/core_pattern # 命名格式 ``` - 手动触发: ```bash kill -SIGSEGV <PID> # 强制生成core dump ``` #### **2. 调试Core Dump** - 启动GDB并加载core文件: ```bash gdb <可执行文件> <core文件> ``` 或直接附加到进程: ```bash gdb -p <PID> ``` #### **3. 常用GDB命令** | 命令 | 作用 | |---------------------|----------------------------------------------------------------------| | `bt` | 显示当前线程的调用栈。 | | `thread apply all bt` | 显示所有线程的调用栈。 | | `info registers` | 显示寄存器状态。 | | `x/<格式> <地址>` | 显示内存内容(如`x/10xw 0x7fffffffd000`显示10个字的十六进制值)。 | | `disassemble` | 反汇编当前函数。 | | `set follow-fork-mode child` | 调试子进程(如多进程程序)。 | #### **4. 典型场景分析** - **段错误(Segmentation Fault)**: ```gdb bt info registers x/i $pc # 显示崩溃指令 ``` 检查调用栈中是否有无效指针或数组越界。 - **死锁**: ```gdb thread apply all bt info mutex # 查看互斥锁状态(需GDB支持) ``` - **内存泄漏**: 使用`valgrind`提前检测: ```bash valgrind --leak-check=full ./your_program ``` --- ### **三、跨平台工具** 1. **Dr. Memory**(Windows/Linux): - 检测内存错误(如泄漏、越界)。 - 示例: ```bash drmemory -- ./your_program ``` 2. **LLVM Sanitizers**(编译时检测): - **AddressSanitizer (ASan)**:检测内存错误。 - **UndefinedBehaviorSanitizer (UBSan)**:检测未定义行为。 - 编译时添加标志: ```bash gcc -fsanitize=address -g your_program.c ``` --- ### **四、高级技巧** 1. **时间旅行调试(Time Travel Debugging, TTD)**: - WinDbg支持录制程序执行过程,可回放任意时间点的状态。 - 命令: ```cmd .ttd/record <进程> .ttd/replay ``` 2. **脚本自动化**: - 编写WinDbg脚本(`.txt`文件)批量分析多个dump文件。 - 示例脚本: ```cmd .logopen C:\logs\analysis.log !analyze -v kv .logclose ``` 3. **与版本控制集成**: - 通过`git blame`定位崩溃代码的提交记录。 --- ### **五、常见问题** #### **Q1: 为什么WinDbg提示“符号未加载”?** - 符号服务器未配置或网络问题。检查`.sympath`和`.reload`命令。 #### **Q2: Core Dump文件很大怎么办?** - 使用`split`命令分割文件,或通过`ulimit -c`限制大小。 #### **Q3: 如何调试第三方程序的dump文件?** - 确保有匹配版本的PDB符号(Windows)或调试信息(Linux)。 #### **Q4: 能否调试Release版本的dump文件?** - 可以,但缺少调试信息时需结合反汇编分析。 #### **Q5: 如何共享dump文件而不泄露敏感信息?** - 使用`strings`命令提取文本信息,或通过`dd`截取部分内存。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值