Google Breakpad 學(xué)習(xí)筆記

作者:lds(lds2012@gmail.com)

日期:2017-03-24

一. BreakPad簡介

Google breakpad是一個跨平臺的崩潰轉(zhuǎn)儲和分析框架和工具集合。

Breakpad由三個主要組件:

  • client,以library的形式內(nèi)置在你的應(yīng)用中,當崩潰發(fā)生時寫 minidump文件
  • symbol dumper, 讀取由編譯器生成的調(diào)試信息(debugging information),并生成 symbol file
  • processor, 讀取 minidump文件symbol file ,生成可讀的c/c++ Stack trace.

簡單來說就是一個生成 minidump,一個生成symbol file,然后將其合并處理成可讀的Stack trace。

二. MiniDump文件格式

minidump文件格式是由微軟開發(fā)的用于崩潰上傳,它包括:

  • 當dump生成時進程中一系列executable和shared libraries, 包括這些文件的文件名和版本號。
  • 進程中的線程列表,對于每個線程,minidump包含它在寄存器中的狀態(tài),線程的stack memory內(nèi)容。這些數(shù)據(jù)都是未解析的字節(jié)流,Breakpad client通常沒有調(diào)試信息(debugging information)能生成函數(shù)名,行號,甚至無法確定stack frame的邊界。
  • 其他收集關(guān)于系統(tǒng)的信息,如:處理器,操作系統(tǒng)高版本,dump的原因等等。

breakpad在所有平臺上(windows/linux等)都統(tǒng)一使用minidump文件格式,而不使用core files,原因是因為:

  • core files可能很大,而minidump比較小。
  • core files文檔不全
  • 很難說服windows機器去生成core files,但可以說服其他機器來生成minidump文件。
  • breakpad只支持一種統(tǒng)一的格式會比較簡單,而不是同時支持多種格式。

什么是core files?core files是unit系統(tǒng)上程序崩潰時生成的文件。

參見:http://www.lxweimin.com/p/8e1352a9638f

三. Symbols文件格式

symbols文件是基于純文本的,每一行一條記錄,每條記錄中的字段以一個空格作為分隔符,每條記錄的第一個字段表示這一行是什么類型的記錄。

記錄類型:

  • 模塊記錄:MODULE operatingsystem architecture id name
  • 文件記錄:FILE number name
  • 函數(shù)記錄:FUNC address size parameter_size name
  • 行號記錄:address size line filenum
  • PUBLIC記錄:PUBLIC address parameter_size name
  • STACK WIN
  • STACK CFI

參見:https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md

四. 不同平臺的實現(xiàn)原理

默認情況下,當崩潰時breakpad會生成一個minidump文件,在不同平臺上的實現(xiàn)機制不一樣:

  • 在windows平臺上,使用微軟提供的 SetUnhandledExceptionFilter() 方法來實現(xiàn)。
  • 在OS X平臺上,通過創(chuàng)建一個線程來監(jiān)聽 Mach Exception port 來實現(xiàn)。
  • 在Linux平臺上,通過設(shè)置一個信號處理器來監(jiān)聽 SIGILL SIGSEGV 等異常信號。

當minidump被生成后,在不同平臺上也使用不同的機制來上傳crash dump文件。

參見:Windows SetUnhandledExceptionFilter
參見:Mac OS X Exception handling
參見:Catching Exceptions and Printing Stack Traces for C on Windows, Linux, & Mac

五. 異常處理機制

提供兩種不同的異常處理機制:

  1. 同進程(in-process)
  2. 跨進程(out-precess)

因為在崩潰的進程寫minidump文件是不安全的,所以三個平臺(windows、linux、mac os)都提供跨進程的異常處理機制。

六. 在Linux平臺使用breakpad

這里因為要研究Android上使用breakpad,所有主要研究linux平臺,windows和mac平臺的使用方法請自行參考文檔。

6.1 構(gòu)建Breakpad庫

