google-breakpad - 使用篇
前言
前段时间无聊时看chromium无意间发现了这个breakpad
库,发现正好可以应用到我们团队中(windows已经有了),本篇章节将会介绍brekapad
的源码编译和linux
上breakpad的
使用。在下一篇文档中将会通过breakpad
的源码去揭开它神秘的面纱。
简介
breakpad
是google
开发的一个跨平台C/C++ dump
捕获开源库,崩溃文件使用微软的minidump
格式存储,也支持发送这个dump文件到你的服务器,breakpad
可以在程序崩溃时触发dump
写入操作,也可以在没有触发dump
时主动写dump
文件。breakpad
支持windows
、linux
、macos
、android
、ios
等。目前已有Google Chrome
, Firefox
, Google Picasa
, Camino
, Google Earth
等项目使用。
整体概述
图片左上角是一个完整的应用程序,它包含了三部分即程序代码、Breakkpad Client
(即brekapad
提供出来的静态库),调式信息
在Build System
中breakpad
的symbol
生成工具借助应用层序中的Debugging Information
这一部分生成一个Google
自己的符号文件,这个符号文件类似于windows
上的pdb
文件,最终呢在发布应用层序的时候使用strip
将调式信息去除
在User's System
中运行的应用程序是通过strip
去除了调式信息的,倘若应用程序发生Crash
,Breakpad client
就会写minidump
文件到指定目录,并且可以将产生的minidump
文件发送到远端服务器即Crash Colletcor
。
在Crash Collector
就可以利用Build System
中产生的symol
文件和User's System
中上报的minidump
文件生成用户可读的stack trace
breakpad
有三个主要的组件:
breakpad-client
:client
是一个静态库,主要提供给应用程序使用,它可以帮助应用层序捕获应用层序并且生成minidump
文件以及上传minidump
文件symbol dumper
: symbol dumper的表现形式是一个可执行文件,它可以通过调式信息生成一个symbol file
, 这个symbol file
的格式是google自己的格式,具体请查看
Minidump
Minidump
是微软开发的一种用于崩溃时记录的小存储器转储文件,它类似与linux
下的core file
,minidump
中包含以下信息:
进程装载的驱动程序和共享库列表,这个列表中包含了指定的名称和版本号
进程中存在的线程列表。对于每个线程,小型转储包括处理器寄存器的状态和线程堆栈内存的内容。这些数据是未解释的字节流,因为 Breakpad 客户端通常没有可用于生成函数名称或行号,甚至标识堆栈帧边界的调试信息。
已停止的处理器的上下文 (
PRCB
)已停止的进程的信息和内核上下文 (
EPROCESS
)有关收集转储的系统的其他信息:处理器和操作系统版本、转储的原因等。
Breakpad
在所有平台上使用 Windows
小型转储文件,而不是传统核心文件,原因如下:
核心文件可能非常大,因此无法通过网络将其发送到收集器进行处理。小型转储更小,因为它们被设计为这样使用。
核心文件格式记录得很差。例如,
Linux
标准基础不描述寄存器如何存储在段中。说服
Windows
计算机生成核心转储文件比说服其他计算机编写小型转储文件更难。它简化了
Breakpad
处理器,仅支持一种文件格式。
源码下载以及编译
mkdir breakpad && cd breakpad fetch breakpad cd src ./configure && make make check make install 复制代码
使用教程
breakpad分为 in-process
和 out-process
In-Process
#include "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[]) { google_breakpad::MinidumpDescriptor descriptor("/tmp"); google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL, true, -1); crash(); return 0; } 复制代码
MinnidumpDescriptor
设置了dump
生成目录为/tmp
,然后初始化了ExceptionHandler
,之后crash
函数模拟了程序的崩溃,在程序崩溃之后会在tmp
目录下生成一个dump
文件,路径是descriptor.path()
编译
g++ -g -o test.cc test -I/usr/local/include/breakpad -lbreakpad_client -lpthread 复制代码
给你的应用程序生成symbol文件
通过上面的步骤你还是只有dump
文件,你需要通过google
提供的dump_syms
二进制程序给你的应用程序生成symbol
文件(如果你运行了make install
,在/usr/local/bin
目录下就会有这个二进制文件), 之后通过symbol
文件和dump
文件就可以产生可读堆栈信息
通过dump_syms
给test
生成symbol
文件
dump_syms ./test > test.sym 复制代码
symbol
文件需要根据 test.sym
的第一行类容来防止目录结构位置,才能够被正确读取
head -n1 test.sym // 输出 MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 test 复制代码
根据上面的信息,你的test.sym
信息需要放置到./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830/test.sym
, 当然这样你也还是只加载来你应用层序的symbol
,上面同样的操作你还需要对你依赖的动态库进行符号文件的生成。
根据minnidump和symbol生成stack trace
minidump_stackwalk
是一个二进制可执行程序,你执行过make install
在/usr/local/bin
里面可以找到这个可执行程序,这个可执行程序可以生成可读堆栈信息
minidump_stackwalk minidump.dump ./symbols 复制代码
Out-Process
out-process
表示dump
文件的生成和写入在崩溃进程外进行,linux
中进程间采用socketpair
通信
int server_fd; int client_fd; void OnClientDumpRequestCallabck(void* context, const ClientInfo* client_info, const string* file_path) { } int main(void) { CrashGenerationServer::CreateReportChannel(&server_fd, &client_fd); CrashGenerationServer crash_server( server_fd, &OnClientDumpReuqestCallabck, NULL, NULL, NULL, true, "/tmp"); crash_server.Start(); // 拉起检查崩溃进程,并且传入client_fd, 在崩溃检查进程中初始化ExceptionHandler类,最后一个参数传入client_fd }
作者:spider集控团队
链接:https://juejin.cn/post/6899070041074073614