你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> Crash log符號化與調試信息

Crash log符號化與調試信息

編輯:IOS開發基礎

這篇文章主要整理了crash log的符號化解析和調試信息與配置相關的一些內容。

對於做移動App開發的來說,質量和體驗都是很重要的。一個客戶端應用如果經常“閃退”,是產品質量很差的一個體現,用戶體驗就更不用提了。所以開發一個優秀的App,首先是保證自身的技術質量,盡量杜絕“閃退”,也就是“Crash”。但客戶端上線後,偶爾出現一個隱藏很深的bug也在所難免。我們所能做的就是盡可能的收集問題相關的信息,爭取在將來的新版本中解決和改進。

0. Crash

一個App啟動之後,用著用著就突然被iOS系統關閉,或者干脆就起不來,在打開的一瞬間關閉,這就是Crash,俗稱“閃退”“崩潰”。

iOS上的App閃退有各種各樣的原因,手機過熱、響應超時、內存過低都是有可能的crash原因。但更多情況下是App程序自身的運行邏輯存在問題、缺陷。比如調用用了Objective-C對象根本不支持的方法(發送消息),非法內存訪問,數組越界,參數不符合要求等。

這些問題在調試階段,我們都可以很容易的通過斷點和console中提供的信息快速定位並解決。

但對於已發布的App,如果想重現並利用上述辦法來解決,恐怕會比較費時費事。

最有幫助最直接的辦法就是根據出現問題時的閃退日志,分析和判斷crash的原因,快速准確的定位和解決。

1. Crash log

在iOS上運行的App出現crash的時候,通常會生成一個crash log,記載問題發生時的具體狀況。開發者可以在iTunes Connect(相當於App Store後台)中特定App下找到收集上來的crash log。不過客戶端用戶可以選擇不發送診斷信息,這樣收集上來的信息就不一定是全面的。

不過開發者可以對exception和signal設置自定義的handler做額外處理,以收集現場信息。現在也有很多第三方的工具很流行,比如Crashlytics,國內的友盟等。

閃退日志裡面包含了Crash發生的App、運行軟硬件環境、發生時間、錯誤類型、方法調用異常棧、各線程狀態、寄存器和內存信息。

而其中對我們開發人員來說意義最為重大的,可能就是異常線程的調用棧,例如:

Last Exception Backtrace:
0   CoreFoundation                  0x18517e950 __exceptionPreprocess + 132
1   libobjc.A.dylib                 0x1916841fc objc_exception_throw + 60
2   CoreFoundation                  0x185085910 -[__NSDictionaryM setObject:forKey:] + 900
3   CrashDebugInfoTest              0x1000c2b90 0x1000bc000 + 27536
4   CrashDebugInfoTest              0x1000c28dc 0x1000bc000 + 26844
5   UIKit                           0x1881bc55c -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 316
6   UIKit                           0x1881bbf08 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1564
7   UIKit                           0x1881b59ec -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 772
8   UIKit                           0x1881498cc -[UIApplication handleEvent:withNewEvent:] + 3316
9   UIKit                           0x188148ad0 -[UIApplication sendEvent:] + 104
10  UIKit                           0x1881b5044 _UIApplicationHandleEvent + 672
11  GraphicsServices                0x18ad63504 _PurpleEventCallback + 676
12  GraphicsServices                0x18ad63030 PurpleEventCallback + 48
13  CoreFoundation                  0x18513e890 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56
14  CoreFoundation                  0x18513e7f0 __CFRunLoopDoSource1 + 444
15  CoreFoundation                  0x18513ca14 __CFRunLoopRun + 1620
16  CoreFoundation                  0x18507d6d0 CFRunLoopRunSpecific + 452
17  UIKit                           0x1881b41c8 -[UIApplication _run] + 784
18  UIKit                           0x1881aefdc UIApplicationMain + 1156
19  CrashDebugInfoTest              0x1000c2c5c 0x1000bc000 + 27740
20  libdyld.dylib                   0x191c77aa0 start + 4

其中從第二列來看,很多是開發庫中的調用,而關鍵在於其間我們自己的App方法調用。可惜有些時候,這關鍵的信息竟然全是16進制的數據,我們很難看懂。比如:

3 CrashDebugInfoTest 0x1000c2b90 0x1000bc000 + 27536

那麼要從十六進制的地址碼,得到我們代碼中對應的方法調用,就需要結合調試信息對crash log進行符號化。

2. 符號化的各種方法

符號化的方法多種多樣,從網上社區論壇和個人經驗看來,至少有如下辦法:

  • 使用開發工具庫中自帶的symbolicatecrash

  • 使用atos

  • 使用dwarfdump

更有牛人,自己寫了個復雜的腳本來解決這個問題。下面我介紹我常使用的兩種方法,一個是利用atos,一個是充分利用Xcode自帶的工具。其它的大家都可以到網上參看相關文章,一搜一大筐。

atos,就是address to symbol,把地址翻譯成符號。上面那段我提到了,要想把十六進制的地址翻譯為符號,需要調試信息。最好用的調試信息就是我們在每次給App打包時生成的dSYM文件。而atos最好用的方式就是:

atos -o XXX.app.dSYM/Contents/Resources/DWARF/XXX -l address0 targetAddress

其中:

  • XXX是AppName

  • address0是當前進程在內存中加載的起始地址,至於為什麼需要這個,那就有必要去了解下ASLR

  • targetAddress就是你想要符號化的地址了,比如0x1000c2b90

除了atos外,我想介紹的另一個辦法就是使用Xcode自帶的crash log分析工具,在老版本的Xcode中是在Organizer裡,在新版本裡是在Devices中。

有的朋友可能會說,那裡面顯示的可還是十六進制的地址啊!那是因為它“沒看到”App和dSYM文件啊。那怎麼辦?簡單:

把App和dSYM放在一個目錄中,並用mdimport把目錄加入到Spotlight的索引中即可。

怎麼樣,這招是不是更快更好用?symbolicatecrash神馬的就不需要了吧!

3. 針對framework靜態庫的crash定位和調試選項設置

之前本人曾經以framework(iOS Universal Framework)的方式開發了好多SDK供別人用。可當使用了framework庫的App閃退了的時候,即使是SDK中的邏輯問題,異常棧中顯示的也是App的名字。

更重要的是,默認情況下,異常棧的最右一列根本沒法符號化。

這是因為framework實際上是一種靜態庫,在Build App時,它已經完全“融入”了,靜態鏈接到App產物中。而在framework生成的時候,調試信息已經被抽取掉了。

我們打開SDK的工程文件,在Build Settings裡搜索Strip,會發現有好幾個選項:

  • Strip Debug Symbol During Copy

  • Strip Linked Product

  • Strip Style

  • Use Separate Strip

對於這個問題,我們只要在Strip Linked Product一項中選擇No就行了。這樣在Build出的SDK framework中,包的體積會變大,因為它容納了本要去除掉的調試信息。

按我在之前的Blog的辦法,我們看看在Mach-O文件中多了什麼:

debugSym.jpg

Debug Info

是的,正是DWARF格式的數據。DWARF是一種通用的調試信息格式,可以認為是Debugging With Attributed Records Format的縮寫。感興趣的可以前往: http://www.dwarfstd.org

這樣,關於Crash問題的解決方案和原理我就解釋清楚了,歡迎大家拍磚!

(本文作者:三石)

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved