mac下利用Breakpad的dump文件進行調試


一、前情回顧

最近把公司的一個視頻處理程序更新了一個版本,准備提交測試的發現了崩潰的情況。這個程序采用Qt和ffmpeg技術棧開發,主要用於對視頻進行渲染拼接處理,在Windows和mac兩個平台同時進行發布。在windows上測試完一切正常,然而就在我以為一切大功告成的時候,測試的同事直接給我來了個當頭棒喝,程序崩潰了!沒有道理啊,同一套代碼在Windows上安然無恙,在Mac上為何直接崩潰?好消息是程序在崩潰的時候保存了dump文件。

這得感謝前段時間集成的Google Breakpad了。Google Breakpad是Google開發的一個跨平台異常捕獲和dump文件(准確的說是mini dump)生成的開發庫。利用這個庫可以在Windows, Mac, Linux, iOS, Android平台上對程序異常崩潰進行捕獲,並生成dump文件供后期調試。據說Google Chrome, Chromium, Firefox都使用了這套機制,因此其可用性是經得起考驗的,並且這個庫現在依然更新的很頻繁。

 如此強大的東西,怎么使用呢?好在網上關於breakpad的資料是還是挺多的,只不過都不是很完整很簡潔。要么就只介紹了實現原理、或者只介紹了怎么編譯、或者就只介紹了怎么集成,對於新手使用非常不友善。這里就根據我在Windows和Mac兩個平台的使用經驗來總結下吧。

二、breakpad的使用

 breakpad以源代碼的形式發布,所以首先要從倉庫中把代碼下下來:

git clone https://chromium.googlesource.com/breakpad/breakpad  

這個是Google的代碼倉庫,基於國內的環境需要把VPN打開。下載下來的代碼包含了windows, mac, linux三個平台所有的文件了,也包含了各個平台的工具源碼。沒錯,breakpad的工具需要自己編譯。

假設源代碼下載到了E:/breakpad,那么進入到這個目錄運行make命令:

./configure
make

在Windows上需要用gyp工具來編譯,所以還得下載gyp非常麻煩。在mac上就非常簡單了,直接運行上述命令即可生成靜態庫文件。但是工具的話需要進入到tools目錄,里面有個已經配置好的xcode工程,直接打開即可編譯。

不過要注意的是,最新的breakpad源碼在編譯工具的時候會報錯:

Undefined symbols for architecture x86_64:
  "google_breakpad::BaseName(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
      google_breakpad::DumpSymbols::CreateEmptyModule(google_breakpad::scoped_ptr<google_breakpad::Module>&) in dump_syms.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

解決辦法是:

 

 在這一步中我們編譯源碼主要是為了得到兩個工具:minidump_stackwalkdump_syms。這兩個分別有什么用呢?dump_syms用於從可執行程序中抽取出調試符號保存到syms符號文件中,而minidump_stackwalk則根據syms文件來分析mini dump文件,得到一個可讀性強的崩潰調用堆棧。由於我的工程是基於Qt的,所以我直接利用了Github上面的一個開源項目進行編譯。這個項目針對Qt剔除了一些無用的頭文件,並對源代碼做了稍微的調整。

基於QMake的工程,可以直接用Qt Creator打開編譯。在Windows上和Mac上無縫支持。編譯即可得到我們需要的lib文件了。這個在我們后面集成工程中鏈接需要用到。當然也可以直接將源代碼集成到工程去。

接下來就講講如何集成吧。集成步驟其實非常簡單,直接上代碼:

#ifdef _WINDOWS
#include <client/windows/handler/exception_handler.h>
#else
#include <client/mac/handler/exception_handler.h>
#endif

#ifdef _WINDOWS
bool minidumpCB(const wchar_t *dump_path, const wchar_t *id, void *context, EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion, bool succeeded) {
#else
bool minidumpCB(const char* dump_path, const char* id, void* context, bool succeeded) {
#endif
    if (succeeded) {
        std::wcout << "Mini Dump file: " << id << ".dump Path: " << dump_path << std::endl;
    }  
    return succeeded;
}

int main() {
#ifdef NDEBUG // 只在Release模式下啟用Breakpad #ifdef _WINDOWS google_breakpad::ExceptionHandler eh(dumpLocation.toStdWString(), NULL, minidumpCB, NULL, google_breakpad::ExceptionHandler::HANDLER_ALL); #else google_breakpad::ExceptionHandler eh(dumpLocation.toStdString(), NULL, minidumpCB, NULL, true, NULL); #endif
#endif }

接口非常簡單,只要定義一個回調函數minidumpCB()。當程序崩潰被捕捉到的時候就會調用這個函數,這里只是輸出了mini dump文件保存的位置。如果第一張截圖中的紅框所示。

三、dump文件如何利用

 生成的dump文件如何利用?如何轉換成我們能看得懂的調用堆棧信息?其實有上面編譯出來的兩個工具,接下來的工作分三個步驟:

  • 使用dump_syms生成符號表:
    ./dump_syms ~/Test/Caputre > Capture.syms
  • 創建有層次的調試符號文件夾:
    head -n1 Capture.syms  // 查看文件層次
    mkdir -p ./symbols/PanoramaCapture/3EXXXXXX/ //這一步根據上面的輸出來
    mv Capture.syms ./symbols/PanoramaCapture/3EXXXXX/ // 將符號文件移動進去
  • 利用minidump_stackwalk分析dump文件:
    ./minidump_stackwalk minidump.dmp ./symbols

 

   最后一步將輸出詳細的堆棧信息:

  相信有了這些信息,找出代碼中潛伏的bug不是什么難事了。而我也正是根據這些信息,成功解決了這次的崩潰問題。再提一句,不管在Windows上還是Mac上,編譯Release的時候最好把調試符號文件保存好。這樣利用breakpad來分析的時候才能事半功倍,breakpad方才能展現其強大的一面。

四、參考鏈接

1. https://www.jianshu.com/p/295ebf42b05b

2. https://github.com/google/breakpad

3. https://groups.google.com/forum/#!topic/google-breakpad-discuss/fierVnIAv1M

4. https://github.com/gyunaev/google-breakpad-qt


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM