1、前言

在一次Qt编程时,使用到第三方库,但是第三方库是Release版本,所以Qt开发也需要是Release版本,但是无法直接Debug调试,需要进行设置,另外为了生成exe后,可以通过WinDbg排查程序崩溃问题,在此进行记录,方便自己后续查看。

项目为QtCreator,使用MSVC2017 64bit编译

2、Qt在Release模式下调试并生成.pdb文件

在项目的.pro文件中添加如下设置,并右键项目,按照顺序依次选择qmake、重新构建项目

QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO

在生成项目后,exe目录中会同时生成.pdb文件

此时已经可以再QtCreator中在Release模式时正常Debug调试了

3、WinDbg调试Dump文件

3.1、将程序崩溃时的执行信息保存为dump文件

这部分网上文章较多,在windows系统下的主要思路是:

  1. 使用SetUnhandledExceptionFilter注册程序的异常捕获回调函数;

  2. 将捕获的异常通过MiniDumpWriteDump函数保存。

注意:需要先在.pro文件里加入LIBS += -lDbgHelp

#pragma execution_character_set("utf-8")

#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include <QDir>
#include <QDebug>
#include <QDateTime>
#include <QTextCodec>
#include <windows.h>
#include <DbgHelp.h>

// 保存程序异常崩溃的信息
LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException)
{
    //初始化dump文件夹
    QString logFilePath = QCoreApplication::applicationDirPath() + "/DumpCrashes/";
    QDir dstDir(logFilePath);
    if(!dstDir.exists())
    {
        if(!dstDir.mkpath(logFilePath))
        {
            qDebug()<<__FILE__<<__LINE__<<"创建DumpCrashes文件夹失败!";
        }
    }

    //创建Dump文件
    QString dumpFileName = logFilePath + QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss") + ".dmp";
    HANDLE hDumpFile = CreateFile((LPCWSTR)(dumpFileName.toStdWString().c_str()), 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, (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithProcessThreadData | MiniDumpWithUnloadedModules), &dumpInfo, NULL, NULL);
    }

    //这里弹出一个错误对话框并退出程序
    EXCEPTION_RECORD* record = pException->ExceptionRecord;
    QString errCode(QString::number(record->ExceptionCode,16));
    QString errAddr(QString::number((uint)record->ExceptionAddress,16));
    QMessageBox::critical(NULL,"错误",QString("程序异常崩溃捕获!\nerrCode:%1 \nerrAddr:%2").arg(errCode.toStdString().c_str()).arg(errAddr.toStdString().c_str()));

    return EXCEPTION_EXECUTE_HANDLER;
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    //注冊异常捕获函数
    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);   

    MainWindow w;
    w.show();

    return a.exec();
}

此时,当出现运行崩溃时,将会弹出提示框,提示异常捕获,并在exe所在目录中出现“DumpCrashes”文件夹,在文件夹中存在以异常出现日期时间为文件名的.dmp后缀文件(此项目为了测试而设置了明显的崩溃问题)

3.2、使用 WinDbg 分析dump文件
  1. 打开WinDbg(x64)(windbg.exe);
  2. File —> Symbol File Path,设置.pdb文件所在的文件夹注意是文件夹,而不是文件);
  3. File —> Source File Path,设置release版本的.exe执行文件所在的文件夹
  4. File —> Open Crash Dump,打开crash.dmp文件。

出现Command窗口

3.3、在窗口中进行代码分析

点击或在下方输入栏输入!analvze -v并回车

!analvze -v

点击或在下方输入栏输入.excr 切换到发生异常的线程上下文中

.excr

将会打开源码中报错位置与代码

4、最后

以上方法为本人测试使用,如有问题,欢迎指正。

另外,参考了Qt程序Release版本记录崩溃信息,并定位问题代码以及Windows下Release版本Qt程序生成日志和dump文件(用于程序异常崩溃检测)两位大佬的文章,感谢大佬的分享。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