用dump和pdb文件定位程序崩溃的位置

目的

利用dump和pdb文件来快速定位程序崩溃的地方

步骤

这里写一个简单的崩溃程序。
sample.cpp

class Test{
public:
	void say(){
		int a = 0;
		int b = 10 / a;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	Test t;
	t.say();

	return 0;
}


int b=10/a这句代码会导致程序崩溃。

1.dump文件生成相关配置

添加两个文件。
CCreateDump.h

#pragma once
#include <string>

using namespace std;
class CCreateDump
{
public:
	CCreateDump();
	~CCreateDump(void);
	static CCreateDump* Instance();
	static long __stdcall UnhandleExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo);
	//声明Dump文件,异常时会自动生成。会自动加入.dmp文件名后缀
	void DeclarDumpFile(std::string dmpFileName = "");
private:
	static std::string    strDumpFile;
	static CCreateDump*    __instance;
};

CCreateDump.cpp文件

#include "stdafx.h"
#include <Windows.h>
#include "CCreateDump.h"
#include <DbgHelp.h>
#pragma comment(lib,  "dbghelp.lib")

CCreateDump* CCreateDump::__instance = NULL;
std::string CCreateDump::strDumpFile = "";

CCreateDump::CCreateDump()
{ 
}

CCreateDump::~CCreateDump(void)
{

}

long  CCreateDump::UnhandleExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo)
{
	HANDLE hFile = CreateFile(strDumpFile.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile != INVALID_HANDLE_VALUE)
	{
		MINIDUMP_EXCEPTION_INFORMATION   ExInfo;
		ExInfo.ThreadId = ::GetCurrentThreadId();
		ExInfo.ExceptionPointers = ExceptionInfo;
		ExInfo.ClientPointers = FALSE;
		//   write   the   dump
		BOOL   bOK = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL);
		CloseHandle(hFile);
		if (!bOK)
		{
			DWORD dw = GetLastError();
			//写dump文件出错处理,异常交给windows处理
			return EXCEPTION_CONTINUE_SEARCH;
		}
		else
		{    //在异常处结束
			return EXCEPTION_EXECUTE_HANDLER;
		}
	}
	else
	{
		return EXCEPTION_CONTINUE_SEARCH;
	}
}

void CCreateDump::DeclarDumpFile(std::string dmpFileName)
{
	SYSTEMTIME syt;
	GetLocalTime(&syt);
	char c[MAX_PATH];
	sprintf_s(c, MAX_PATH, "[%04d-%02d-%02d %02d:%02d:%02d]", syt.wYear, syt.wMonth, syt.wDay, syt.wHour, syt.wMinute, syt.wSecond);
	strDumpFile = std::string(c);
	if (!dmpFileName.empty())
	{
		strDumpFile += dmpFileName;
	}
	strDumpFile += std::string(".dmp");
	SetUnhandledExceptionFilter(UnhandleExceptionFilter);
}

CCreateDump* CCreateDump::Instance()
{
	if (__instance == NULL)
	{
		__instance = new CCreateDump;
	}
	return __instance;
}

在sample.cpp添加一句:

int _tmain(int argc, _TCHAR* argv[])
{
	CCreateDump::Instance()->DeclarDumpFile("dumpfile");//新加代码
	Test t;
	t.say();

	return 0;
}

对项目属性进行设置。
属性-》配置属性-》常规-》字符集-》使用多字节字符集。
在这里插入图片描述

2.pdb文件生成相关配置

对项目属性进行配置:
属性–》链接器-》调试–》生成调试信息–》是
在这里插入图片描述

3.生成dump和pdb文件

对项目进行编译生成sample.exe文件,可以同时生成了sample.pdb文件。
在这里插入图片描述
双击运行.exe程序,程序一闪而过,崩溃了,同时生成了dump文件。
在这里插入图片描述

4.调试

用vs打开dump文件,点击使用本机进行调试。在这里插入图片描述
可以发现自动定位到崩溃的代码了。
在这里插入图片描述
当然这是最理想的状态。工程项目的目录结构跟生成pdb文件的时候一样没发生改变,不需要设置源码的路径,直接把exe、pdb、dump文件放到同一个文件夹下就行了,因为pdb文件中保存了源代码的绝对路径。否则需要手动添加源码路径,然后在进行本机调试。
属性-》调试源文件
在这里插入图片描述
当然也可以不管,直接本机调试,根据调用堆栈也能知道是哪句代码出问题,只是看不到具体代码。
在这里插入图片描述

5.注意

前面的部分有个大前提,就是得保证exe、dump和pdb文件的一致性,就是说exe和pdb都是由一份代码在同一时间生成的,而dump又是由这个exe生成的。这三个文件有GUID的效验码,假如不一致的话就会没法定位。代码稍微改动了没关系,只是定位会不是很准确。这个GUID貌似是跟时间戳相关的,就算代码没变,重新生成了的话也会改变GUID。
在这里插入图片描述
可以用dumpbin查看guid。打开VS2013 开发人员命令提示,输入

dumpbin /headers D:\opgl\sample\Debug\sample.exe

在这里插入图片描述
,这部分就是GUID
在这里插入图片描述
前面还有一段,这是时间戳信息,也就是生成exe的时间,可以用它来找相应的代码。
在这里插入图片描述

6.用Windbg定位

对WIndbg不是很熟悉,据说:
Windbg是一款功能十分强大的调试工具,它设计了极其丰富的功能来支持各种调试任务,包括用户态调试、内核态调试、调试转储文件、远程调试等等。

.1设置pdb文件路径

file-》Symbol Search Path。我的pdb是放在这个路径下。
在这里插入图片描述

.2设置源码位置

file-》Source Search Path
在这里插入图片描述

.3打开dump文件

把dump文件直接拖进去。
在这里插入图片描述
输入自动分析命令

!analyze -v

在这里插入图片描述

此时左边变成了BUSY,就是在工作中,等它变回去就结束了。
在这里插入图片描述
分析结果关键部分是这个
在这里插入图片描述
STACK_TEXT表示堆栈信息,后面表示崩溃的代码。
不输入源代码路径的话它就会自动读取pdb中的源码路径,假如找不到的话就没后面部分,只能知道哪个函数出错了。

我用的Windbg是这个:
链接:https://pan.baidu.com/s/1eNMibUvA1xgIgM6GIM9ePA
提取码:z221

在这里插入图片描述
外面的windbg是汉化版,但用起来有问题,我用的是x64里面的。
参考:
1.Dump文件的生成和使用
2.Dump调试
3.vs2010下使用dmp文件和pdb文件调试时dump、exe和pdb三个文件要保持版本一致的原因
4.VC++使用pdb和dump恢复“案发现场”
5.转储了dump后,如何用Windbg进行分析呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值