項(xiàng)目介紹
breakpad是google開發(fā)的一個(gè)跨平臺(tái)C/C++ dump捕獲開源庫,崩潰文件使用微軟的minidump格式存儲(chǔ),也支持發(fā)送這個(gè)dump文件到服務(wù)器,breakpad可以在程序崩潰時(shí)觸發(fā)dump寫入操作,也可以在沒有觸發(fā)dump時(shí)主動(dòng)寫dump文件。breakpad支持windows、linux、macos、android、ios等。目前已有Google Chrome, Firefox, Google Picasa, Camino, Google Earth等項(xiàng)目使用。
- 主頁:https://chromium.googlesource.com/breakpad/breakpad/
- 文檔:https://chromium.googlesource.com/breakpad/breakpad/+/HEAD/docs
- GitHub 地址:https://github.com/google/breakpad
主要組件
breakpad有三個(gè)主要的組件:
- breakpad client:breakpad的客戶端靜態(tài)庫(即:libbreakpad_client.a)。它的主要作用是在程序崩潰后,接管程序的異常處理,具體來說,它主要做了兩方面的事情。
- 響應(yīng)程序崩潰時(shí)接收到的signal,包括:SIGSEGV,SIGABRT,SIGFPE,SIGILL,SIGBUS。 (另外兩個(gè)SIGSTOP,SIGKILL無法處理)
- 獲取程序崩潰那一刻的運(yùn)行時(shí)信息,保存為一個(gè)minidump格式的文件。
- symbol dumper:調(diào)試信息文件生成程序(即:dump_syms)。主要是用來從可執(zhí)行程序中提取與符號(hào)相關(guān)的信息,并保存為一種特定格式的文件。
- processor module:minidump 處理程序(即:minidump_stackwalk),它的作用就是根據(jù)coredump及symbol file,構(gòu)建出可讀的call stack。
下載編譯
- 下載Breakpad源碼:git clone https://github.com/google/breakpad 。
- 下載Breakpad依賴的三方庫 LSS:git clone https://github.com/adelshokhy112/linux-syscall-support ,將 LSS 中的linux_syscall_support.h文件放至breakpad/src/third_party/lss/ 目錄下。
- 編譯Breakpad:在源目錄下執(zhí)行./configure && make。
libbreakpad_client.a在src/client/linux/ 目錄下。
dump_syms在src/tools/linux/dump_syms/目錄下。
minidump_stackwalk在src/processor/目錄下。
還有一個(gè)將minidump轉(zhuǎn)換為core文件的程序minidump-2-core在src/tools/linux/md2core/目錄下。
集成breakpad
- 首先,在程序中引用異常處理程序的頭文件。
#include "client/linux/handler/exception_handler.h"
- 為了生成minidump文件,我們需要實(shí)例化一個(gè)ExceptionHandler對(duì)象,并提供一個(gè)存儲(chǔ)minidump的路徑,以及一個(gè)回調(diào)函數(shù)來接收關(guān)于已寫入的minidump的信息。
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
void* context, bool succeeded) {
printf("Dump path: %s\n", descriptor.path());
return succeeded;
}
void crash() { volatile 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);
crash();
return 0;
}
- 在編譯時(shí)需要鏈接breakpad提供的靜態(tài)庫libbreakpad_client.a,頭文件搜索路徑需要包含breakpad的src目錄。編譯運(yùn)行這個(gè)程序,會(huì)在/tmp/目錄下生成一個(gè)minidump文件,并在退出之前打印該文件的路徑。
- 編譯命令如下:
$ g++ -g -I ./ -o breakpad_test test.cpp ./client/linux/libbreakpad_client.a -lpthread -std=c++11
- PS:回調(diào)函數(shù)中應(yīng)該盡可能少的做一些工作。因?yàn)楫?dāng)該函數(shù)回調(diào)時(shí),程序處于不安全狀態(tài)。從其他函數(shù)庫分配內(nèi)存或調(diào)用函數(shù)可能并不安全。如果你必須要在回調(diào)函數(shù)中實(shí)現(xiàn)一些功能,最安全的操作是
fork
和exec
一個(gè)新的進(jìn)程來執(zhí)行你需要做的任何功能。Breakpad源碼中包含libc函數(shù)的一些簡(jiǎn)單重新實(shí)現(xiàn),同樣,在src/third_party/lss中包含一些用于進(jìn)行Linux系統(tǒng)調(diào)用的函數(shù),應(yīng)該避免直接調(diào)用libc和一些其他的動(dòng)態(tài)庫。
發(fā)送minidump文件
- 在實(shí)際的應(yīng)用程序中,可以將minidump文件發(fā)送到服務(wù)器以便進(jìn)行后續(xù)的分析和統(tǒng)計(jì)工作。
- Breakpad源碼中相關(guān)文件在src/common/linux/http_upload.h(HTTP上傳)和src/tools/linux/symupload/minidump_upload.cc (minidump上傳)。
生成符號(hào)文件
- 為了產(chǎn)生有用的堆棧信息,Breakpad要求將二進(jìn)制文件中的調(diào)試符號(hào)轉(zhuǎn)換為文本格式的符號(hào)文件。
- 首先,需要確保已使用-g編譯程序以包含調(diào)試符號(hào)。
- 然后,使用dump_syms工具生成文本格式的符號(hào)文件。比如程序名為test,則命令如下:
$ ./dump_syms ./test > test.sym
- 為了將這些符號(hào)與minidump_stackwalk工具一起使用,還需要將它們放在特定的目錄結(jié)構(gòu)中。 符號(hào)文件的第一行包含生成此目錄結(jié)構(gòu)所需的信息,比如上述的test.sym可使用如下命令:
$ head -n1 test.sym MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 test
$ mkdir -p ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830
$ mv test.sym ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830
根據(jù)minnidump和symbol生成stack trace
minidump_stackwalk工具可以提取一個(gè)minidump文件及其相應(yīng)的文本格式符號(hào),并生成可讀的堆棧信息。在上述示例中可以使用如下命令生成最后的可讀堆棧信息文件:
$ ./minidump_stackwalk xxxx.dmp ./symbols > dmp_info.txt
使用總結(jié)
- 使用-g選項(xiàng)編譯程序。
- 使用dump_syms工具提取上一步生成的可執(zhí)行文件中的符號(hào),然后將符號(hào)文件放到指定目錄下。
- 去掉-g選項(xiàng)重新編譯程序。
- 待程序產(chǎn)生崩潰時(shí)生成dmp文件。
- 使用minidump_stackwalk工具將dmp文件轉(zhuǎn)換成可讀的堆棧信息文件。
以上,使用自動(dòng)化腳本更簡(jiǎn)單。