项目介绍
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等项目使用。
- 主页:https://chromium.googlesource...
- 文档:https://chromium.googlesource...
- GitHub 地址:https://github.com/google/bre...
主要组件
breakpad有三个主要的组件:
breakpad client:breakpad的客户端静态库(即:libbreakpad_client.a)。它的主要作用是在程序崩溃后,接管程序的异常处理,具体来说,它主要做了两方面的事情。
- 响应程序崩溃时接收到的signal,包括:SIGSEGV,SIGABRT,SIGFPE,SIGILL,SIGBUS。 (另外两个SIGSTOP,SIGKILL无法处理)
- 获取程序崩溃那一刻的运行时信息,保存为一个minidump格式的文件。
- symbol dumper:调试信息文件生成程序(即:dump_syms)。主要是用来从可执行程序中提取与符号相关的信息,并保存为一种特定格式的文件。
- processor module:minidump 处理程序(即:minidump_stackwalk),它的作用就是根据coredump及symbol file,构建出可读的call stack。
下载编译
- 下载Breakpad源码:git clone https://github.com/google/bre...。
- 下载Breakpad依赖的三方库 LSS:git clone https://github.com/adelshokhy...),将 LSS 中的linux_syscall_support.h文件放至breakpad/src/third_party/lss/ 目录下。
- 编译Breakpad:在源目录下执行./configure && make。
libbreakpad_client.a在src/client/linux/ 目录下。
dump_syms在src/tools/linux/dump_syms/目录下。
minidump_stackwalk在src/processor/目录下。
还有一个将minidump转换为core文件的程序minidump-2-core在src/tools/linux/md2core/目录下。
集成breakpad
首先,在程序中引用异常处理程序的头文件。
#include "client/linux/handler/exception_handler.h"
为了生成minidump文件,我们需要实例化一个ExceptionHandler对象,并提供一个存储minidump的路径,以及一个回调函数来接收关于已写入的minidump的信息。
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; }
- 在编译时需要链接breakpad提供的静态库libbreakpad_client.a,头文件搜索路径需要包含breakpad的src目录。编译运行这个程序,会在/tmp/目录下生成一个minidump文件,并在退出之前打印该文件的路径。
编译命令如下:
$ g++ -g -I ./ -o breakpad_test test.cpp ./client/linux/libbreakpad_client.a -lpthread -std=c++11
- PS:回调函数中应该尽可能少的做一些工作。因为当该函数回调时,程序处于不安全状态。从其他函数库分配内存或调用函数可能并不安全。如果你必须要在回调函数中实现一些功能,最安全的操作是
fork
和exec
一个新的进程来执行你需要做的任何功能。Breakpad源码中包含libc函数的一些简单重新实现,同样,在src/third_party/lss中包含一些用于进行Linux系统调用的函数,应该避免直接调用libc和一些其他的动态库。
发送minidump文件
- 在实际的应用程序中,可以将minidump文件发送到服务器以便进行后续的分析和统计工作。
- Breakpad源码中相关文件在src/common/linux/http_upload.h(HTTP上传)和src/tools/linux/symupload/minidump_upload.cc (minidump上传)。
生成符号文件
- 为了产生有用的堆栈信息,Breakpad要求将二进制文件中的调试符号转换为文本格式的符号文件。
- 首先,需要确保已使用-g编译程序以包含调试符号。
然后,使用dump_syms工具生成文本格式的符号文件。比如程序名为test,则命令如下:
$ ./dump_syms ./test > test.sym
为了将这些符号与minidump_stackwalk工具一起使用,还需要将它们放在特定的目录结构中。 符号文件的第一行包含生成此目录结构所需的信息,比如上述的test.sym可使用如下命令:
$ head -n1 test.sym MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 test $ mkdir -p ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830 $ mv test.sym ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830
根据minnidump和symbol生成stack trace
minidump_stackwalk工具可以提取一个minidump文件及其相应的文本格式符号,并生成可读的堆栈信息。在上述示例中可以使用如下命令生成最后的可读堆栈信息文件:
$ ./minidump_stackwalk xxxx.dmp ./symbols > dmp_info.txt
使用总结
- 使用-g选项编译程序。
- 使用dump_syms工具提取上一步生成的可执行文件中的符号,然后将符号文件放到指定目录下。
- 去掉-g选项重新编译程序。
- 待程序产生崩溃时生成dmp文件。
- 使用minidump_stackwalk工具将dmp文件转换成可读的堆栈信息文件。
以上,使用自动化脚本更简单。