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

发布于:2025-08-06 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、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:\package

set CV2PDB_HOME=%~dp0
CHDIR /D  %OBJECT_HOME%

set COMPILE_BIN=%OBJECT_HOME%\bin

echo "step1: del *.pdb..."
del *.pdb

echo "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:\package

set CV2PDB_HOME=%~dp0
CHDIR /D  %OBJECT_HOME%

set COMPILE_LIB=%OBJECT_HOME%\lib

echo "step1: del *.pdb..."
del *.pdb

echo "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" )


网站公告

今日签到

点亮在社区的每一天
去签到