Qt下生成pdb文件,并在exe崩溃时生成dmp文件,且由dmp查询崩溃原因
一、编译时生成pdb文件
选择profile编译即可,在此模式下,既可享受release的运行速度,又可以享受debug的符号查找。
发布的程序可以正常运行在生产环境,尤其是适合在一些实时性要求高的项目中。
二、在exe崩溃时生成dmp文件
参考:
https://blog.csdn.net/a844651990/article/details/85225273
声明函数
DumpHelper.h
#ifndef DUMPHELPER_H
#define DUMPHELPER_H
#include <QSystemSemaphore>
#include <QDir>
#include <QDateTime>
#include <QDebug>
#include <tchar.h>
#include <Windows.h>
#include <DbgHelp.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "DbgHelp.Lib")
int GenerateMiniDump(PEXCEPTION_POINTERS pExceptionPointers)
{
// 定义函数指针
typedef BOOL(WINAPI * MiniDumpWriteDumpT)(
HANDLE,
DWORD,
HANDLE,
MINIDUMP_TYPE,
PMINIDUMP_EXCEPTION_INFORMATION,
PMINIDUMP_USER_STREAM_INFORMATION,
PMINIDUMP_CALLBACK_INFORMATION
);
// 从 "DbgHelp.dll" 库中获取 "MiniDumpWriteDump" 函数
MiniDumpWriteDumpT pfnMiniDumpWriteDump = NULL;
HMODULE hDbgHelp = LoadLibrary(_T("DbgHelp.dll"));
if (NULL == hDbgHelp)
{
return EXCEPTION_CONTINUE_EXECUTION;
}
pfnMiniDumpWriteDump = (MiniDumpWriteDumpT)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
if (NULL == pfnMiniDumpWriteDump)
{
FreeLibrary(hDbgHelp);
return EXCEPTION_CONTINUE_EXECUTION;
}
// 创建 dmp 文件件
TCHAR szFileName[MAX_PATH] = { 0 };
TCHAR szVersion[] = L"DumpFile";
SYSTEMTIME stLocalTime;
GetLocalTime(&stLocalTime);
wsprintf(szFileName, L"%s-%04d%02d%02d-%02d%02d%02d.dmp",
szVersion, stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond);
HANDLE hDumpFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
if (INVALID_HANDLE_VALUE == hDumpFile)
{
FreeLibrary(hDbgHelp);
return EXCEPTION_CONTINUE_EXECUTION;
}
// 写入 dmp 文件
MINIDUMP_EXCEPTION_INFORMATION expParam;
expParam.ThreadId = GetCurrentThreadId();
expParam.ExceptionPointers = pExceptionPointers;
expParam.ClientPointers = FALSE;
pfnMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hDumpFile, MiniDumpWithDataSegs, (pExceptionPointers ? &expParam : NULL), NULL, NULL);
// 释放文件
CloseHandle(hDumpFile);
FreeLibrary(hDbgHelp);
return EXCEPTION_EXECUTE_HANDLER;
}
LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS lpExceptionInfo)
{
// 这里做一些异常的过滤或提示
if (IsDebuggerPresent()) {
return EXCEPTION_CONTINUE_SEARCH;
}
return GenerateMiniDump(lpExceptionInfo);
}
long __stdcall errCallback(_EXCEPTION_POINTERS* pException)
{
// //用于崩溃重启
// // 信号量的意义,把操作共享内存的代码锁住。因为有可能同时启动, 防止并发
// QSystemSemaphore sema("DyError", 1, QSystemSemaphore::Open);
// sema.acquire();
QDir dir;
dir.mkdir("./dumps");
dir.cd("./dumps");
/*
***保存数据代码***
*/
QString fileName = dir.path() + "/" +
QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss.zzz") + ".dmp";
LPCWSTR pFileName = (LPCWSTR)fileName.unicode();
//创建 Dump 文件
HANDLE hDumpFile = CreateFile(pFileName,
GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
qDebug() << "create dumpFile:" << hDumpFile << INVALID_HANDLE_VALUE;
if(hDumpFile != INVALID_HANDLE_VALUE)
{
//Dump信息
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
dumpInfo.ExceptionPointers = pException;
dumpInfo.ThreadId = GetCurrentThreadId();
dumpInfo.ClientPointers = TRUE;
//写入Dump文件内容
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
}
// delete unimem;
// qDebug() << "start application:" << QProcess::startDetached(qApp->applicationFilePath(), QStringList());//重启
// qApp->quit();
qApp->exit(-1);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif // DUMPHELPER_H
调用函数
在main函数中注册
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include "DumpHelper.h"
int main(int argc, char *argv[])
{
// SetUnhandledExceptionFilter(ExceptionFilter); // dmp文件比较大
SetUnhandledExceptionFilter(errCallback); // dmp文件比较小
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
三、经由dmp文件查询崩溃原因
在我们写好程序,编译好,且发布了给客户时,一定要注意保存几个东西:此时的源码、此时的exe+pdb文件。
在给到客户的程序发生了崩溃,产生了dmp文件后,我们需要把我们当时发布的exe、pdb、客户发给我们的dmp文件放在一起,然后用vs打开,进行调试操作。
基本前提
能够查询溯源的前提是对软件发布时的东西做好了备份:源码、pdb、exe
下面以实例说明。
目前,有一个 versionTest 项目,经过编译后,发布了v1版本。内容如下:
并且,在发布时,我也备份了对应的源码、pdb文件
假设此时,用户发现软件崩溃了,在对应目录生成了dmp文件,他将文件发给了我。
1.将对应的dmp文件、exe文件、pdb文件拷贝你发布的一份程序目录下
2.用vs打开dmp文件,并执行调试
此时它可能会定位到你最新的代码那里去的。
3.自己手动定位一下真正源码位置
选择你之前备份的文件夹
自然就对上了。