当前位置: 首页 > news >正文

Windows下定位Mingw编译的Qt程序崩溃堆栈

一、dump和pdb是什么

        在Windows系统下,当我们写的程序跑在客户的机器上,因为一个bug,导致程序崩溃,我们该如何定位并修复这个bug呢?

        有人会说记录日志,即便有日志,也是不好定位的,因为你只能推测出大概的模块或者位置,无法定位到具体出错的代码行。

        此时,我们可以让程序崩溃后,自动生成一个*.dmp文件,并配合在编译该程序时生成的pdb文件,来准确定位到调用堆栈、代码行上。这样很轻易就可以找到该bug。

  • dump文件,后缀*.dmp,是程序崩溃时的内存转储文件;

  • pdb文件,后缀*.pdb,是程序的符号文件。

二、Breakpad与qbreakpad简介

        Breakpad是由Google开发的开源跨平台崩溃报告系统,用于捕获程序崩溃时的内存状态并生成轻量级minidump文件(.dmp)。其核心功能包括崩溃拦截、堆栈记录和寄存器状态捕获,适用于C++应用的多平台部署(Windows/Linux/macOS)‌。

        QBreakpad是Breakpad的‌Qt专用封装库‌,它将Breakpad的复杂集成简化为Qt模块,提供更便捷的API和跨平台兼容性,专门服务于Qt应用程序的崩溃管理‌。

        BreakPad工作原理示意图:

表达的意思就是:

  • 我们在编译的时候,需要在Release版程序中生成调试信息。

  • 使用Breakpad提供的dump_syms工具或者cv2pdb工具,从release版本程序导出符号文件。

  • 当程序崩溃时,breakpad会捕捉崩溃,并生成dump文件。

  • dump文件可以直接发送到指定服务器,或者由用户手动发给开发者。

  • 收到dump文件后,结合符号文件,可通过minidump_stackwalk工具或Visual Studio工具生成堆栈调用信息文件,这个文件可以直接阅读,定位bug。

三、开发环境说明

        本人使用的开发环境如下:

        操作系统:Windows10

        IDE:Qt Creator4.4.1

        编译器:mingw53_32

        Qt库:Qt5.9.3 

四、源码准备

        我们知道qBreakpad是对Breakpad的封装,所以qBreakpad的编译,还依赖2套源码Breakpad、LSS。

(1)下载Breakpad源码

下载地址:https://github.com/google/breakpad

(2)下载LSS源码

下载地址:https://github.com/ithaibo/linux-syscall-support

(3)下载qBreakpad源码

下载地址:https://github.com/buzzySmile/qBreakpad

 (4)下载cv2pdb工具

下载地址:

注意:这个工具最好下载最新版本的,作者发布本文时,最新版本是cv2pdb 0.53

五、编译qBreakpad

(1)将Breakpad、LSS源码放入third_party目录

        解压qBreakpad源码后,在qBreakpad-master\third_party目录下,有如下2个目录,如下:

        分别解压Breakpad、LSS源码至breakpad和lss目录,此2个目录下源码需要参与qBreakpad的编译。放置好后,如下所示:

(2)qBreakpad工程介绍

        在qBreakpad源码目录下,使用QtCreator打开qBreakpad.pro工程,如下:

  • demo工程下,有2个演示程序program和reporter,分别实现了演示生成dump文件,上报dump文件的功能。

  • handler为静态库工程,该工程封装了Breakpad,直接编译此工程,可生成qBreakpad.lib。

  • tests为一个简单的测试工程。

(3)编译生成qBreakpad.lib

        分别在Debug、Release模式下,编译handler工程,生成2个版本的qBreakpad.lib静态库。

因为程序调用qBreakpad.lib时,只能debug版程序链接debug版库,release版程序链接release版库。debug版程序链接release版库会报错。

(4)编译生成demo

      在program.pro文件添加下图所示内容,目的是编译release版程序时生成调试信息:

############ for qBreakpad ############
# qBreakpad中需要使用到network模块
QT += network# 启用多线程、异常、RTTI、STL支持
CONFIG += thread exceptions rtti stl# without c++11 & AppKit library compiler can't solve address for symbols
CONFIG += c++11
macx: LIBS += -framework AppKit# 启用调试信息(关键!)
QMAKE_CXXFLAGS += -g
QMAKE_CXXFLAGS_RELEASE += -g
QMAKE_CFLAGS_RELEASE += -g
#release在最后link时默认有"-s”参数,表示"Omit all symbol information from the output file",因此要去掉该参数
QMAKE_LFLAGS_RELEASE = -mthreads -Wl,# 配置头文件搜索路径和链接库路径
INCLUDEPATH += $$PWD/qBreakpad/include
CONFIG(debug, debug|release) {
LIBS += -L$$PWD/qBreakpad/lib/debug -lqBreakpad
} else {
LIBS += -L$$PWD/qBreakpad/lib/release -lqBreakpad
}
############ for qBreakpad ############

 

      在main函数添加以下内容,启用崩溃时生成.dmp文件的功能:

