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

Qt使用qBreakpad定位崩溃位置

Qt使用qBreakpad定位崩溃位置

文章目录

  • Qt使用qBreakpad定位崩溃位置
    • 前言
      • 1、Google - Breakpad
      • 2、qBreakpad
      • 3、crashpad
      • 4、注意
    • Linux下
      • 1、环境
      • 2、qBreakpad源码准备
      • 3、qBreakpad编译
      • 4、测试qBreakpad
      • 5、dump文件调试
        • 5.1 编译breakpad
        • 5.2 开始分析dmp文件
    • Windows下
      • 1、环境
      • 2、源码准备
      • 3、qBreakpad编译
      • 4、测试qBreakpad
      • 5、dump文件调试
      • 6、打包qBreakpad模块
      • 7、测试打包的qBreakpad模块

更多精彩内容
👉个人内容分类汇总 👈

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
  • Qt版本:Qt5.14.2

2、qBreakpad源码准备

  • 下载qBreakpad

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

    cd qBreakpad/third_party
    

    在这里插入图片描述

    • 打开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
    

3、qBreakpad编译

  • 进入qBreakpad/handler文件夹

    cd qBreakpad/handler
    
  • 使用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

    在这里插入图片描述

  • 因为debug默认生成,release默认是不生成的dmp文件的

  • 在qBreakpad.pri文件中添加下列两行代码禁止release优化,然后使用release编译的程序崩溃后就会生成dmp 文件了(注意:添加下列代码后需要重新qmake)

    QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
    QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO
    

    在这里插入图片描述

  • 进入可执行程序路径下,会发现生成了一个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构建编译
  • 使用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");
    

    在这里插入图片描述

  • 删除后如下所示,然后保存修改,重新使用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)
    
    

    在这里插入图片描述

  • 根据错误提示打开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
    

    在这里插入图片描述

  • 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
    
  • 打开error.log文件,根据可执行程序名称test 找到奔溃位置位于TestThread类crash()函数中,具体在TestThread.cpp文件的第34行。

    在这里插入图片描述

    在这里插入图片描述

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符号文件;

    # release模式生成.pdb符号文件
    QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
    QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO
    

    在这里插入图片描述

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
    

    在这里插入图片描述

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

    在这里插入图片描述

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

    在这里插入图片描述

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

    在这里插入图片描述

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

    在这里插入图片描述

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

    在这里插入图片描述

相关文章:

  • IAR+vscode开发环境搭建,千万别用,当心爱上
  • 一些 Next Generation ABAP Platform 的新语法用例
  • java面向对象思维程序设计开发以及案例 -电梯运行问题对象分析与程序设计(1)
  • vulnhub EMPIRE: BREAKOUT靶机
  • 【Python】PyQt5 Designer工具配置
  • Camera-MTK OpenCamera时序以及耗时
  • SpringCloud链路追踪SkyWalking-第二章-部署搭建及高可用
  • springboot vue3 elementui plus点餐外卖系统源码
  • Node.js阶段学习(一)
  • 一、nacos安装与高可用部署
  • mysql实现删除某一列的重复数据(只留一行或全部删除)
  • 数学建模十大算法01-蒙特卡洛算法(Monte Carlo)
  • 智能家居相关企业达2万余家,湖南智能家居发展将进入快车道
  • java计算机毕业设计高校学生社团管理源码+数据库+系统+lw文档+mybatis+运行部署
  • Flutter: FutureBuilder 组件的使用
  • 收藏网友的 源程序下载网
  • 《深入 React 技术栈》
  • angular2开源库收集
  • ES6之路之模块详解
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • js写一个简单的选项卡
  • node入门
  • passportjs 源码分析
  • Sequelize 中文文档 v4 - Getting started - 入门
  • TypeScript迭代器
  • web标准化(下)
  • 分享一份非常强势的Android面试题
  • 基于axios的vue插件,让http请求更简单
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 使用 QuickBI 搭建酷炫可视化分析
  • 使用putty远程连接linux
  • 数组大概知多少
  • 异步
  • SAP CRM里Lead通过工作流自动创建Opportunity的原理讲解 ...
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • ​批处理文件中的errorlevel用法
  • #14vue3生成表单并跳转到外部地址的方式
  • #if和#ifdef区别
  • #每天一道面试题# 什么是MySQL的回表查询
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • (12)Linux 常见的三种进程状态
  • (C)一些题4
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (附源码)ssm高校运动会管理系统 毕业设计 020419
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (利用IDEA+Maven)定制属于自己的jar包
  • (三)uboot源码分析
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (十三)Maven插件解析运行机制
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • *上位机的定义
  • .java 9 找不到符号_java找不到符号
  • .mysql secret在哪_MYSQL基本操作(上)