你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 如何手動解析CrashLog

如何手動解析CrashLog

編輯:IOS開發基礎

vintage-grey-airplane-plane-large.jpg

解決崩潰問題是移動應用開發者最日常的工作之一。如果是開發過程中遇到的崩潰,可以根據重現步驟調試,但線上版本就無能為力了。好在目前已經有很多不錯的第三方CrashLog搜集平台(如友盟、Crashlytics等)為我們做好了解析工作,甚至在Xcode7裡蘋果也跟進了解析線上版本崩潰日志的功能,為開發者減輕了不少負擔。盡管通常已經不需要我們手工處理CrashLog,了解CrashLog的還原原理和方法還是有必要的。

一、.dSYM

.dSYM(debugging SYMbols)又稱為調試符號表,是蘋果為了方便調試和定位問題而使用的一種調試方案,本質上使用的是起源於貝爾實驗室的DWARF(Debugging With Attributed Record Formats),其在.xcarchive目錄中的層次結構為:

.xcarchive
--dSYMs
  |--Your.app.dSYM
    |--Contents
      |--Resources
        |--DWARF

關於DWARF的具體內容以後有機會再說。我們能解析CrashLog全靠.dSYM文件,解析方式見後文。

二、確定符號表和崩潰日志的一致性

有了符號表文件,有了崩潰日志文件,在解析之前一定要確保二者的對應關系,否則就算按照下述步驟解析出內容也肯定是不准確的。二者的對應關系可以通過UUID來確定。

1、從崩潰日志中獲取UUID

崩潰日志比較靠下的位置有個Binary Images模塊,其第一行內容如下:

Binary Images:
0xa2000 - 0x541fff Your armv7   /var/mobile/Containers/Bundle/Application/645D3184-4C20-4161-924B-BDE170FA64CC/Your.app/Your

從中可以看到關於你應用的若干信息:

  • 代碼段的起終地址為:0xa2000 – 0x541fff

  • 運行你應用的CPU指令集為:armv7

  • 應用的UUID為:a5c8d3cfda65396689e4370bf3a0ac64(不區分大小寫)

2、從符號表中獲取UUID

執行以下命令從符號表中提取UUID:

dwarfdump --uuid Your.app.dSYM

或者:

dwarfdump --uuid Your.app.dSYM/Contents/Resources/DWARF/Your

執行結果為:

UUID: A5C8D3CF-DA65-3966-89E4-370BF3A0AC64 (armv7) Your.app.dSYM/Contents/Resources/DWARF/Your

由此得到armv7指令集的UUID為:A5C8D3CF-DA65-3966-89E4-370BF3A0AC64(如果你的二進制文件支持多個指令集,這裡會列出每個指令集對應符號表的UUID),通過和崩潰日志中的對比發現二者一致,才可進行進一步的解析操作。

三、計算崩潰符號表地址

以下面的崩潰堆棧為例:

Thread 0:
0   libobjc.A.dylib                   0x33f10f60 0x33efe000 + 77664
1   Foundation                        0x273526ac 0x2734a000 + 34476
2   Foundation                        0x27355c3e 0x2734a000 + 48190
3   UIKit                             0x29ef9d1c 0x29bbc000 + 3398940
4   UIKit                             0x29ef9c9a 0x29bbc000 + 3398810
5   UIKit                             0x29ef954c 0x29bbc000 + 3396940
6   UIKit                             0x29c3a16a 0x29bbc000 + 516458
7   UIKit                             0x29e4b8e6 0x29bbc000 + 2685158
8   UIKit                             0x29c3a128 0x29bbc000 + 516392
9   Your                              0x000f0846 0xa2000 + 321606
10  UIKit                             0x29e90fb2 0x29bbc000 + 2969522
11  UIKit                             0x29e91076 0x29bbc000 + 2969718
12  UIKit                             0x29e867cc 0x29bbc000 + 2926540
13  UIKit                             0x29c9e8ea 0x29bbc000 + 927978
14  UIKit                             0x29bc8a6a 0x29bbc000 + 51818
15  QuartzCore                        0x295f0a08 0x295e4000 + 51720
16  QuartzCore                        0x295ec3e0 0x295e4000 + 33760
17  QuartzCore                        0x295ec268 0x295e4000 + 33384
18  QuartzCore                        0x295ebc4c 0x295e4000 + 31820
19  QuartzCore                        0x295eba50 0x295e4000 + 31312
20  QuartzCore                        0x295e5928 0x295e4000 + 6440
21  CoreFoundation                    0x266d0d92 0x26604000 + 839058
22  CoreFoundation                    0x266ce44e 0x26604000 + 828494
23  CoreFoundation                    0x266ce856 0x26604000 + 829526
24  CoreFoundation                    0x2661c3bc 0x26604000 + 99260
25  CoreFoundation                    0x2661c1ce 0x26604000 + 98766
26  GraphicsServices                  0x2da1a0a4 0x2da11000 + 37028
27  UIKit                             0x29c2a7ac 0x29bbc000 + 452524
28  Your                              0x0024643a 0xa2000 + 1721402
29  libdyld.dylib                     0x34484aac 0x34483000 + 6828