六、生成.pdb文件

        将program这个demo程序编译出release版本:

        可见这个demo程序编译出来后体积是比较大的:

        然后将前面下载的cv2pdb工具解压放到目标程序同一个目录:

        在这个目录打开终端,执行命令生成.pdb文件:

cv2pdb.exe   目标程序.exe

        执行成功后,会在目标程序的同级目录下生成.pdb文件,同时也可以看到目标程序的体积变小了:

七、通过.dmp文件追踪程序崩溃的堆栈信息

        运行前面生成的test.exe文件,程序崩溃后会生成.dmp文件:

        使用Visual Studio打开.dmp文件,这里以Visual Studio2022为例:

        点击上图中的“设置符号路径”,将.pdb文件所在路径添加进去:

        击下图中的“使用仅限本机进行调试”:

        如下图所示,可以看到程序崩溃时的堆栈调用情况:

        双击堆栈调用的行内容,将源码文件路径设置一下,便可查看源码及变量的实时值。

八、总结

        在Windows系统下,使用Mingw编译器编译出来的程序,重点和难点是如何生成.pdb文件。而生成.pdb文件的重点有两方面,一是在.pro文件添加-g编译参数,二是使用cv2pdb工具的最新版本,旧版本的cv2pdb工具可能无法生成.pdb文件(这一点困扰了我好久)。

        如果应用程序调用了很多自己开发的动态库,那么动态库的.pro文件也需要添加-g编译参数,并且动态库也需要用cv2pdb工具生成.pdb文件。

        最后,为了方便提取多个文件的.pdb文件,本人写了2个批处理脚本,一个用于提取.exe文件,另一个用于提取.dll文件,我将脚本给出,供大家参考:

        批量提取D:\package\bin目录下所有exe文件的pdb:

@echo off
echo Hello,I am processing pdb files...set OBJECT_HOME=D:\packageset CV2PDB_HOME=%~dp0
CHDIR /D  %OBJECT_HOME%set COMPILE_BIN=%OBJECT_HOME%\binecho "step1: del *.pdb..."
del *.pdbecho "step2: create *.pdb..."set FILE_TYPE_EXE=*.exe
for /r "%COMPILE_BIN%" %%i in (%FILE_TYPE_EXE%)do ( if exist %%i %CV2PDB_HOME%/cv2pdb.exe "%%i" )

        批量提取D:\package\lib目录下所有dll文件的pdb:

@echo off
echo Hello,I am processing pdb files...set OBJECT_HOME=D:\packageset CV2PDB_HOME=%~dp0
CHDIR /D  %OBJECT_HOME%set COMPILE_LIB=%OBJECT_HOME%\libecho "step1: del *.pdb..."
del *.pdbecho "step2: create *.pdb..."set FILE_TYPE_EXE=*.dll
for /r "%COMPILE_LIB%" %%i in (%FILE_TYPE_EXE%)do ( if exist %%i %CV2PDB_HOME%/cv2pdb.exe "%%i" )

http://www.dtcms.com/a/311834.html

相关文章:

  • Python科研数据可视化技术
  • 2025年常见网络安全问题及针对性预防措施
  • 小迪23年-22~27——php简单回顾(2)
  • pytorch的 Size[3] 和 Size[3,1] 区别
  • 动态规划Day7学习心得
  • 深入理解Linux线程:从概念到控制的最佳实践
  • jenkins从入门到精通-P1—九五小庞
  • Python编程基础与实践:Python函数编程入门
  • 基于Redis自动过期的流处理暂停机制
  • day38 力扣279.完全平方数 力扣322. 零钱兑换 力扣139.单词拆分
  • 位运算-371.两整数之和-力扣(LeetCode)
  • 2 安装 Docker 和 Jenkins:持续构建环境起步
  • Chisel芯片开发入门系列 -- 17. CPU芯片开发和解释7(5级流水线指令原理)
  • 洛谷 P3372 【模板】线段树 1-普及+/提高
  • 【AI学习】RadioDiff:代码学习
  • Paper Reading《TrafficFormer: An Efficient Pre-trained Model for Traffic Data》
  • 【MQ】kafka同步和异步的区别
  • Windows中使用Qwen模型:VSCode+Cline
  • 64GB U盘实际显示容量为57.2GB的原因解析
  • innoDB的buffer pool
  • Wasatch SoftRIP数码打印 印花软件
  • 谷歌开源Agent框架ADK快速入门
  • 深入理解 Go 语言中 Map 的底层原理
  • Python爬虫实战:研究SimpleCV技术,构建图像获取及处理系统
  • Apache Doris数据库——大数据技术
  • 【LeetCode刷题指南】--二叉树的前序遍历,二叉树的中序遍历
  • MCP Agent 工程框架Dify初探
  • pytorch简单理解
  • 我的世界之战争星球 暮色苍茫篇 第二十六章、身世
  • 分布在内侧内嗅皮层的层Ⅱ或层Ⅲ的头部方向细胞(head direction cells)对NLP中的深层语义分析的积极影响和启示