VC++使用pdb和dump恢复“案发现场”

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/i_chaoren/article/details/81453142

目录

 

pdb文件

PDB文件简介

 EXE、DLL等与pdb文件的匹配

编译器产生符号的过程

Release程序生成pdb文件

 dump文件

使用背景介绍

dump文件的生成

调试dump文件

VS调试

 本地dump调试

无源代码dump调试

WinDbg调试


pdb文件

PDB文件简介

pdb符号文件是连接二进制指令和源代码之间的纽带,没有符号你所面对只有地址,由链接器自动生成

pdb在运行的时候没有任何作用的,但是对于调试器和我们调试则有很大的帮助。

文件由两个部分构成,私有符号数据(private symbol data)和公共符号表(public symbol table)

  • 私有符号数据(Private Symbol Data)

    • 函数

    • 全局变量

    • 局部变量

    • 用户定义的结构体,类,数据类型

    • 源文件的名称和源文件中每个二进制指令的行号

  • 公共符号表(Public Symbol Table)

    • 静态变量

    • 全局变量(external)

 EXE、DLL等与pdb文件的匹配

调试器是如何来判别EXE、DLL等是否和一个pdb文件匹配呢?

每次我们链接EXE或者DLL或者SYS的时候,链接器都将产生一个唯一的GUID,然后将其写入到PDB和可执行文件。调试器加载的时候将检查两者的GUID,如果一致就表示他们匹配。

如果我们需要调试,我们需要查dmp文件,那么请妥善保管好自己的代码和pdb每次重新编译,即使所有代码均没有变化,他们的GUID也不同。

编译器产生符号的过程

如果指定生成调试信息,编译器在每次编译完文件以后就会产生一个obj文件,然后同时产生它对应的调试信息。当我们进行连接的时候,编译器就会帮我们把所有obj统一编译为一个可执行文件,然后所有的调试信息统一生成一个PDB文件。

Release程序生成pdb文件

用VS调试Release的程序,发现无法调试。其实,并不是Release的程序不能调试,而是没有让Release的程序生成pdb文件,VS无法加载pdb文件而无法调试程序。

设置一下,让Release的程序也生成pdb文件,就好了。

 dump文件

使用背景介绍

当程序遇到未处理异常(主要指非指针造成)导致程序崩溃死,如果在异常发生之前调用了SetUnhandledExceptionFilter()函数,异常交给函数处理。MSDN中描述为:

Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.

因而,在程序开始处增加SetUnhandledExceptionFilter()函数,并在函数中利用适当的方法生成Dump文件,即可实现需要的功能。

Dump文件是进程的内存镜像。可以把程序的执行状态通过调试器保存到dump文件中。

dump文件的生成

#include<iostream>
#include<Windows.h>
#include<DbgHelp.h>
using namespace std;
#pragma comment(lib,"DbgHelp.lib")

// 创建Dump文件
void CreateDumpFile(LPCWSTR lpstrDumpFilePathName, EXCEPTION_POINTERS *pException)
{
	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);
}

// 处理Unhandled Exception的回调函数
LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException)
{
	CreateDumpFile(L"Test.dmp", pException);
	cout << "异常已记录" << endl;
	system("pause");
	return EXCEPTION_EXECUTE_HANDLER;
}

void func1() {
	cout << "正常函数" << endl;
}

void func2() {
	int num = 10;
	int in;
	cout << "输入一个整数:" << endl;
	//当输入为0时则会发生异常
	cin >> in;
	num = num / in;
	cout << num << endl;
}

int main()
{
	//注册异常处理函数
	SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);
	func1();
	func2();
}

调试dump文件

VS调试

 本地dump调试

直接用VS打开Test.dmp文件,测试时dmp文件是本地产生的,因此VS会依据dmp文件自行找到exe,pdb和源代码的路径。因此直接点击调试,程序会出错代码行中断。

无源代码dump调试

但若dmp文件是exe在另一台机器上产生的,则我们最好把exe,pdb,dmp放到同一文件夹下,必须保证pdb与出问题的exe是同一时间生成的,用VS打开dmp文件后还需要设置符号表文件路径和源代码路径。

(1)当把pdb文件与dmp文件放入同一目录下时,就不需设置其路径,否则需要设置

工具->选项->调试->符号:

(2)还需设置源代码路径:

属性->调试源代码:

这样点击“使用仅限本机进行调试”,即可在出错代码行中断:

WinDbg调试

基本思路与VS一致,winDbg会提供更为全面的调试信息

(1)设置pdb路径:File ->Symbol File Path

(2)设置exe路径:File -> Image File Path

(3)设置源代码路径:File -> Source File Path(指sln所在目录)

(4)打开dmp文件:File ->Open Crash Dump

(5)执行命令 !analyze –v  

可以得出详细的异常分析

猜你喜欢

转载自blog.csdn.net/i_chaoren/article/details/81453142
今日推荐