软件调试
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
-
打开vs,选择继续但无需代码

-
将dmp文件直接拖如vs中

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

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

-
成功定位到崩溃位置

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

5、下载qt符号表
这种方法可以选择下载部分调试符号表,体积比较小。
-
选择系统环境https://download.qt.io/online/qtsdkrepository/

-
选择desktop

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

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

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

6、主要代码
-
默认情况下只有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 <qmessagebox> #include <qdatetime> #include <qglobal.h> #ifdef _msc_ver #include <windows.h> // windows.h必须放在dbghelp.h前,否则编译会报错 #include <dbghelp.h> #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, "程式崩溃","<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 void crashhandler::initcrashhandler() { #ifdef _msc_ver setunhandledexceptionfilter((lptop_level_exception_filter)applicationcrashhandler); // 使用win api注册异常处理函数 #endif }
发表评论