|
Breakpad 是 Google 用 C++ 編寫的一個開源、跨平臺的崩潰報告系統(tǒng),它支持 Windows、Linux 和 macOS,并提供了一個上傳器,可以在進程崩潰時向一個配置好的 URL 提交 minidump 文件。
目前,有很多大型項目都在使用 Breakpad,例如:Google Chrome、Firefox、Google Picasa、Camino、Google Earth 等。 主頁:https://chromium./breakpad/breakpad/ 文檔:https://chromium./breakpad/breakpad/+/HEAD/docs GitHub 地址:https://github.com/google/breakpad
工作原理 BreakPad 工作原理: 
其中,包含了三個主要組件: Breakpad client:是一個庫(即:libbreakpad_client.a),將來要集成到我們的程序中。用于寫 minidump 文件,捕獲當前線程的狀態(tài),以及可執(zhí)行文件/共享庫的標識。 Breakpad 符號轉(zhuǎn)儲工具:是一個程序(即:dump_syms),用于讀取由編譯器產(chǎn)生的調(diào)試信息,并以 Breakpad 自己的格式生成一個符號文件。 Breakpad minidump 處理器:是一個程序(即:minidump_stackwalk),用于讀取 minidump 文件和符號文件,并生成一個可讀的 C/C++ 堆棧跟蹤。
編譯安裝 下載 Breakpad 源碼; 由于 Breakpad 依賴于 LSS,所以還需要下載它(地址:https://github.com/adelshokhy112/linux-syscall-support); 將 LSS 中的 linux_syscall_support.h 文件放至 breakpad/src/third_party/lss/ 目錄下。 編譯 Breakpad,步驟非常簡單:
$ cd breakpad $ ./configure && make $ make $ sudo make install
成功之后,會生成 libbreakpad_client.a 庫文件,以及 dump_syms、minidump_stackwalk 等程序。 將 Breakpad 集成到程序中 和其他第三方庫的用法一樣,要將 Breakpad 集成到程序中,先要鏈接生成的庫 libbreakpad_client.a,并設(shè)置包含路徑為 breakpad/src/,接下來就可以 include 頭文件了。 為了生成 mindump 文件,我們需要實例化一個 ExceptionHandler 對象,并提供一個存儲 mindump 的路徑,以及一個回調(diào)函數(shù)來接收關(guān)于已寫入的 mindump 的信息: #include 'client/linux/handler/exception_handler.h' #include <iostream>
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { std::cout << 'Dump path:' << descriptor.path() << std::endl;
return succeeded; }
void crash() { int* a = nullptr; *a = 1; }
int main(int argc, char* argv[]) { google_breakpad::MinidumpDescriptor descriptor('/tmp'); google_breakpad::ExceptionHandler eh(descriptor, nullptr, dumpCallback, nullptr, true, -1); crash();
return 0; }
編譯運行這個程序,會在 /tmp/ 目錄下生成一個 minidump 文件,并在退出之前打印該文件的路徑。 注意:在使用 Breakpad 時,需要目標程序內(nèi)包含調(diào)試信息,這樣 dump_syms 工具才能從中解析出調(diào)試符號。而在默認情況下,Release 模式編譯的程序是并不包含調(diào)試信息,若想包含,需要在編譯程序時添加 -g 選項。 生成可讀的堆棧跟蹤 帶調(diào)試信息的目標程序有了,minidump 文件有了,dump_syms 和 minidump_stackwalk 等工具也有了,現(xiàn)在要做的就是生成有用的堆棧跟蹤信息了! Breakpad 要求我們將目標程序中的調(diào)試符號轉(zhuǎn)換為文本格式的符號文件,這一步需要通過 dump_syms 工具來完成。 假設(shè),我們的程序名為 test,執(zhí)行以下命令,便會生成一個名為 test.sym 的符號文件: $ dump_syms ./test > test.sym
為了使用這些符號,需要將生成的符號文件放在特定的目錄結(jié)構(gòu)中: 
查看符號文件,第一行包含了生成目錄結(jié)構(gòu)所需的信息: $ head -n1 test.sym MODULE Linux x86_64 95E20E34BE203CB093B675D606A7D7D20 test
創(chuàng)建以上目錄結(jié)構(gòu),并將符號文件移動到該路徑下: $ mkdir -p ./symbols/test/95E20E34BE203CB093B675D606A7D7D20 $ mv test.sym ./symbols/test/95E20E34BE203CB093B675D606A7D7D20/
當一切準備就緒,minidump_stackwalk 工具就派上用場了。 只需將 mindump 文件和符號路徑作為命令行參數(shù)傳遞給它,便能生成堆棧跟蹤信息了。為了便于分析,可以將輸出重定向至文件中:
$ minidump_stackwalk /tmp/48596758-1d7a-4318-15edb4af-a9186ad7.dmp ./symbols > error.log
定位 Crash 所在位置 打開 error.log,搜索關(guān)鍵字“crashed”,一般與它最接近的一行,就是發(fā)生崩潰時程序的堆棧信息: 
可以很清楚地看到,崩潰發(fā)生在 main.cpp 的第 16 行。 查看我們的測試程序,與預(yù)期結(jié)果一樣: 
至此,Crash 所在位置已經(jīng)準確地定位到了,趕緊抓緊時間修改吧! 將上述過程腳本化 由于以上過程會經(jīng)常執(zhí)行,可以將其做成自動化腳本,不僅可有效防止步驟命令的遺忘,而且極大的加快了操作速度。 新建一個腳本 dumptool.sh,內(nèi)容如下: #!/bin/bash
if [ $# != 3 ] ; then echo 'USAGE: $0 TARGET_NAME DMP_NAME OUTPUT_NAME' echo ' e.g.: $0 test 48596758-1d7a-4318-15edb4af-a9186ad7.dmp error.log' exit 1; fi
#獲取輸入?yún)?shù) target_file_name=$1 dmp_file_name=$2 output_file_name=$3
getSymbol() { echo '@getSymbol: start get symbol' dump\_syms ./$target_file_name > $target_file_name'.sym' }
getStackTrace() { echo '@getStackTrace: start get StackTrace' sym_file_name=$target_file_name'.sym'
#獲取符號文件中的第一行 line1=`head -n1 $sym_file_name`
#從第一行字符串中獲取版本號 OIFS=$IFS; IFS=' '; set -- $line1; aa=$1;bb=$2;cc=$3;dd=$4; IFS=$OIFS
version_number=$dd
#創(chuàng)建特定的目錄結(jié)構(gòu),并將符號文件移進去 mkdir -p ./symbols/$target_file_name/$version_number mv $sym_file_name ./symbols/$target_file_name/$version_number
#將堆棧跟蹤信息重定向到文件中 minidump_stackwalk $dmp_file_name ./symbols > $output_file_name }
main() { getSymbol if [ $? == 0 ] then getStackTrace fi }
#運行main main
使用比較簡單,先為腳本增加可執(zhí)行權(quán)限: $ chmod +x ./dump_tool.sh
然后執(zhí)行下述命令,將二進制文件、minidump 文件、輸出日志文件作為參數(shù)傳遞給它: $ ./dumptool.sh ./test /tmp/48596758-1d7a-4318-15edb4af-a9186ad7.dmp error.log
完成之后,所有的堆棧跟蹤信息就會被輸出到 error.log 文件中了。 很好用吧,學會這個絕招,讓 C++ 崩潰無處可逃!- EOF -
|