Linux程序中集成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等项目使用。

  • 主页:https://chromium.googlesource.com/breakpad/breakpad/
  • 文档:https://chromium.googlesource.com/breakpad/breakpad/+/HEAD/docs
  • GitHub 地址:https://github.com/google/breakpad

主要组件

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/breakpad 。
  • 下载Breakpad依赖的三方库 LSS:git clone https://github.com/adelshokhy112/linux-syscall-support ,将 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:回调函数中应该尽可能少的做一些工作。因为当该函数回调时,程序处于不安全状态。从其他函数库分配内存或调用函数可能并不安全。如果你必须要在回调函数中实现一些功能,最安全的操作是forkexec一个新的进程来执行你需要做的任何功能。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文件转换成可读的堆栈信息文件。

以上,使用自动化脚本更简单。

你可能感兴趣的:(Linux程序中集成breakpad)