C++(Qt)软件调试---Windows下Qt使用dump定位崩溃位置(1)

本文详细介绍了Windows环境下,如何使用Qt与C++开发时遇到崩溃问题,通过生成dump文件并结合Visual Studio和WinDbg工具进行定位。涵盖了dump文件的概念、如何在程序中设置异常处理生成dump,以及符号表的下载和调试步骤。
摘要由CSDN通过智能技术生成

C++(Qt)软件调试—Windows下Qt使用dump定位崩溃位置(1)

更多精彩内容
👉个人内容分类汇总 👈
👉C++软件调试、异常定位 👈

本文说的方法只适合Windows下MSVC编译器(不支持MinGW),如果需要跨平台可以👉看这一篇

1、Qt崩溃定位方法

方法1: 通过日志系统保存程序执行日志信息,在程序崩溃后通过日志信息可分析出程序进行了哪些操作;
方法2:

  • 日志信息并不是万能的,有些情况下日志信息不一定能分析出崩溃问题,这时就需要借助dump文件进行分析;
  • 当程序遇到未处理的异常导致程序崩溃,如果在异常发生之前调用了SetUnhandledExceptionFilter() 函数,异常交给函数处理。因而,在程序开始处增加SetUnhandledExceptionFilter()函数,并在函数中利用适当的方法生成Dump文件,保存崩溃位置信息。

2、 什么是dump文件

  • Dump文件通常是指程序或系统崩溃时,将内存中的数据转储并保存到磁盘文件中的一种文件格式。Dump文件包含了程序崩溃时的内存状态、寄存器状态、线程状态等信息,可以帮助开发人员诊断和解决故障。
  • Dump文件一般是以二进制格式保存在磁盘上,其内容包含了程序或系统崩溃时内存中的所有数据,包括代码、数据、栈、堆等。Dump文件的大小通常很大,可能达到几百MB或几GB,因此在进行分析和调试时需要使用专门的工具和技术。
  • 在Windows系统中,dump文件一般使用Windows的调试工具WinDbg来分析。WinDbg可以读取dump文件,并提供调试命令和分析工具,帮助开发人员进行故障诊断和调试。除了WinDbg,还有其他的调试工具和分析工具可以读取和分析dump文件,例如Visual Studio的调试器、QtCreator和第三方工具如IDA Pro等。

3、使用vs调试dmp

  1. 打开vs,选择继续但无需代码

    在这里插入图片描述

  2. 将dmp文件直接拖如vs中

    在这里插入图片描述

  3. 点击1️⃣【设置符号路径】,进行如下设置;

    1. 如果是第一次调试需要勾选Microsoft符号服务器2️⃣:会从网络下载调试使用的符号文件,然后将符号文件下载到5️⃣位置,以后就不需要勾选符号服务器了;
    2. 点击“+”号3️⃣添加【TestCrashHandler.pdb】6️⃣文件所在路径4️⃣

    在这里插入图片描述

  4. 点击 使用仅限本机进行调试

    在这里插入图片描述

  5. 成功定位到崩溃位置

    在这里插入图片描述

4、下载Windows符号表

如果勾选了Microsoft符号服务器或者NuGet.org服务器则可将window符号表下载到下列路径中,在离线环境中也可进行调试。

在这里插入图片描述

5、下载Qt符号表

这种方法可以选择下载部分调试符号表,体积比较小。

  1. 选择系统环境https://download.qt.io/online/qtsdkrepository/

    在这里插入图片描述

  2. 选择desktop

    在这里插入图片描述

  3. 选择安装的qt版本,我的时5.14.2

    在这里插入图片描述

  4. 选择调试编译器版本,我的是msvc2017-64

    在这里插入图片描述

  5. 下载需要调试的模块的符号表

    在这里插入图片描述

6、主要代码

  • 默认情况下只有Debug可用生成可用的dmp文件,Release对程序的编译进行了优化,并且不生成PDB符号文件,所以无法进行调试,如果想要Release可调试,需要在Pro文件进行下列设置。
msvc:CONFIG(release, debug|release) {
QMAKE_CFLAGS_RELEASE   -= -O2              # 取消C优化
QMAKE_CFLAGS_RELEASE   += -Zi              # 生成调试信息,放到pdb文件中
QMAKE_CXXFLAGS_RELEASE -= -O2              # 取消C++优化
QMAKE_CXXFLAGS_RELEASE += -Zi              # 生成调试信息
QMAKE_LFLAGS_RELEASE   -= /INCREMENTAL:NO  # 选择增量链接
QMAKE_LFLAGS_RELEASE   += /DEBUG           # 将调试信息放到PDB文件中
message(MSVC编译器Release关闭优化,生成调试信息使用)
}

