• Qt使用qBreakpad定位崩溃位置


    C++(Qt)软件调试—Qt使用qBreakpad定位崩溃位置(2)

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


    Windows下封装的崩溃报告模块

    如果找不到在哪下载可以下载我准备好的

    • CSDN
    • 百度网盘:链接:https://pan.baidu.com/s/1AgGSi6kDtTfVrNGlXNsSqA 提取码:vetg

    前言

    1、Google - Breakpad

    • Breakpad 是 Google 公司开发的开源 跨平台C++崩溃检测库。
    • Breakpad可以捕获发布给用户的应用程序的崩溃,并记录软件崩溃的调试信息到 minidump 文件中。
    • 调试信息包括错误行号,报错详情,堆栈错误(stack traces)。

    2、qBreakpad

    • qBreakpad 是 Qt 库,用于使用 google-breakpad 崩溃报告工具(并方便地使用它)。支持

      • Windows(但故障转储解码不适用于 MinGW 编译器)
      • Linux
      • macOS X
    • 地址

    3、crashpad

    • Crashpad 是 Google 构建的最新开源崩溃报告工具,是流行的 Breakpad 崩溃报告器的继任者。 Crashpad 允许您在产品发生崩溃后将小型转储提交到配置的 URL。
    • 这里没有使用crashpad,以后再慢慢了解。

    4、注意

    • dmp文件、pdb文件、可执行程序、源码 版本一定要一致,否则可能无法调试。

    Linux下

    1、环境

    • 系统:ubuntu20.04.1、ubuntu22.04
    • Qt版本:Qt5.14.2

    2、qBreakpad源码准备

    • 可用下载我打包修改好的源码,包含了依赖文件

      git clone https://gitee.com/mahuifa/q-breakpad.git
      
      • 1
    • 下载qBreakpad

      git clone https://github.com/buzzySmile/qBreakpad.git
      
      • 1
    • 进入依赖文件夹third_party

      cd qBreakpad/third_party
      
      • 1

      在这里插入图片描述

      • 打开README文件,可以看见我们还需要下载breakpadlinux-syscall-support两个仓库,由于这两个仓库地址不方便访问,但是在github上也有,所以直接在Github下载就可以

      在这里插入图片描述

    • 下载依赖仓库,注意: 是在qBreakpad/third_party文件夹下下载,或者下载后移动到qBreakpad/third_party文件夹下

      # breakpad
      git clone https://github.com/google/breakpad.git
      # linux-syscall-support
      git clone https://github.com/adelshokhy112/linux-syscall-support.git
      
      
      # 然后将 breakpad 放至qBreakpad/third_party/beakpad
      # 然后将 linux-syscall-support下的lss 放至qBreakpad/third_party
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    3、qBreakpad编译

    • 进入qBreakpad/handler文件夹

      cd qBreakpad/handler
      
      • 1
    • 使用qtcreator 打开handler.pro

      在这里插入图片描述

    • 选择Release模式,点击锤子开始编译

      在这里插入图片描述

    • 编译完成后会在handler 文件夹下生成一个libqBreakpad.a文件,这就编译完成了

      在这里插入图片描述

    4、测试qBreakpad

    • qBreakpad/demo/program/program.pro工程

      在这里插入图片描述

      在这里插入图片描述

    • 编译后发现报了如下3个错误信息,错误信息大概是google_breakpad::PEFile::TryGetDebugInfo未定义

      在这里插入图片描述

    • 打开minidump_writer.cc文件,搜索TryGetDebugInfo,找到如下位置

      在这里插入图片描述

    • 按着Ctrl键,鼠标点击TryGetDebugInfo,进入到pe_file.h头文件,这里是声明,那没定义大概是没有包含cc文件或者cpp文件

      在这里插入图片描述

    • 将鼠标放到下列位置就可以知道头文件位置了

      在这里插入图片描述

    • 发现pe_file.h头文件在qBreakpad/third_party/breakpad/src/client/linux/minidump_writer文件夹下,进入该文件夹后发现了pe_file.cc文件

      在这里插入图片描述

    • 在breakpad.pri文件夹中如下位置加入$$BREAKPAD_PATH/client/linux/minidump_writer/pe_file.cc \,然后将build-handler-Desktop_Qt_5_14_2_GCC_64bit-Release文件夹删除后重新编译handler.pro

      在这里插入图片描述

    • 编译完成后再去编译program.pro 就不会报错了,program.pro编译运行后会崩溃(正常情况,特意写的异常用于生成dmp文件),program.pro生成的可执行程序为test

      在这里插入图片描述

    • 进入可执行程序路径下,会发现生成了一个crashes 文件夹,dmp 文件就放在这个文件夹下

      在这里插入图片描述

      这个文件夹名称是在main.cpp文件中由QBreakpadInstance.setDumpPath("crashes");指定的。

      在这里插入图片描述

    5、dump文件调试

    • 由于dmp文件不能直接查看,定义崩溃位置,这里需要使用到2个工具
      • dump_syms:由beakpad编译生成,使用 dump_syms读取调试信息并生成Breakpad 符号文件;
      • minidump_stackwalk:由beakpad编译生成,minidump_stackwalk可以获取一个minidump及其相应的符号,并产生一个符号化的崩溃位置信息;
    5.1 编译breakpad
    • 想要生成dump_syms、minidump_stackwalk 两个文件就需要编译breakpad,由于之前编译qBreakpad已经下载breakpad源码,这里就不需要再下载了;
    • lss文件夹移动到 breakpad/src/third_party/ 路径下

    在这里插入图片描述

    cd breakpad/           # 进入breakpad文件夹
    mkdir build            # 创建一个build文件夹
    sudo chmod -R 777 ./   # 修改所有文件的权限
    cd build/              # 进入build文件夹
    ../configure           # 开始配置
    sudo make              # 使用make构建编译
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 使用make 编译时可能会出现下列错误,根据错误提示打开breakpad/src/third_party/lss/linux_syscall_support.h:文件,定位到2408行,将"rsp"删除

      ../src/third_party/lss/linux_syscall_support.h: In member function ‘bool google_breakpad::ExceptionHandler::GenerateDump(google_breakpad::ExceptionHandler::CrashContext*)’:
      ../src/third_party/lss/linux_syscall_support.h:2408:75: error: listing the stack pointer register ‘rsp’ in a clobber list is deprecated [-Werror=deprecated]
       2408 |                              : "rsp", "memory", "r8", "r10", "r11", "rcx");
      
      • 1
      • 2
      • 3

      在这里插入图片描述

    • 删除后如下所示,然后保存修改,重新使用sudo make 构建

      在这里插入图片描述

    • 重新编译后又出现了新的错误,错误信息提示strcmp不是std成员,strcmp位于string.h文件夹中

      ../src/common/dwarf/elf_reader.cc: In constructor ‘google_breakpad::ElfSectionReader<ElfArch>::ElfSectionReader(const char*, const string&, int, const typename ElfArch::Shdr&)’:
      ../src/common/dwarf/elf_reader.cc:200:15: error: ‘strcmp’ is not a member of ‘std’; did you mean ‘strcmp’?
        200 |     if ((std::strcmp(name, ".strtab") == 0 ||
            |               ^~~~~~
      In file included from ../src/common/dwarf/elf_reader.cc:35:
      /usr/include/string.h:137:12: note: ‘strcmp’ declared here
        137 | extern int strcmp (const char *__s1, const char *__s2)
            |            ^~~~~~
      ../src/common/dwarf/elf_reader.cc:201:15: error: ‘strcmp’ is not a member of ‘std’; did you mean ‘strcmp’?
        201 |          std::strcmp(name, ".shstrtab") == 0) &&
            |               ^~~~~~
      In file included from ../src/common/dwarf/elf_reader.cc:35:
      /usr/include/string.h:137:12: note: ‘strcmp’ declared here
        137 | extern int strcmp (const char *__s1, const char *__s2)
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

      在这里插入图片描述

    • 根据错误提示打开breakpad/src/common/dwarf/elf_reader.cc文件,将所有std::strcmp替换成strcmp,然后保存重新编译就可以编译通过了

      在这里插入图片描述

    • 执行sudo make install 安装编译后的breakpad。

    5.2 开始分析dmp文件
    • 进入可执行程序当前文件夹,使用dump_syms生成 符号文件,test 是program工程生成的可执行程序。

      dump_syms test > test.sym
      
      • 1

      在这里插入图片描述

    • program工程源码当前路径下创建symbols/test/B84C09F0458DE588E280087B600FDCC80三级文件夹

      • 第一级目录,固定为symbols
      • 第二级目录,为即将放入的符号文件名称,如test.sym,则目录名为test
      • 第三级目录,在sym文件中第一行内容,有一串16进制编号,将其作为目录名。如下图所示:

      在这里插入图片描述

    • 将test.sym文件移动到symbols/test/B84C09F0458DE588E280087B600FDCC80文件夹下

    • 将包含dmp 文件的crashes文件夹也移动到program工程源码路径下,如下图所示

      在这里插入图片描述

    • 使用minidump_stackwalk 生成堆栈跟踪信息

      minidump_stackwalk crashes/470c3ed4-d8f5-470c-17786f91-4280144e.dmp symbols/ > error.log
      
      • 1
    • 打开error.log文件,根据可执行程序名称test 找到奔溃位置位于TestThread类crash()函数中,具体在TestThread.cpp文件的第34行。

      在这里插入图片描述

      在这里插入图片描述

    • 注意:目前测试来看除零异常可用定位到文件、函数、行号,但是空指针异常很难定位到(不知道是不是我操作问题)

      • 使用QWidget的空指针异常无法定位到,使用int空指针异常可用定位到。

      • 在这里插入图片描述

      • 在这里插入图片描述

    Windows下

    windows下如果不想这么麻烦的编译qBreakPad或者不考虑跨平台,可以使用我封装的crashhandler模块。

    1、环境

    • Windows10
    • Qt版本:Qt5.12.5
    • 编译器版本:msvc2017_64

    2、源码准备

    • 使用到的源码和Linux下一样

      • qBreakpad
      • breakpad 放至qBreakpad/third_party/beakpad
      • linux-syscall-support下的lss 放至qBreakpad/third_party

      在这里插入图片描述

      在这里插入图片描述

    3、qBreakpad编译

    • 进入qBreakpad/handler文件夹,双击打开handler.pro

      在这里插入图片描述

    • 注意编译器一定要选择MSVC,不能使用MinGW,这里演示就使用Release,如果需要Debug也是差不多的;

      • 打开handler.pro后选择Release,然后点击左下角的锤子,等待编译。

      在这里插入图片描述

    • 编译成功后会在qBreakpad\handler文件夹下生成一个qBreakpad.lib 文件

      在这里插入图片描述

    • 因为后续调用qBreakpad需要使用到qBreakpad.pri模块,这里使用文本编辑器打开qBreakpad.pri文件,加入下列两行代码,否则Release程序编译时不会生成.pdb符号文件;

    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关闭优化,生成调试信息使用)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    4、测试qBreakpad

    • qBreakpad/demo/program/program.pro工程,如下图所示

      在这里插入图片描述

    • 直接点击左下角在这里插入图片描述
      开始编译运行,编译完成后程序运行就会崩溃,然后打开可执行程序路径,会发现生成

      • crashes文件夹:存放dump文件
      • test.pdb:符号文件

      在这里插入图片描述

    • 只要生成pdb、dmp两个文件就说明已经成功使用qBreakpad捕获了崩溃信息。

    5、dump文件调试

    • 打开Visual Studio,将生成的dmp文件直接拖进vs中

      在这里插入图片描述

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

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

      在这里插入图片描述

    • 设置完成后点击【确认】,然后点击【使用仅限本机进行调试】

      在这里插入图片描述

    • 如下图所示成功得到崩溃位置

      在这里插入图片描述

    6、打包qBreakpad模块

    • 新建一个qBreakpad文件夹,将qBreakpad.pri文件和handler文件夹移动到qBreakpad文件夹中,handler文件夹中包含qBreakpad.lib

      在这里插入图片描述

    在这里插入图片描述

    7、测试打包的qBreakpad模块

    • 新建工程TestCrashes,编译器选择和编译qBreakpad一样,使用Release

      在这里插入图片描述

    • 将打包的qBreakpad模块文件夹复制到新建的工程路径下

      在这里插入图片描述

    • 在工程的TestCrashes.pro文件中添加下列两行代码,加载qBreakpad模块

      include(./qBreakpad/qBreakpad.pri)
      INCLUDEPATH += ./qBreakpad
      
      • 1
      • 2

      在这里插入图片描述

    • 由于qBreakpad有使用到网络模块,所以在qBreakpad.pri文件中添加QT += network

      在这里插入图片描述

    • 在main.cpp文件中添加头文件#include "QBreakpadHandler.h"QBreakpadInstance.setDumpPath("crashes");

      在这里插入图片描述

    • 在widget.cpp文件中设置一个除0异常 ,点击按键后程序就会异常崩溃

      在这里插入图片描述

    • 进入编译后的文件夹下,可以看见成功生成pdb符号文件和dmp文件。

      在这里插入图片描述

    • 通过VS成功定位崩溃位置。

      在这里插入图片描述

  • 相关阅读:
    Mac和VScode配置fortran
    selenium下载安装对应的chromedriver并执行
    crash handler
    maven 项目报错--Using ‘UTF-8‘ encoding to copy filtered resources
    2022高教社杯全国大学生数学建模竞赛B题解析(更新完结)
    Zone 和 Zoneset 是什么关系
    dfs式学习笔记(n维正态分布/随机过程)
    第二十四章 数据检测类型
    Docker 的 Busybox 操作系统镜像
    【多目标进化优化】 Pareto 最优解集的构造方法
  • 原文地址:https://blog.csdn.net/qq_43627907/article/details/126603907