一、介绍
Breakpad是一个库和工具套件可以让你发布的应用程序(把编译器提供的调试信息剥离掉的)给用户,记录了崩溃紧凑的“dump”文件,发送回您的服务器,并从这些minidump产生C和C++堆栈踪迹。Breakpad可以根据请求使没有崩溃的程序也可以写出minidump。目前使用Breakpad的有谷歌浏览器,火狐,谷歌的Picasa,卡米诺,谷歌地球等目前已知的支持平台有windows 、Linux、 OS X 、Android。简单一点说就是,当你程序挂了,用它可以记录其堆栈信息,这样就很方便的找出奔溃在哪了
Breakpad有四个主要组件:
1).libbreakpad_client.a:客户端,也是要集成到你的程序里的。 它可以获取当前线程的状态和当前加载的可执行文件和共享库的ID写转储文件。需要在奔溃之前创建一个ExceptionHandler,这样你的程序奔溃的时候 才会产生一个有效的 dump文件(这里使用的是minidump,不同与core文件)
2).dump_syms:符号生成器,读取由编译器产生的调试信息,并生成一个使用Breakpad格式的符号文件 。
3).minidump_stackwalk:dump解析器(minidump processor),读取一个minidump文件,根据相应的版本的符号文件,生成堆栈信息。
4).symupload:可以上传奔溃信息。如果你写了一个服务器,可以接收记录它们,当然普通调试就用不到了。
对于不同平台,客户端生成minidump的调用方法会有点差别,默认初始化Breakpad时,安装了一个异常/信号handler,崩溃时可写一个minidump到磁盘。
1)在Windows上,这是通过SetUnhandledExceptionFilter()实现;
2)在 OS X上,这是通过创建一个线程,等待的Mach exception端口
3)在linux上,这是通过安装一个信号handler来应对程序的各种异常情况,如SIGILL,SIGSEGV等。
一旦生成minidump,每个平台上传奔溃信息的方式略有不同,在Windows和Linux上,提供一个单独的函数库(upload)。在OS X上,通过一个单独的进程处理,提示用户是否允许,如果同意这样做则上传文件。
二、下载地址
官方地址这里就不提供了,自己百度,当然那是在你能翻墙的前提下可以去官网下,当然如果不能,那么请在以下地址下载,地址1:已经实验过的可用的完整版本(2017年的),当然随着时间流逝可能就不是最新的了, 地址2可以下载到相对较信道版本,当时截止目前,该版本编译会提示缺少linux_syscall_support.h,你可以从其他地方下载该.h或从地址1下载了替换进去后再编译就OK了
地址1:完整的包 http://download.csdn.net/detail/fword/9878407
地址2:github:https://github.com/bittorrent/breakpad
三、嵌入式linux编译参考:
1).编译
# export CC=/opt/hisi-linux/x86-arm/arm-hisiv400-linux/target/bin/arm-hisiv400-linux-gcc
# export CXX=/opt/hisi-linux/x86-arm/arm-hisiv400-linux/target/bin/arm-hisiv400-linux-g++
# ./configure –host=arm-hisiv400-linux-gnueabi –prefix=/usr/hisiv400/rootfs
# chmod a+x ./configure
# make
# make install
2).完成后 会在 /usr/hisiv400/rootfs 目录的lib/ bin/ include/下生成相应库和工具及头文件
四、直接上实例
环境: linux上使用客户端
文件名:breakpad_sample.cpp
#include "client/linux/handler/exception_handler.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;
}
1.注意事项:
回调dumpCallback里做的工作越少越好,因为crash的程序本身就不安全,分配内存或调用另一个库里的函数都是不安全的,使用fork另起个进程来做事才是最安全的. 如果必须在crash时使用回调参考(附件 参考网址4和5),避免直接调用libc
2.编译命令:
root@woozon-PC:breakpad# g++ -g breakpad_sample.cpp -I/usr/hisiv400/rootfs/include/breakpad -L/usr/hisiv400/rootfs/lib -lbreakpad_client -lpthread -o breakpad_sample
注意,这里 -g不要忘了,否则堆栈信息里定位不到具体函数
3.见证奇迹:
下面的每一步如果是做开发的应该都可以看懂,就不详细解释了
拷贝/usr/hisiv400/rootfs/bin/里的所有文件 到你的板子里的/bin/里,这里我将板子nfs挂
/mnt/nfs # cp /mnt/nfs/hisiv400/rootfs/bin/* /bin/
/mnt/nfs # dump_syms ./breakpad_sample > breakpad_sample.sym
/mnt/nfs # head -n1 ./breakpad_sample.sym
MODULE Linux arm C4E8DB657F2EB4C1782CD6BBC6E3DD6D0 breakpad_sample
/mnt/nfs # mkdir -p /tmp/symbols/breakpad_sample/C4E8DB657F2EB4C1782CD6BBC6E3DD6D0
/mnt/nfs # mv ./breakpad_sample.sym /tmp/symbols/breakpad_sample/C4E8DB657F2EB4C1782CD6BBC6E3DD6D0/
/mnt/nfs # ./breakpad_sample
Dump path: /tmp/b2044a06-f906-4a3f-1070d68e-18eb55b3.dmp
Segmentation fault
/mnt/nfs # minidump_stackwalk /tmp/d23f8d5e-5832-45ac-da9a718d-7d847b15.dmp /tmp/symbols
2017-06-15 20:15:02: minidump.cc:4811: INFO: Minidump opened minidump /tmp/d23f8d5e-5832-45ac-da9a718d-7d847b15.dmp
2017-06-15 20:15:02: minidump.cc:4931: INFO: Minidump not byte-swapping minidump
2017-06-15 20:15:02: minidump.cc:5414: INFO: GetStream: type 15 not present
2017-06-15 20:15:02: minidump.cc:5414: INFO: GetStream: type 1197932545 not present
2017-06-15 20:15:02: minidump.cc:5414: INFO: GetStream: type 1197932546 not present
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /mnt/nfs/breakpad_sample
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libc-2.16.so
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libpthread-2.16.so
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libgcc_s.so.1
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libm-2.16.so
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libstdc++.so.6.0.19
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libdl-2.16.so
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/ld-2.16.so
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /mnt/nfs/breakpad_sample
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libc-2.16.so
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libpthread-2.16.so
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libgcc_s.so.1
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libm-2.16.so
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libstdc++.so.6.0.19
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/libdl-2.16.so
2017-06-15 20:15:02: minidump.cc:2182: INFO: MinidumpModule could not determine version for /lib/ld-2.16.so
2017-06-15 20:15:02: minidump.cc:5414: INFO: GetStream: type 14 not present
2017-06-15 20:15:02: minidump_processor.cc:152: INFO: Found 2 memory regions.
2017-06-15 20:15:02: minidump_processor.cc:162: INFO: Minidump /tmp/d23f8d5e-5832-45ac-da9a718d-7d847b15.dmp has CPU info, OS info, no Breakpad info, exception, module list, thread list, no dump thread, requesting thread, and no process create time
2017-06-15 20:15:02: minidump_processor.cc:201: INFO: Looking at thread /tmp/d23f8d5e-5832-45ac-da9a718d-7d847b15.dmp:0/1 id 0x5149
2017-06-15 20:15:02: source_line_resolver_base.cc:236: INFO: Loading symbols for module /mnt/nfs/breakpad_sample from memory buffer
2017-06-15 20:15:02: simple_symbol_supplier.cc:196: INFO: No symbol file at /tmp/symbols/libc-2.16.so/D4DD1DB3B93E4BDC3CF81E63D83B8B110/libc-2.16.so.sym
2017-06-15 20:15:02: stackwalker.cc:98: INFO: Couldn’t load symbols for: /lib/libc-2.16.so|D4DD1DB3B93E4BDC3CF81E63D83B8B110
2017-06-15 20:15:02: basic_code_modules.cc:110: INFO: No module at 0xb6dd3000
2017-06-15 20:15:02: basic_code_modules.cc:110: INFO: No module at 0xbebaccc4
2017-06-15 20:15:02: basic_code_modules.cc:110: INFO: No module at 0x1
2017-06-15 20:15:02: postfix_evaluator-inl.h:334: INFO: Identifier lr not in dictionary
2017-06-15 20:15:02: basic_code_modules.cc:110: INFO: No module at 0x0
2017-06-15 20:15:02: basic_code_modules.cc:110: INFO: No module at 0x0
2017-06-15 20:15:02: minidump_processor.cc:326: INFO: Processed /tmp/d23f8d5e-5832-45ac-da9a718d-7d847b15.dmp
Operating system: Linux
0.0.0 Linux 3.10.0_hi3536 #74 SMP Sat Jun 17 13:28:47 CST 2017 armv7l
CPU: arm
ARMv1 ARM part(0x4100c0e0) features: swp,half,thumb,fastmult,vfpv2,edsp,neon,vfpv3,tls,vfpv4,idiva,idivt
4 CPUsUNKNOWNash reason: SIGSEGV
Crash address: 0x0
Process uptime: not available
Thread 0 (crashed)
0 breakpad_sample!crash() [breakpad_client.cpp : 14 + 0x8]
r0 = 0xbebacb04 r1 = 0x00000000 r2 = 0x00000001 r3 = 0x00000000
r4 = 0x00000000 r5 = 0x00000000 r6 = 0x00009a40 r7 = 0x00000000
r8 = 0x00000000 r9 = 0x00000000 r10 = 0xb6f89000 r12 = 0x00000000
fp = 0xbebacab4 sp = 0xbebacaa8 lr = 0x00009c88 pc = 0x00009bd0
Found by: given as instruction pointer in context
1 breakpad_sample!main [breakpad_client.cpp : 30 + 0x2]
r4 = 0x00000000 r5 = 0x00000000 r6 = 0x00009a40 r7 = 0x00000000
r8 = 0x00000000 r9 = 0x00000000 r10 = 0xb6f89000 fp = 0xbebacb74
sp = 0xbebacab8 pc = 0x00009c88
Found by: call frame info
2 libc-2.16.so + 0x17e46
r4 = 0x00000000 r5 = 0x00000000 r6 = 0x00009a40 r7 = 0x00000000
r8 = 0x00000000 r9 = 0x00000000 r10 = 0xb6f89000 fp = 0x00000000
sp = 0xbebacb78 pc = 0xb6cbde48
Found by: call frame info
3 breakpad_sample!crash() [breakpad_client.cpp : 15 + 0xa]
sp = 0xbebacb88 pc = 0x00009be0
Found by: stack scanning
4 breakpad_sample!google_breakpad::TypedMDRVA<MDString>::AllocateObjectAndArray(unsigned int, unsigned int) [minidump_file_writer-inl.h : 66 + 0x2e]
sp = 0xbebacb94 pc = 0x00009a40
Found by: stack scanning
Loaded modules:
0x00008000 - 0x0001cfff breakpad_sample ??? (main)
0xb6ca6000 - 0xb6dc9fff libc-2.16.so ??? (WARNING: No symbols, libc-2.16.so, D4DD1DB3B93E4BDC3CF81E63D83B8B110)
0xb6dd7000 - 0xb6deafff libpthread-2.16.so ???
0xb6df6000 - 0xb6e11fff libgcc_s.so.1 ???
0xb6e1b000 - 0xb6e82fff libm-2.16.so ???
0xb6e8c000 - 0xb6f43fff libstdc++.so.6.0.19 ???
0xb6f57000 - 0xb6f58fff libdl-2.16.so ???
0xb6f62000 - 0xb6f80fff ld-2.16.so ???
2017-06-15 20:15:03: minidump.cc:4783: INFO: Minidump closing minidump
补充:
可以使用下面命令生成一个crash文件然后拷贝到PC上看:
~# minidump_stackwalk /tmp/d23f8d5e-5832-45ac-da9a718d-7d847b15.dmp /tmp/symbols >/tmp/dump.crash
实例二、so库文件的dump文件分析
加入你的应用是死再libmx.so库里,那么按照实例一处理你所看到的是如下的现象
Operating system: Linux
0.0.0 Linux 3.10.0_hi3536 #77 SMP Tue Jun 27 10:42:15 CST 2017 armv7l
CPU: arm
ARMv1 ARM part(0x4100c0e0) features: swp,half,thumb,fastmult,vfpv2,edsp,neon,vfpv3,tls,vfpv4,idiva,idivt
4 CPUs
GPU: UNKNOWN
Crash reason: SIGFPE
Crash address: 0x10d9
Process uptime: not available
Thread 7 (crashed)
0 libpthread-2.16.so + 0x103a4
r0 = 0x00000000 r1 = 0x000010f2 r2 = 0x00000008 r3 = 0xacbff910
r4 = 0xb6b2f3b0 r5 = 0x9ef15698 r6 = 0x02a5f5a8 r7 = 0x0000010c
r8 = 0xbe9f4ccc r9 = 0x00000014 r10 = 0x00000000 r12 = 0x00000008
fp = 0xacbfed4c sp = 0xacbfecec lr = 0xb6b42d84 pc = 0xb099a3a4
Found by: given as instruction pointer in context
1 libmx.so + 0x27b382
sp = 0xacbfecf8 pc = 0xb6a44384
Found by: stack scanning
2 libmx.so + 0x35c4f2
sp = 0xacbfed08 pc = 0xb6b254f4
Found by: stack scanning
3 libmx.so + 0x3663ae
sp = 0xacbfed48 pc = 0xb6b2f3b0
...
Loaded modules:
0x00008000 - 0x00aaffff breakpad_sample ??? (main)
0x9db9a000 - 0x9e4e6fff simhei.ttf ???
0xb67c9000 - 0xb6b7cfff libmx.so ??? (WARNING: No symbols, libnetec.so, E4F19D64548F2D4B67C47B76592E79F70)
在上面的 libmx.so只给出地址,没给出函数名称,而在Loaded modules中可以看到libmx.so下的警告No symbols,所以下面给libmx.so制作一个sym即可,步骤如下:
# cd breakpad_sample/lib
# dump_syms libmx.so >libmx.so.sym
# head -n1 libmx.so.sym
MODULE Linux arm E4F19D64548F2D4B67C47B76592E79F70 libnetec.so
# mkdir -p /tmp/symbols/libmx.so/E4F1
9D64548F2D4B67C47B76592E79F70/
# mv libmx.so.sym /tmp/symbols/libmx.so/E4F1
9D64548F2D4B67C47B76592E79F70/
# minidump_stackwalk /tmp/0300e6cc-21be-4cce-652af6
b4-230197f0.dmp /tmp/symbols/>0300e.crash
这个时候你去看0300e.crash就可以看到libmx.so中的函数名称了,
注意:
取名一定要按照规则去做,比如生成sym文件,一定是 二进制程序文件名称加.sym 或者so文件夹.sym,大小写也不能改。
参考:
1.Google Breakpad 之一,跨平台crash 处理上报系统简介
http://blog.csdn.net/wpc320/article/details/8290501
2.Breakpad 使用方法理解文档
http://blog.csdn.net/vagrxie/article/details/2501244
3.google官方文档:
http://code.google.com/p/google-breakpad/wiki/GettingStartedWithBreakpad
4.some simple reimplementations of libc functions
http://code.google.com/p/google-breakpad/source/browse/trunk/src/common/linux/linux_libc_support.h
5.linux syscall support
http://code.google.com/p/linux-syscall-support/