mingw:CONFIG(release, debug|release) {
QMAKE_CFLAGS_RELEASE   -= -O2              # 取消C优化
QMAKE_CFLAGS_RELEASE   += -O0              # 显示指定禁止优化
QMAKE_CFLAGS_RELEASE   += -g               # 生成C调试信息
QMAKE_CXXFLAGS_RELEASE -= -O2              # 取消C++优化
QMAKE_CXXFLAGS_RELEASE += -O0              # 显示指定禁止优化
QMAKE_CXXFLAGS_RELEASE += -g               # 生成C++调试信息
QMAKE_LFLAGS_RELEASE   -= -Wl,-s           # 取消Release模式删除所有符号表和重新定位信息的设置
QMAKE_LFLAGS_RELEASE   += -g               # 链接器生成调试信息
message(Mingw编译器Release关闭优化,生成调试信息使用)
}

# 如果不加unix,MinGW也会进入这里
unix:gcc:CONFIG(release, debug|release) {
QMAKE_CFLAGS_RELEASE   -= -O2              # 取消C优化
QMAKE_CFLAGS_RELEASE   += -O0              # 显示指定禁止优化
QMAKE_CFLAGS_RELEASE   += -g               # 生成C调试信息
QMAKE_CXXFLAGS_RELEASE -= -O2              # 取消C++优化
QMAKE_CXXFLAGS_RELEASE += -O0              # 显示指定禁止优化
QMAKE_CXXFLAGS_RELEASE += -g               # 生成C++调试信息
QMAKE_LFLAGS_RELEASE   -= -Wl,-O1          # 取消Release模式链接器优化
QMAKE_LFLAGS_RELEASE   += -g               # 链接器生成调试信息
message(GCC编译器Release关闭优化,生成调试信息使用)
}
  • crashhandler.h
#ifndef CRASHHANDLER_H
#define CRASHHANDLER_H


class CrashHandler
{
public:
    CrashHandler(){}

    static void initCrashHandler();      // 初始化加载应用程序崩溃处理程序
};

#endif // CRASHHANDLER_H

  • crashhandler.cpp
#include "crashhandler.h"
#include <QMessageBox>
#include <QDateTime>
#include <qglobal.h>

#if defined(_MSC_VER)
#include <Windows.h>          // Windows.h必须放在DbgHelp.h前,否则编译会报错
#include <DbgHelp.h>
#elif defined(__MINGW32__)
#include <windows.h>          // MinGW下这两个头文件是小写
#include <dbghelp.h>
#endif

#if defined(_MSC_VER) && (_MSC_VER >= 1600) && (_MSC_VER <= 1900)
#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, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
    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, nullptr, nullptr);
    }
    //这里弹出一个错误对话框并退出程序
    EXCEPTION_RECORD* record = pException->ExceptionRecord;
    QString errCode(QString::number(quint64(record->ExceptionCode), 16));
    QString errAdr(QString::number(quint64(record->ExceptionAddress), 16));

    QMessageBox::critical(nullptr, "不会吧,程序居然发生异常了~","<FONT size=4><div><b>对于发生的错误,表示诚挚的歉意</b><br/></div>"+
                          QString("<div>错误代码:%1</div><div>错误地址:%2</div></FONT>").arg(errCode).arg(errAdr),
                          QMessageBox::Ok);

    return EXCEPTION_EXECUTE_HANDLER;
}
//#endif

// 在main函数中调用这个函数
void CrashHandler::initCrashHandler()
{
    SetUnhandledExceptionFilter(static_cast<LPTOP_LEVEL_EXCEPTION_FILTER>(ApplicationCrashHandler));   // 使用win API注册异常处理函数
}

6、源代码

gitee
github

Windows调试是一种通过分析崩溃时生成的dump文件来定位错误和问题的过程。dump文件是操作系统在程序崩溃时自动创建的一种保存程序状态和信息的文件。 通过dump文件定位崩溃的过程可以分为以下几个步骤: 1. 获取dump文件:当程序崩溃时,操作系统会自动创建一个dump文件,通常保存在程序的运行目录下。可以通过查看程序崩溃时的错误提示信息来确定dump文件的位置。 2. 安装符号文件:符号文件是包含程序源代码和编译器产生的调试信息的文件。在调试过程中,需要将符号文件与dump文件关联起来,以便能够查看和分析源代码。可以从官方网站下载对应版本的符号文件。 3. 打开dump文件:可以使用调试工具(如Visual Studio、WinDbg等)打开dump文件。在打开文件后,工具会加载符号文件,显示出崩溃时的堆栈信息。 4. 分析堆栈信息:堆栈信息显示了程序崩溃时的函数调用情况。从堆栈信息中,可以定位到导致崩溃的函数和代码所在的位置。通过查看源代码,可以进一步分析和解决错误。 5. 调试程序:在分析崩溃原因后,可以使用调试工具来逐步执行程序,观察变量的值和执行的过程,以便定位错误。可以设置断点、观察变量、修改变量的值等操作,帮助分析和解决问题。 通过以上步骤,我们可以利用dump文件进行Windows调试,快速定位程序崩溃的原因,并解决问题。调试过程需要了解一定的调试技巧和工具的使用方法,同时对于程序的结构和运行过程有一定的了解,这样才能更好地定位和解决问题。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mahuifa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值