google_breakpad库的基本使用

参考链接:

  1. windows下捕获dump之Google breakpad_client的理解
  2. Google Breakpad:基本介绍和操作方法
  3. Breakpad 入门
  4. linux下用QT捕获程序异常

简介

github 地址

三大组件

  1. client:读取当前线程的状态、加载的可执行文件、共享库等信息,写入到 minidump 中。可以放到应用中,应用崩溃时自动使用或显式调用;
  2. symbol dumper:读取编译器生成的调试信息,产生基于 breakpad 格式的 symbol file;
  3. processor:读取 minidump 寻找适合的 symbol file,生成可读的 C/C++ 调用栈。

运行流程图

为什么是 minidump?

Breakpad 在所有平台都使用 Windows 的 minidump 文件,而不是传统的 core 文件,原因是:

  1. .core 文件可能非常大,无法通过网络发送到收集器进行处理。Minidump 更小;
  2. .core 文件格式的文档记录很差。比如 Linux Standards Base 没有描述在 PT_NOTE 段中寄存器是如何存储的;
  3. Windows 机器生成 .core dump 文件比让其他机器生成 minidump 文件更难;
  4. 只有一个文件格式,简化了 breakpad 处理器。

minidump 的文件格式

包含:

  1. 该进程已加载的可执行文件和共享库列表,包括名称和版本;
  2. 进程中所有现场的列表,包括每个线程的寄存器状态、栈内容(纯字节流);
  3. 其他的系统信息,包括处理器、操作系统、崩溃原因等等。

minidump 的生成

默认情况下,breakpad 初始化时注册一个异常或信号处理函数,该函数能在异常发生时生成 minidump。注册方法有平台决定:

  1. Windows 中使用 SetUnhandledExceptionFilter()
  2. OS X 中创建一个线程来等待 Mach 例外端口;
  3. Linux 安装一个能处理像 SIGSEGV、SIGKILL 之类的信号处理函数;

一旦生成了 minudump,每个平台都有略微不同的方式来上传崩溃转储。在 Windows 和 Linux 上,提供了一个单独函数库,可以调用它来执行上传。在 OS X上,会生成一个单独的进程,提示用户授予权限(如果配置为这样做)并发送文件。

进程内、外异常处理

通常认为,在崩溃的进程内写入 minidump 是不安全的,因为关键的进程数据结构可能已经被破坏,或者异常处理器所运行的栈可能已经被覆写等。所以 3 个平台都支持所谓的“进程外”异常处理。

编译

根据提示文档进行常规的 ./configure; make; make install 即可。

整合到程序中

可以根据平台,直接参考 docs 目录下的 xxx_starter_guide.md 文档。

步骤:

  1. 注意:项目编译时需要连接好 libbreakpad_client.a 这个库文件;比如 Qt 项目中的 .pro 文件:LIBS += -lbreakpad_client;同时,避免部分文件找不到对应的头文件,在 .pro 中加入 INCLUDEPATH += /usr/local/include/breakpad
  2. main.cpp 中添加测试代码,如下:
#include <QCoreApplication>
#include "breakpad/client/linux/handler/exception_handler.h"

static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
{
    printf("Dump path: %s\n", descriptor.path());
    return succeeded;
}

void crash() { volatile int* a = (int*)(NULL); *a = 1; }

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    google_breakpad::MinidumpDescriptor descriptor("/tmp");
    google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL, true, -1);
    crash();

    return a.exec();
}
  1. 编译并运行程序后,可知,程序会在调用 crash() 函数后崩溃。

堆栈信息分析

程序运行后,会出现如下:

Dump path: /tmp/7ca76e22-4044-46fc-e06318b6-28aea319.dmp
按 <RETURN> 来关闭窗口...

程序崩溃时,生成了 .dmp 文件。

分析 .dmp 文件

x86 平台编译完 breakpad 库后,可以得到一系列工具和库。
以下步骤均在 x86 平台执行:

  1. 确保程序使用了 -g 编译,使用 dump_syms 对程序生成一份符号文件 .sym;如 dump\_syms /home/twdz/PersonalTest/build-breakpadDemo-Desktop\_Qt\_5\_12\_8\_GCC\_64bit-Debug/breakpadDemo > ./breakpad.sym
  2. 然后依次执行以下命令:
$head -n1 breakpadDemo.sym
MODULE Linux x86_64 7DDABFE2CC59CFD3ADF67085B2D231E60 breakpadDemo
$mkdir -p ./symbols/test/7DDABFE2CC59CFD3ADF67085B2D231E60
$mv breakpadDemo.sym ./symbols/test/7DDABFE2CC59CFD3ADF67085B2D231E60/
$minidump_stackwalk 7ca76e22-4044-46fc-e06318b6-28aea319.dmp ./symbols/ > stackTrace.log
  1. 将堆栈调用信息生成到 stackTrace.log 文件中,根据文件进行分析崩溃的位置,如:在这里插入图片描述
    3.1 从位置 1 可以看到崩溃的原因以及地址;发现地址为 0x0,依次往下寻找,最新的堆栈调用信息是在位置 2,而位置 3 说明了其具体的地址;
  2. 使用命令 addr2line 地址 -e 可执行程序名字 -f 可以定位具体的崩溃位置,如:addr2line 0x402451 -e ./breakpadDemo -f(这里采用 0x402451 这个地址是因为使用 0x0 和 0x2451 都无法获取到有效信息)。运行后,打印如下:
_Z5crashv
/home/twdz/PersonalTest/build-breakpadDemo-Desktop_Qt_5_12_8_GCC_64bit-Debug/../breakpadDemo/main.cpp:10

可知,main.cpp 文件第 10 行发生了崩溃。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值