breakpad提供自動構(gòu)建工具來構(gòu)建linux client庫和processor庫。

在breakpad源碼目錄下通過運行命令:

./configure
make

將自動生成 src/client/linux/libbreakpad_client.a 文件, 其包含了在你的應(yīng)用中生成minidumps文件的必要代碼。

6.2 在你的應(yīng)用中使用Breakpad

首先配置build precess來link剛生成的 libbreakpad_client.a 文件。

然后設(shè)置 include paths 來 包含 google-breakpad 目錄下的 src 目錄。

接下來include頭文件:

#include "client/linux/handler/exception_handler.h"

現(xiàn)在你就可以初始化 ExceptionHandler 對象,初始化的時候需要提供一個用于寫minidump文件的目錄,以及一個回調(diào)函數(shù)用于在minidump文件寫完以后調(diào)用。


int main(int argc, char* argv[]) {
  // 初始化ExceptionHandler
  google_breakpad::MinidumpDescriptor descriptor("/tmp"); // minidump文件寫入到的目錄
  google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL, true, -1);
  
  crash();
  return 0;
}

// 寫完minidump后的回調(diào)函數(shù)
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
                         void* context, bool succeeded) {
  printf("Dump path: %s\n", descriptor.path());
  return succeeded;
}

// 觸發(fā)crash來測試
void crash() {
  volatile int* a = (int*)(NULL);
  *a = 1;
}

編譯并運行這個實例應(yīng)該會在 /tmp 目錄下生成 minidump 文件,并且終端下會輸入minidump文件的路徑。

關(guān)于初始化ExceptionHandler可以接受的參數(shù)需要參見源碼

  ExceptionHandler(const MinidumpDescriptor& descriptor,
                   FilterCallback filter,
                   MinidumpCallback callback,
                   void* callback_context,
                   bool install_handler,
                   const int server_fd);

具體參數(shù):

  • descripter,minidump文件寫入的目錄
  • filter,可選,在寫minidump文件之前,會先調(diào)用filter回調(diào)。根據(jù)它返回true/false來決定是否需要寫minidump文件。
  • callback, 可選,在寫minidump文件之后調(diào)用的回調(diào)函數(shù)
  • callback_context,
  • install_handler, 如果為ture,不管怎樣當未捕捉異常被拋出時都會寫入minidump文件,如果為false則必須明確調(diào)用了 WriteMinidump 才會寫入minidump 文件
  • server_fd, 如果為-1,則使用同線程模式(in-precess),如果有一個有效的值,則使用跨線程模式(out-of-process)

參見:exception_handler.h源碼

需要注意的是,你必須在callback回調(diào)函數(shù)中做盡量少的工作,因為你的程序處于一個不安全的狀態(tài),它需要無法安全的去分配內(nèi)存,或調(diào)用其他共享庫中的函數(shù)。安全的方式是 forkexec 一個新進程去做想要做的事情。如果你需要在回調(diào)中做一些工作,breakpad源碼提供一些簡單的重新實現(xiàn)的libc庫里的方法,來避免直接調(diào)用libc, 并提供一個a header file for making linux system calls,來避免直接調(diào)用其他共享庫的方法。

6.3 發(fā)送minidump文件

在真實環(huán)境中,你通常需要以某種方式來處理minidump文件,例如把它發(fā)送給服務(wù)器來進行分析,Breakpad源碼提供了一些HTTP上傳的代碼,并提供一個minidump上傳工具( 詳見minidump_upload.cc)。

6.4 生成symbols文件

為了生成可讀的stack trace, breakpad需要你將binaries里的調(diào)試符號(debugging symbols)轉(zhuǎn)換成基于文本格式的symbol files。

首先確保你在編譯代碼的時候加上 -g 參數(shù)來生成帶調(diào)試符號的。

然后使用 configure && make breakpad源碼來生成 dump_syms 工具。

接著運行 dump_syms 命令來生成 symbol files,如下:

$ google-breakpad/src/tools/linux/dump_syms/dump_syms ./test > test.sym

