Google Breakpad的使用
Google breakpad是一个跨平台的崩溃转储和分析框架和工具集合。
Breakpad由三个主要组件:
-
client 是一个库,以library的形式内置在你的应用中,以配置客户端发生了崩溃时写入一个minidump文件
-
symbol dumper 是一个程序,读取由编译器产生的调试信息(debugging information),并生成一个使用Breakpad格式的符号文件( symbol file)
-
processor 是一个程序,读取 minidump文件 和 symbol file,生成可读的c/c++ 堆栈跟踪(Stack trace.)
默认情况下,当崩溃时breakpad会生成一个minidump文件,
在不同平台上的实现机制不一样:
- 在windows平台上,使用微软提供的 SetUnhandledExceptionFilter() 方法来实现。
- 在OS X平台上,通过创建一个线程来监听 Mach Exception port 来实现。
- 在Linux平台上,通过设置一个信号处理器来监听 SIGILL SIGSEGV 等异常信号。
当minidump被生成后,在不同平台上也使用不同的机制来上传crash dump文件。
在Linux平台使用breakpad
- 下载源码,具体的编译过程请参考breakpad
git clone https://chromium.googlesource.com/breakpad/breakpad
或
git clone https://github.com/google/breakpad.git
- 在breakpad源码目录下通过运行命令:
./configure
make
编译出错
In file included from ./src/client/linux/dump_writer_common/thread_info.h:36,
from ./src/client/linux/minidump_writer/linux_dumper.h:53,
from ./src/client/linux/minidump_writer/minidump_writer.h:41,
from src/tools/linux/core2md/core2md.cc:37:
./src/common/memory_allocator.h:49:10: fatal error: third_party/lss/linux_syscall_support.h: No such file or directory
49 | #include "third_party/lss/linux_syscall_support.h"
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:5667: src/tools/linux/core2md/core2md.o] Error 1
下载依赖包
git clone https://chromium.googlesource.com/linux-syscall-support src/third_party/lss
连接可能超时,无法下载。或 下载文件
进入 breakpad 的 src 目录的 third-party 文件夹,创建 lss 文件夹,拷贝下载的依赖包里的文件。
执行验证文件的正确性: gcc -Wall -Wextra -Wstrict-prototypes -c linux_syscall_support.h
然后重新编译
编译完以后会在生成两个可执行文件,分别是src/processor/minidump_stackwalk和src/tools/linux/dump_syms/dump_syms
生成 src/client/linux/libbreakpad_client.a
- 在应用中使用Breakpad
将自动生成 src/client/linux/libbreakpad_client.a 文件, 其包含了在你的应用中生成minidumps文件的必要代码。
首先配置build precess来link刚生成的 libbreakpad_client.a 文件。
然后设置 include paths 来 包含 google-breakpad 目录下的 src 目录。
接下来include头文件:
现在你就可以初始化 ExceptionHandler 对象,初始化的时候需要提供一个用于写minidump文件的目录,以及一个回调函数用于在minidump文件写完以后调用。
#include "client/linux/handler/exception_handler.h"
// 写完minidump后的回调函数
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
void* context, bool succeeded) {
printf("Dump path: %s\n", descriptor.path());
return succeeded;
}
// 触发crash来测试
void testCrash() {
int* a = nullptr;
*a = 1;
}
int main(int argc, char* argv[]) {
// 初始化ExceptionHandler
google_breakpad::MinidumpDescriptor descriptor("/tmp"); // minidump文件写入到的目录
google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL, true, -1);
testCrash();
return 0;
}
编译并运行这个实例应该会在 /tmp 目录下生成 minidump 文件,并且终端下会输入minidump文件的路径。
g++ -g -I ../breakpad/src -o test breakpad_sample.c ../breakpad/src/client/linux/libbreakpad_client.a -lpthread
- 生成symbols文件
为了生成可读的stack trace, breakpad需要你将binaries里的调试符号(debugging symbols)转换成基于文本格式的symbol files。
首先确保你在编译代码带调试符号,release的时候加上 -g 参数来生成带调试符号的。
运行 dump_syms 命令来生成 symbol files,如下:
$ google-breakpad/src/tools/linux/dump_syms/dump_syms ./TestBreakPad_linux > TestBreakPad_linux.sym
- 生成Stack Trace
为了可以使用 `minidump_stackwalk 工具来生成stack trace,你需要将文件放置在一定的目录结构,symbol file的第一行说明了需要放置的目录结构,可以使用命令,或使用 Mozilla 提供的 symbolstore.py 工具来新建这样的目录结构。
$ head -n1 TestBreakPad_linux.sym.sym
// MODULE Linux x86_64 E52092337B1FB1646ED685CC18FD30790 TestBreakPad_linux
├── symbol
│ └── TestBreakPad_linux
│ └── E52092337B1FB1646ED685CC18FD30790
│ └── TestBreakPad_linux.sym
$ mkdir -p ./symbol/TestBreakPad_linux/E52092337B1FB1646ED685CC18FD30790
$ mv test.sym ./symbol/TestBreakPad_linux/E52092337B1FB1646ED685CC18FD30790
$ google-breakpad/src/processor/minidump_stackwalk 41c013b5-9e9a-4dfc-ec430795-b944e4b3.dmp ./symbol
它会生成verbose output到stderr, stacktrace到stdout。
CPU: amd64
family 6 model 78 stepping 3
4 CPUs
GPU: UNKNOWN
Crash reason: SIGSEGV /SEGV_MAPERR
Crash address: 0x0
Process uptime: not available
Thread 0 (crashed)
0 TestBreakPad_linux!testCrash() [main.cpp : 16 + 0x4]
rax = 0x0000000000000000 rdx = 0x0000000000000000
rcx = 0x00007fff570e1350 rbx = 0x0000000000000000
rsi = 0x0000000000000000 rdi = 0x0000561071a596c0
rbp = 0x00007fff570e13a0 rsp = 0x00007fff570e13a0
r8 = 0x0000000000000000 r9 = 0x000056107214af88
r10 = 0x0000000000000008 r11 = 0x00007f84945a4ce0
r12 = 0x00007fff570e1678 r13 = 0x0000561071a40068
r14 = 0x0000561071a58a18 r15 = 0x00007f8494840040
rip = 0x0000561071a4005f
Found by: given as instruction pointer in context
1 TestBreakPad_linux!main [main.cpp : 24 + 0x5]
rbx = 0x0000000000000000 rbp = 0x00007fff570e1560
rsp = 0x00007fff570e13b0 r12 = 0x00007fff570e1678
r13 = 0x0000561071a40068 r14 = 0x0000561071a58a18
r15 = 0x00007f8494840040 rip = 0x0000561071a4013a
Found by: call frame info
2 libc.so.6 + 0x29d90
rbx = 0x0000000000000000 rbp = 0x0000000000000001
rsp = 0x00007fff570e1570 r12 = 0x00007fff570e1678
r13 = 0x0000561071a40068 r14 = 0x0000561071a58a18
r15 = 0x00007f8494840040 rip = 0x00007f84943b4d90
Found by: call frame info
3 TestBreakPad_linux!testCrash() [main.cpp : 17 + 0x3]
rsp = 0x00007fff570e1580 rip = 0x0000561071a40068
Found by: stack scanning
4 0x1570e1688
rbp = 0x0000561071a40068 rsp = 0x00007fff570e1588
rip = 0x00000001570e1688
Found by: call frame info
5 TestBreakPad_linux!testCrash() [main.cpp : 17 + 0x3]
rsp = 0x00007fff570e15b0 rip = 0x0000561071a40068
Found by: stack scanning
6 0x561071a58a18
rbp = 0x0000561071a40068 rsp = 0x00007fff570e15b8
rip = 0x0000561071a58a18
Found by: call frame info
7 libc.so.6 + 0x29e40
rsp = 0x00007fff570e1610 rip = 0x00007f84943b4e40
Found by: stack scanning
8 TestBreakPad_linux!google_breakpad::ConvertUTF8toUTF32(unsigned char const**, unsigned char const*, unsigned long**, unsigned long*, google_breakpad::ConversionFlags) [clone .cold] + 0xd
rsp = 0x00007fff570e1640 rip = 0x0000561071a3ff20
Found by: stack scanning
9 TestBreakPad_linux!_start + 0x25
rsp = 0x00007fff570e1660 rip = 0x0000561071a3ff45
Found by: stack scanning
10 0x7fff570e1668
rsp = 0x00007fff570e1668 rip = 0x00007fff570e1668
Found by: call frame info
Loaded modules:
0x561071a3c000 - 0x561071a51fff TestBreakPad_linux ??? (main)
0x7f84942a4000 - 0x7f849432dfff libm.so.6 ???
0x7f849438b000 - 0x7f8494547fff libc.so.6 ??? (WARNING: No symbols, libc.so.6, 489D3869975ADB93E873F0EA2C93E02E0)
0x7f84945b3000 - 0x7f84945ccfff libgcc_s.so.1 ???
0x7f84945d3000 - 0x7f849477cfff libstdc++.so.6 ???
0x7f8494806000 - 0x7f8494831fff ld-linux-x86-64.so.2 ???
0x7fff57182000 - 0x7fff57183fff linux-gate.so ???
2023-09-12 11:52:35: minidump.cc:5558: INFO: Minidump closing minidump