Breakpad(跨平台crash工具)

  • Post author:
  • Post category:其他


最近海思平台在项目测试过程中,经常出现coredump的问题,尤其是那些的不经常挂的情况,光看日志定位问题真的很难,同时生成的core文件由于各种动态链接和静态链接,分析起来实在是比较困难。为解决coredump问题,有必要提供一个跨平台的crash处理系统,目前已知的支持平台有windows 、Linux、 OS X 、android等,Google自己用的系统Breakpad被广泛的应用于该类的死机场景中。

本章主要学习breakpad的基本概念和移植方法,将用于移植到海思平台上。



1. 简介

Breakpad是一个库和工具套件可以让你发布的应用程序(把编译器提供的调试信息剥离掉的)给用户,记录了崩溃紧凑的“dump”文件,发送回您的服务器,并从这些minidump产生C和C++堆栈踪迹。Breakpad可以根据请求使没有崩溃的程序也可以写出minidump。目前使用Breakpad的有谷歌浏览器,火狐,谷歌的Picasa,卡米诺,谷歌地球,和其他项目。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mFR9j1Fr-1597070837041)(D:\学习总结\内存管理单元\image-20200810224436252.png)]

Breakpad有三个主要组件:


  • 客户端

    是一个库,包含在您的应用程序中。 它可以获取当前线程的状态和当前加载的可执行文件和共享库的ID写转储文件。您可以配置客户端发生了崩溃时写入一个minidump时,或明确要求时。

  • 符号卸载器

    是一个程序,读取由编译器产生的调试信息,并生成一个使用

    Breakpad格式



    符号文件

  • 该**处理器(minidump processor)**是一个程序,读取一个minidump文件,找到相应的版本的符号文件的(可执行文件和共享库的转储提到的),并产生了一个人可读的C / C + +堆栈跟踪。



小型转储文件格式(即minidump)

转储文件的格式是由微软开发的类似存储的文件,崩溃便利上传。一个minidump文件包含:

  • 在创建dump的进程中加载的可执行文件和共享库列表。此列表中包含的特定版本加载的那些文件的文件名和标识符。

  • 在这个过程中存在的线程列表。对于每个线程转储包括处理器寄存器的状态,线程的堆栈存储器的内容。一般Breakpad客户端没有可用于产生函数名或行号,甚至确定堆栈帧的边界的调试信息,所以这些数据是不可解释的字节流。

  • 其他收集的有关系统转储信息比如:处理器和操作系统版本,转储的原因,等等。

Breakpad在所有平台上使用Windows dump文件,而不是传统的core文件,有以下几个原因:

  • core文件可能会非常大,不适合在网络上发送给收集器处理。minidump较小,因此它们被设计为使用这种方式。
  • core文件格式缺乏文档信息。例如,Linux标准库不描述寄存器如何存储在

    PT_NOTE

    段的。
  • 一个Windows机器上生成一个core dump文件,比起其他机器上生成一个minidump文件,哪个难很难说。
  • 简化了Breakpad处理器,只支持一种文件格式。



2. 编译Breakpad

下载源码,具体的编译过程请参考


breakpad

git clone https://chromium.googlesource.com/breakpad/breakpad

编译方法

./configure && make

编译出错

mv -f $depbase.Tpo $depbase.Po
src/client/linux/crash_generation/crash_generation_client.cc:40:10: fatal error: third_party/lss/linux_syscall_support.h: No such file or directory
 #include "third_party/lss/linux_syscall_support.h"
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
Makefile:5177: recipe for target 'src/client/linux/crash_generation/crash_generation_client.o' failed
make: *** [src/client/linux/crash_generation/crash_generation_client.o] Error 1

包含了前两者都缺少的一个头文件*

linux_syscall_support.h*

,该头文件要放在\src\third_party\lss目录下,然后重新编译

编译完以后会在生成两个可执行文件,分别是src/processor/minidump_stackwalk和src/tools/linux/dump_syms/dump_syms

生成

src/client/linux/libbreakpad_client.a



3. 实际例子

编写程序如下breakpad_sample.c

#include "client/linux/handler/exception_handler.h"
#include <stdio.h>
#include <string.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("/home/book/log");
    google_breakpad::ExceptionHandler eh(descriptor,
                         NULL,
                         dumpCallback,
                         NULL,
                         true,
                         -1);
    crashHare();
    return 0;
}


编译

g++ -g -I ../breakpad/src -o test breakpad_sample.c ../breakpad/src/client/linux/libbreakpad_client.a -lpthread


运行得到下面的信息

root@100ask:/home/book/hello# ./test
Dump path: /home/book/log/b063498c-ca03-411a-fd49dca8-85d56aaf.dmp
Segmentation fault (core dumped)
root@100ask:/home/book/hello#


参看stack 信息

方式一

minidump-2-core ../log/b063498c-ca03-411a-fd49dca8-85d56aaf.dmp > core
 gdb ../log/b063498c-ca03-411a-fd49dca8-85d56aaf.dmp core
warning: File "/lib/x86_64-linux-gnu/libthread_db-1.0.so" auto-loa                                                                                                                        ding has been declined by your `auto-load safe-path' set to "$debu                                                                                                                        gdir:$datadir/auto-load".

warning: Unable to find libthread_db matching inferior's thread li                                                                                                                        brary, thread debugging will not be available.
Failed to read a valid object file image from memory.
Core was generated by `./test'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x000055dd66b1f375 in crashHare () at breakpad_sample.c:17
17          *a = 1; // 放心的奔溃吧
(gdb)

