跳转至

QT Mingw编译通过Dump文件查看源码报错的位置

文件中创建并生成Dump文件

使用以下代码创建并生成Dump文件

#include <windows.h>
#include <dbghelp.h>
#include <QDateTime>
#include <QMessageBox>
#include <QTextCodec>

LONG CreateCrashHander(EXCEPTION_POINTERS *pException)
{
    if (!pException) {  // 防止空指针崩溃
        QMessageBox::warning(NULL, "错误", "异常指针为空!", QMessageBox::Ok);
        return EXCEPTION_CONTINUE_SEARCH;
    }

    // 获取应用程序工作目录路径(程序运行时所在的目录)
    QString appWorkPath = QCoreApplication::applicationDirPath();

    // 1. 生成合法的文件名(不含非法字符)
    QDateTime CurrentDTime = QDateTime::currentDateTime();
    QString CurrentDtimeStr = CurrentDTime.toString("yyyy-MM-dd hh-mm-ss");  // 用-替代:
    // 获取用户文档目录(确保有写入权限)
    QString dumpText = appWorkPath + "/Dump_" + CurrentDtimeStr + ".dmp";  // 完整路径

    // 2. 创建文件(显式使用宽字符版本CreateFileW)
    HANDLE DumpHandle = CreateFileW(
        (LPCWSTR)dumpText.utf16(),  // 宽字符路径
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );

    // 3. 处理文件创建失败的情况
    if (DumpHandle == INVALID_HANDLE_VALUE) {
        DWORD errorCode = GetLastError();  // 获取系统错误代码
        QMessageBox::critical(NULL, "创建dump失败",
                            QString("无法创建dump文件!\n路径:%1\n错误代码:%2")
                            .arg(dumpText).arg(errorCode),
                            QMessageBox::Ok);
        return EXCEPTION_EXECUTE_HANDLER;
    }

    // 4. 生成minidump(使用更完整的类型)
    MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
    dumpInfo.ExceptionPointers = pException;
    dumpInfo.ThreadId = GetCurrentThreadId();
    dumpInfo.ClientPointers = TRUE;

    // 调用MiniDumpWriteDump生成dump
    BOOL success = MiniDumpWriteDump(
        GetCurrentProcess(),
        GetCurrentProcessId(),
        DumpHandle,
        MiniDumpWithFullMemory,  // 包含完整内存信息
        &dumpInfo,
        NULL,
        NULL
    );

    if (!success) {
        QMessageBox::warning(NULL, "生成dump失败",
                            QString("MiniDumpWriteDump调用失败!错误代码:%1")
                            .arg(GetLastError()),
                            QMessageBox::Ok);
    }

    CloseHandle(DumpHandle);  // 关闭文件句柄

    // 5. 显示崩溃信息
    EXCEPTION_RECORD *record = pException->ExceptionRecord;
    QString errCode = QString::number(record->ExceptionCode, 16).toUpper();
    QString errAddr = QString::number((quint64)record->ExceptionAddress, 16).toUpper();
    QString errFlag = QString::number(record->ExceptionFlags, 16).toUpper();
    QString errPara = QString::number(record->NumberParameters, 16).toUpper();

    QMessageBox::warning(NULL, "程序崩溃",
                        QString("错误代码:0x%1\n错误地址:0x%2\n错误标志:0x%3\n参数数量:0x%4\nDump文件已保存至:%5")
                        .arg(errCode).arg(errAddr).arg(errFlag).arg(errPara).arg(dumpText),
                        QMessageBox::Ok);

    return EXCEPTION_EXECUTE_HANDLER;
}


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

    QTextCodec *codec=QTextCodec::codecForLocale();
    QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());

    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)CreateCrashHander);

    for(int i=10;i>=0;i--){
        int a = 10/i;
    }

    w.show();
    return a.exec();
}

代码想要运行还需要再pro文件中增加相关lib库

LIBS += -ldbghelp

为了生成的代码能够输出调试信息,在pro文件中增加以下内容

QMAKE_CXXFLAGS += -g -O0
QMAKE_LFLAGS += -g

代码编译如果崩溃,就会在目录下生成dump文件

后面release试了以下

# ========== 调试信息配置 ==========
# Debug 模式:默认有 -g,不动
# Release 模式:额外加上 -g,同时保留优化
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE += -O2 -g

# 避免 Release 链接时 strip 掉符号
QMAKE_LFLAGS_RELEASE -= -s

# MSVC 下也强制生成 PDB(Release 模式)
win32-msvc* {
    QMAKE_CXXFLAGS_RELEASE += /Zi
    QMAKE_LFLAGS_RELEASE   += /DEBUG /INCREMENTAL:NO
}

后面发现好像不用这么麻烦,用下面指令就行了,但是带上debuginfo的应用程序会大很多。

CONFIG += force_debug_info

查看错误信息

addr2line

源代码不能改,改了就和生成的错误信息对不上了。

你在 Windows + MinGW + Qt 下,生成的 dump 文件里会有崩溃地址(ExceptionAddress)。 例如:

错误地址:0x401523

这时就可以用 addr2line 去查源码位置:

addr2line -e your_program.exe 0x401523

输出可能是:

C:/Users/you/project/main.cpp:42

表示崩溃发生在 main.cpp 第 42 行。

  1. 你的程序必须是 带调试信息编译的-g 选项)。
    在 Qt 项目的 .pro 文件里可以加:

    QMAKE_CXXFLAGS += -g

  2. 不要去掉符号(也就是不要加 -s strip)。

gdb

输入gdb加上应用程序名字

gdb JYSWJ.exe

然后使用list查看

list *0x402556