1、什么是breakpad?
写代码的人最难堪而又无法回避的事情之一,莫过于你写的程序某刻当着 QA 的面突然挂掉 --- 大大没面子!但更没面子的是,之后你一直没法解决问题。。。程序崩溃而又无法解决可能有很多的原因,其中一个就是无法找到出问题的地方,尤其是那些 release 版本的程序。异常崩溃后的善后处理是一件很重要而又不大好做的事情,一方面事关用户体验,另一方面能否尽可能收集崩溃现场的信息关系着接下来能否快速和及时有效地解决问题。
google breakpad 可以说算是专门为解决这类事情而开发出来的工具。简单来说,它的主要作用是在程序崩溃后,输出一个特殊的 coredump,并且然后根据 coredump 还原崩溃时函数的调用栈,为了做到这些它提供了一些手段,使得你的程序能够捕获异常,从而能让它在弥留之际可以煽情地留下些什么,而不是突然就凭空消失了。
具体的介绍读者可以参考一下官方的说明:https://code.google.com/p/google-breakpad/wiki/GettingStartedWithBreakpad. 本文只简单记一下怎样在我们的代码中使用该工具,后续会探讨一下实现的细节。
breakpad官方新地址:https://chromium.googlesource.com/breakpad/breakpad/
2、breakpad能够解决什么问题?
它的主要作用是在程序崩溃后,输出一个特殊的 coredump,并且然后根据 coredump 还原崩溃时函数的调用栈,为了做到这些它提供了一些手段,使得你的程序能够捕获异常,从而能让它在弥留之际可以煽情地留下些什么,而不是突然就凭空消失了。
3、怎样安装breakpad?
官方给出的下载:
git clone https://chromium.googlesource.com/breakpad/breakpad
如果下载不下来,这样下载应该也是可以的:在下面这个界面里下载
https://chromium.googlesource.com/breakpad/breakpad/+/778bd12f226d1c2d3f4aeca2fb86a53028ce8d39
Linux googlebreakpad 编译
1. 下载源码
源码包括两部分,分为依赖库和 breakpad,网址一般会被屏蔽,需要墙一下。另,编译器需要支持 c++11. 我用的gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC) 是可以的。
(1)依赖包
http://linux-syscall-support.googlecode.com/svn/trunk/lss/
src/third_party/lss
(2)breakpad 包
git clone https://chromium.googlesource.com/breakpad/breakpad
的 master 分支
2. 注意事项,直接下载 breakpad 代码编译,会编译失败。报错缺少 linux_syscall_support.h
需要用third_party/lss里的头文件。
(1) 进入 breakpad 的 src 目录的 third-party 文件夹,创建 lss 文件夹,拷贝下载的依赖包里的文件。
执行验证文件的正确性:
gcc -Wall -Wextra -Wstrict-prototypes -c linux_syscall_support.h
3. 然后
./configure
make
4. 生成
./src/client/linux/libbreakpad_client.a
./src/client/mac/gcov/libgcov.a
./src/third_party/libdisasm/libdisasm.a
./src/libbreakpad.a
5. 编写、编译 demo
报错不支持 nullptr,因为需要支持 C++11才可以。
g++ -g -I ../breakpad/src/ -o breakpad_sample breakpad_sample.cpp ../breakpad/src/client/linux/libbreakpad_client.a -lpthread -std=c++11
6. 运行生成 dmp 文件
[root@018 test-breakpad]# ./breakpad_sample
Dump path: /tmp/c220e8a9-11ce-4fb3-aea619b4-c0f68967.dmp
Segmentation fault
7. 解析 dmp 文件
我创建了一个 core 文件夹,把 core文件、可执行breakpad_sample、c220e8a9-11ce-4fb3-aea619b4-c0f68967.dmp 、minidump-2-core、dump_syms拷贝过来。
有两种方法,一个是用minidump-2-core、 一个是用dump_syms。
我用的是minidump-2-core,执行指令:
./minidump-2-core e6f2524d-0bb5-46bc-b077df92-d49613b6.dmp > e6.core
gdb ./breakpad_sample e6.core
得到如下信息:
warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available.
Failed to read a valid object file image from memory.
Core was generated by `./breakpad_sample'.
Program terminated with signal 11, Segmentation fault.
#0 0x0000000000401ea6 in crashHare () at breakpad_sample.cpp:19
19 *a = 1; // 放心的奔溃吧
Missing separate debuginfos, use: debuginfo-install glibc-2.17-157.el7_3.5.x86_64 libgcc-4.8.5-16.el7_4.2.x86_64 libstdc++-4.8.5-16.el7_4.2.x86_64
(gdb) list
14 }
15
16 static void crashHare()
17 {
18 int *a = (int *)(NULL);
19 *a = 1; // 放心的奔溃吧
20 }
21
22 int main(int argc, char *argv[])
23 {
(gdb) print a
$1 = (int *) 0x0
8. 执行 strip -s breakpad_sample 是不影响解析的。
9. breakpad_sample 源码如下:
#include <iostream>
#include "../breakpad/src/client/linux/handler/exception_handler.h"
//#include "../breakpad/src/third_party/lss/linux_syscall_support.h"
//#include "../breakpad/src/client/linux/handler/minidump_descriptor.h"
#include <sys/types.h>
#include <unistd.h>
static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
void *context,
bool succeeded)
{
printf("Dump path: %s\n", descriptor.path());
return succeeded;
}
static void crashHare()
{
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);
crashHare();
return 0;
}
4、怎样使用breakpad?
使用说明主要在:https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/
5、怎样把 breakpad 加入程序中:
1) 编译breakpad.
按照说明进行编译后,会得到一个libbreakpad_client.a 及一系列的工具。其中最主要的两个在:
a. /src/tools/linux/dump_syms/dump_syms
b. /src/processor/minidump_stackwalk
有一点需要提一下,这个库在低版本的gcc中编译不了,比较不方便,google code上有人提了这个问题,也有人做了些patch,但由于库在实现上依赖了一些高版本编译器的特性,作者并不打算去解决这个问题了。
2) 把 libbreakpad_client.a 链接到你的程序中.
3) 至于怎么在你的程序加以使用,其实非常简单,示例如下:
#include "client/linux/handler/exception_handler.h"
#include "third_party/lss/linux_syscall_support.h"
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descr,
void*context,bool succeeded)
{
printf("crash occurs!\n");
pid_t ret = sys_fork();
if(ret < 0)
{
fprintf(stderr,"mini dump fork error/n");
return false;
}
else if(ret == 0)
{
printf("child process\n");
char* const arg[] = {"ch",(char *)descr.path(),NULL}; char* const env[] = {NULL,NULL};
sys_execve("./ch",arg,env);
// execl("./dh","dh",descr.path(),0);
printf("error , we should never be here\n");
}
else
{
}
return true;
}
int main()
{
printf("crash source.\n");
using namespace google_breakpad;
MinidumpDescriptor desc("./dump");
ExceptionHandler eh(desc,NULL,dumpCallback,NULL,true,-1);
printf("ready to crash\n");
int num = 0;
int div = 3;
int i = div/num;
return 0;
}