為了可以使用 ``minidump_stackwalk` 工具來生成stack trace,你需要將文件放置在一定的目錄結(jié)構(gòu),symbol file的第一行說明了需要放置的目錄結(jié)構(gòu),可以使用命令,或使用 Mozilla 提供的 symbolstore.py 工具來新建這樣的目錄結(jié)構(gòu)。

$ head -n1 test.sym 
// MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 test
$ mkdir -p ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830
$ mv test.sym ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830

6.5 生成Stack Trace

breakpad包含一個叫做 minidump_stackwalk 的工具來將 minidump 文件,外加symbol files來生成一個人可讀的stack trace。在編譯breakpad后,這個工具一般在 google-breakpad/src/processor 目錄下, 通過將 minidump 和 symbol files 傳入給它即可:

$ google-breakpad/src/processor/minidump_stackwalk minidump.dmp ./symbols

它會生成verbose output到stderr, stacktrace到stdout。

參見:How To Add Breakpad To Your Linux Application

七. 在Android平臺使用Breakpad

Breakpad支持 ARM x86 和 MIPS 架構(gòu)的Android系統(tǒng)。需要Android NDK r11c及以上版本。

7.1 構(gòu)建client庫

Android版本的Client庫設(shè)計為一個靜態(tài)庫(static library)來使得你可以鏈接到你的Android native代碼里。

一共有兩種方法來build。

7.1.1 方法1:使用ndk-build構(gòu)建(推薦)

使用ndk-build來構(gòu)建,需要如下幾個步驟:

  1. 在你的項目中的 Android.mk 中 include google-breakpad的 Android.mk
include $(LOCAL_PATH)/breakpad/android/google_breakpad/Android.mk
  1. 鏈接break-client未你的靜態(tài)庫模塊
LOCAL_STATIC_LIBRARIES += breakpad_client
  1. 因為需要c++ STL,所以還需要在 Application.mk 文件中加入 STL 支持:
APP_STL := stlport_static

7.1.2 方法2:使用Android toolchain構(gòu)建

  $GOOGLE_BREAKPAD_PATH/configure --host=arm-linux-androideabi \
                                  --disable-processor \
                                  --disable-tools
  make -j4

將會build到 src/client/linux/libbreakpad_client.a 文件。

可使用 make check 來在Android設(shè)備上運行測試。

7.2 在Android上使用Breakpad

在Android平臺上使用breakpad,基本和在linux平臺上是基本類似的。

需要如下幾個步驟:

  1. 在cpp文件中include exception_handler頭文件
#include "client/linux/handler/exception_handler.h"
  1. 如果使用ndk-build,需要配置include path(在Android.mk文件中)
LOCAL_C_INCLUDES        := $(GOOGLE_BREAKPAD_PATH)/src/common/android/include \
                           $(GOOGLE_BREAKPAD_PATH)/src

并且加上 -llog flag

LOCAL_LDLIBS := -llog
  1. 時刻記住在Android系統(tǒng)上沒有 /tmp 目錄,需要指定一個其他目錄,可以是 application 專有目錄(/data/data/packageName/files),或者存儲到SDCard上面去(需要寫入權(quán)限)

7.3 生成stack trace

這個操作和其他平臺一樣。

  1. 從設(shè)備上獲取minidumps文件
  2. 使用dump_syms工具生成so的symbol files
dump_symc $PROJECT_PATH/obj/local/$ABI/libfoo.so > libfoo.so.sym
  1. 創(chuàng)建symbol files專有目錄結(jié)構(gòu)
// MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 test

$PROJECT_PATH/symbols/libfoo.so/6EDC6ACDB282125843FD59DA9C81BD830/libfoo.sym
  1. 使用 minidump_stackwalk 來生成stack trace:
minidump_stackwalk $MINIDUMP_FILE $PROJECT_PATH/symbols

參見:breakpad for android 官方文檔

八. 參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內(nèi)容