更多精彩内容 |
---|
个人内容分类汇总 |
C++软件调试、异常定位 |
本文说的方法只适合Windows下MSVC编译器(不支持MinGW),如果需要跨平台可以看这一篇
方法1: 通过日志系统保存程序执行日志信息,在程序崩溃后通过日志信息可分析出程序进行了哪些操作;
方法2:
打开vs,选择继续但无需代码
将dmp文件直接拖如vs中
点击1️⃣【设置符号路径】,进行如下设置;
点击 使用仅限本机进行调试
成功定位到崩溃位置
如果勾选了Microsoft符号服务器或者NuGet.org服务器则可将window符号表下载到下列路径中,在离线环境中也可进行调试。
这种方法可以选择下载部分调试符号表,体积比较小。
选择系统环境https://download.qt.io/online/qtsdkrepository/
选择desktop
选择安装的qt版本,我的时5.14.2
选择调试编译器版本,我的是msvc2017-64
下载需要调试的模块的符号表
默认情况下只有Debug可用生成可用的dmp文件,Release对程序的编译进行了优化,并且不生成PDB符号文件,所以无法进行调试,如果想要Release可用调试,需要在Pro文件进行下列设置
# 在Release生成用于调试dump的信息,包括【禁用release编译优化】、【生成PDB符号表】,但是这些设置会降低程序性能,和debug差不多
CONFIG(release, debug|release) {
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE += -O0
QMAKE_CXXFLAGS_RELEASE += /Zi
QMAKE_LFLAGS_RELEASE += /DEBUG /OPT:REF /OPT:ICF # 生成 PDB符号文件,功能和下一行一样,但是最好用这一行,显示指定编译选项
# QMAKE_LFLAGS_RELEASE += $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO
# 打印变量参数值
message(QMAKE_CXXFLAGS_RELEASE变量值:$$QMAKE_CXXFLAGS_RELEASE)
message(QMAKE_LFLAGS_RELEASE变量值:$$QMAKE_LFLAGS_RELEASE)
}
main.cpp
#include "crashhandler.h"
#include
#include
#include
#ifdef _MSC_VER
#include // Windows.h必须放在DbgHelp.h前,否则编译会报错
#include
#endif
//MSVC编译器
#ifdef _MSC_VER
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
#pragma execution_character_set("utf-8")
#endif
/**
* @brief 应用程序崩溃处理程序
* @param pException
* @return EXCEPTION_EXECUTE_HANDLER equ 1 表示我已经处理了异常,可以优雅地结束了
* EXCEPTION_CONTINUE_SEARCH equ 0 表示我不处理,其他人来吧,于是windows调用默认的处理程序显示一个错误框,并结束(qt中会导致窗口卡死一段时间)
* EXCEPTION_CONTINUE_EXECUTION equ -1 表示错误已经被修复,请从异常发生处继续执行
*/
LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException){//程式异常捕获
//创建 Dump 文件
QString strPath = QString("%1.dmp").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH-mm-ss"));
#ifdef UNICODE
LPCWSTR filePath = reinterpret_cast<LPCWSTR>(strPath.utf16());
#else
LPCSTR filePath = reinterpret_cast<LPCSTR>(strPath.toStdString().data());
#endif // !UNICODE
HANDLE hDumpFile = CreateFile(filePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
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);
}
//这里弹出一个错误对话框并退出程序
EXCEPTION_RECORD* record = pException->ExceptionRecord;
QString errCode(QString::number((quint64)record->ExceptionCode, 16));
QString errAdr(QString::number((uint)record->ExceptionAddress, 16));
QMessageBox::critical(nullptr, "程式崩溃","对于发生的错误,表示诚挚的歉意
"+
QString("错误代码:%1错误地址:%2").arg(errCode).arg(errAdr),
QMessageBox::Ok);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif
void CrashHandler::initCrashHandler()
{
#ifdef _MSC_VER
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler); // 使用win API注册异常处理函数
#endif
}
gitee
github