1、 符號表堆棧地址計算方式

要想利用符號表解析出崩潰對應位置,需要計算出符號表中對應的崩潰堆棧地址。而從上述堆棧中第9行可以看到,應用崩潰發生在運行時地址0x000f0846,該進程的運行時起始地址是0xa2000,崩潰處距離進程起始地址的偏移量為十進制的321606(對應十六進制為0x4E846)。三者對應關系:

0x000f0846 = 0xa2000 + 0x4E846

對應的公式為:

運行時堆棧地址 = 運行時起始地址 + 偏移量

崩潰堆棧中的起始地址和崩潰地址均為運行時地址,根據虛擬內存偏移量不變原理,只要提供了符號表TEXT段的起始地址,再加上偏移量(這裡為0x4E846)就能得到符號表中的堆棧地址,即:

符號表堆棧地址 = 符號表起始地址 + 偏移量

2、獲取符號表中的TEXT段起始地址

符號表中TEXT段的起始地址可以通過以下命令獲得:

$otool -l Your.app.dSYM/Contents/Resources/DWARF/Your

運行結果中的片段如下:

Load command 3
      cmd LC_SEGMENT
  cmdsize 736
  segname __TEXT
   vmaddr 0x00004000
   vmsize 0x00700000
  fileoff 0
 filesize 0
  maxprot 0x00000005
 initprot 0x00000005
   nsects 10
    flags 0x0

其中的vmaddr 0x00004000字段即為TEXT段的起始地址。

3、計算符號表地址

由公式:

符號表堆棧地址 = 符號表起始地址 + 偏移量

可得:

0x52846 = 0x4E846 + 0x4000

即符號表中的崩潰地址為0x52846,接下來就可以根據這個地址解析出崩潰位置了。

四、崩潰信息還原

有了符號表的崩潰地址,有以下幾種方式解析崩潰信息:

1、dwarfdump

命令如下:

$dwarfdump --arch armv7 Your.app.dSYM --lookup 0x52846 | grep 'Line table'

需要注意的是:

  • 這裡的armv7是運行設備的CPU指令集,而不是二進制文件的指令集

比如armv7指令集的二進制文件運行在arm64指令集的設備上,這個地方應該寫arm64。

  • —lookup後面跟的一定是經過准確計算的符號表中的崩潰地址

  • 使用dwarfdump解析的結果較雜亂,因此使用grep命令抓取其中關鍵點展示出來

運行結果如下:

Line table dir : '/data/.../Src/OBDConnectSetting/Controller'
Line table file: 'OBDFirstConnectViewController.m' line 882, column 5 with start address 0x000000000052768

其中第一行是編譯時文件目錄,第二行包含了崩潰發生的文件名稱以及文件中具體行號等信息,有了這些信息就能准確定位崩潰原因啦。

2、atos

atos是另一種更加簡潔的崩潰日志解析方法,使用方式如下:

 $atos -o LuBao -arch armv7 0x52846

其執行結果如下:

-[OBDFirstConnectViewController showOilPricePickerView] (in Your) (OBDFirstConnectViewController.m:882)

相對dwarfdump命令的解析結果,更加簡潔直觀的指出了崩潰發生的位置。

3、無需符號表崩潰地址的解析方式

實際上,atos還提供了另外一種無需計算崩潰地址對應的符號表地址的方式,命令格式如下:

$atos -o Your.app.dSYM/Contents/Resources/DWARF/Your -arch armv7 -l 0xa2000 0x000f0846

其中-l選項指定了二進制文件在運行時的起始地址0xa2000(獲取方式見Binary Images相關內容),後面跟的是崩潰發生的運行時地址0x000f0846,解析結果和使用計算得到的符號表中崩潰地址一致:

-[OBDFirstConnectViewController showOilPricePickerView] (in Your) (OBDFirstConnectViewController.m:882)

五、參考文檔

  • How to Match a Crash Report to a Build

  • CrashReporter

  • Understanding and Analyzing iOS Application Crash Reports

  • atos and dwarfdump won’t symbolicate my address

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