方式二

root@100ask:/home/book/hello# dump_syms ./test | head -1         
MODULE Linux x86_64 6BD7C0D9ECCE1FC511E4FBA9D9A13B650 test
mkdir -p ./symbols/test/6BD7C0D9ECCE1FC511E4FBA9D9A13B650
dump_syms ./test > ./symbols/test/6BD7C0D9ECCE1FC511E4FBA9D9A13B650/test.sym
 minidump_stackwalk ../log/b063498c-ca03-411a-fd49dca8-85d56aaf.dmp symbols/

死机信息为

CPU: amd64
     family 6 model 142 stepping 12
     1 CPU

GPU: UNKNOWN

Crash reason:  SIGSEGV /SEGV_MAPERR
Crash address: 0x0
Process uptime: not available

Thread 0 (crashed)
 0  test!crashHare [breakpad_sample.c : 17 + 0x4]
    rax = 0x0000000000000000   rdx = 0x000055dd66d366a0
    rcx = 0x0000000000000000   rbx = 0x0000000000000000
    rsi = 0x0000000000000000   rdi = 0x000055dd66d366a0
    rbp = 0x00007ffe0a737280   rsp = 0x00007ffe0a737280
     r8 = 0x0000000000000000    r9 = 0x0000000000000000
    r10 = 0x000055dd68c86010   r11 = 0x0000000000000000
    r12 = 0x000055dd66b1f220   r13 = 0x00007ffe0a737520
    r14 = 0x0000000000000000   r15 = 0x0000000000000000
    rip = 0x000055dd66b1f375
    Found by: given as instruction pointer in context
 1  test!main [breakpad_sample.c : 29 + 0x5]
    rbx = 0x0000000000000000   rbp = 0x00007ffe0a737440
    rsp = 0x00007ffe0a737290   r12 = 0x000055dd66b1f220
    r13 = 0x00007ffe0a737520   r14 = 0x0000000000000000
    r15 = 0x0000000000000000   rip = 0x000055dd66b1f446
    Found by: call frame info
 2  libc.so.6 + 0x21b97
    rbx = 0x0000000000000000   rbp = 0x000055dd66b304e0
    rsp = 0x00007ffe0a737450   r12 = 0x000055dd66b1f220
    r13 = 0x00007ffe0a737520   r14 = 0x0000000000000000
    r15 = 0x0000000000000000   rip = 0x00007fcab0eeab97
    Found by: call frame info
 3  test!crashHare [breakpad_sample.c : 18 + 0x3]
    rsp = 0x00007ffe0a737470   rip = 0x000055dd66b1f37e
    Found by: stack scanning

Loaded modules:
0x55dd66b1d000 - 0x55dd66b35fff  test  ???  (main)
0x7fcab0b2b000 - 0x7fcab0cc7fff  libm.so.6  ???
0x7fcab0ec9000 - 0x7fcab10affff  libc.so.6  ???  (WARNING: No symbols, libc.so.6, 4B76CFD3972F3EACFE366DDD07AD902F0)
0x7fcab12ba000 - 0x7fcab12d0fff  libgcc_s.so.1  ???
0x7fcab14d2000 - 0x7fcab164afff  libstdc++.so.6  ???
0x7fcab185b000 - 0x7fcab1874fff  libpthread.so.0  ???
0x7fcab1a7a000 - 0x7fcab1aa0fff  ld-linux-x86-64.so.2  ???
0x7ffe0a789000 - 0x7ffe0a789fff  linux-gate.so  ???
2020-08-10 10:36:22: minidump.cc:5061: INFO: Minidump closing minidump

在上面的libc.so.6只给出地址,没给出函数名称,而在Loaded modules中可以看到libc.so.6下的警告No symbols,所以下面给libc.so.6制作一个sym即可,步骤如下:


找到对应的libc.so.6的库文件

,取名一定要按照规则去做,比如生成sym文件,一定是二进制程序文件名称加.sym 或者so文件夹.sym,大小写也不能改。

dump_syms libc.so.6 > libc.so.6.sym
root@100ask:/home/book/hello# head -n1 libc.so.6.sym
MODULE Linux x86_64 4B76CFD3972F3EACFE366DDD07AD902F0 libc.so.6
mkdir -p ./symbols/libc.so.6/4B76CFD3972F3EACFE366DDD07AD902F0
mv libc.so.6.sym ./symbols/libc.so.6/4B76CFD3972F3EACFE366DDD07AD902F0/
minidump_stackwalk ../log/b063498c-ca03-411a-fd49dca8-85d56aaf.dmp symbols/
Loaded modules:
0x55dd66b1d000 - 0x55dd66b35fff  test  ???  (main)
0x7fcab0b2b000 - 0x7fcab0cc7fff  libm.so.6  ???
0x7fcab0ec9000 - 0x7fcab10affff  libc.so.6  ???
0x7fcab12ba000 - 0x7fcab12d0fff  libgcc_s.so.1  ???
0x7fcab14d2000 - 0x7fcab164afff  libstdc++.so.6  ???
0x7fcab185b000 - 0x7fcab1874fff  libpthread.so.0  ???
0x7fcab1a7a000 - 0x7fcab1aa0fff  ld-linux-x86-64.so.2  ???
0x7ffe0a789000 - 0x7ffe0a789fff  linux-gate.so  ???
2020-08-10 11:17:27: minidump.cc:5061: INFO: Minidump closing minidump



版权声明:本文为u012489236原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。