最近海思平台在项目测试过程中,经常出现coredump的问题,尤其是那些的不经常挂的情况,光看日志定位问题真的很难,同时生成的core文件由于各种动态链接和静态链接,分析起来实在是比较困难。为解决coredump问题,有必要提供一个跨平台的crash处理系统,目前已知的支持平台有windows 、Linux、 OS X 、android等,Google自己用的系统Breakpad被广泛的应用于该类的死机场景中。
本章主要学习breakpad的基本概念和移植方法,将用于移植到海思平台上。
1. 简介
Breakpad是一个库和工具套件可以让你发布的应用程序(把编译器提供的调试信息剥离掉的)给用户,记录了崩溃紧凑的“dump”文件,发送回您的服务器,并从这些minidump产生C和C++堆栈踪迹。Breakpad可以根据请求使没有崩溃的程序也可以写出minidump。目前使用Breakpad的有谷歌浏览器,火狐,谷歌的Picasa,卡米诺,谷歌地球,和其他项目。
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