目录
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
可以得出详细的异常分析