1. 程式人生 > >iOS崩潰堆疊符號化,定位問題分分鐘搞定!

iOS崩潰堆疊符號化,定位問題分分鐘搞定!

轉載自:  http://bugly.qq.com/blog/?p=119

最近一段時間,在跟開發者溝通過程中,蘿莉發覺大家對iOS的應用符號表還不是很清楚,除了諮詢關於符號表生成、配置的問題以外,對Bugly崩潰分析需要配置符號表也存在疑問。

在這裡,蘿莉就給大家分享下關於iOS符號表的一些內容。

首先,進行常識“腦補”。

1. 符號表是什麼?

符號表就是指在Xcode專案編譯後,在編譯生成的二進位制檔案.app的同級目錄下生成的同名的.dSYM檔案。

.dSYM檔案其實是一個目錄,在子目錄中包含了一個16進位制的儲存函式地址對映資訊的中轉檔案,所有Debugsymbols都在這個檔案中(包括檔名、函式名、行號等),所以也稱之為除錯符號資訊檔案。

一般地,Xcode專案每次編譯後,都會生成一個新的.dSYM檔案。因此,App的每一個釋出版本,都需要備份一個對應的.dSYM檔案,以便後續除錯定位問題。

注意:
專案每一次編譯後,.app.dSYM成對出現,並且二者有相同的UUID值,以標識是同一次編譯的產物。
UUID值可以使用dwarfdump —uuid來檢查:

 $ dwarfdump --uuid XX.app.dSYM
 $ dwarfdump --uuid XX.app/XX

那麼,問題就來了!

2. 符號表有什麼用?

在Xcode開發除錯App時,一旦遇到崩潰問題,開發者可以直接使用Xcode的偵錯程式定位分析。

但如果App釋出上線,開發者不可能進行除錯,只能通過分析系統記錄的崩潰日誌來定位問題,在這份崩潰日誌檔案中,會指出App出錯的函式記憶體地址,而這些函式地址是可以在.dSYM檔案中找到具體的檔名、函式名和行號資訊的,這正是符號表的重要作用所在。

實際上,使用Xcode的Organizer檢視崩潰日誌時,也自動根據本地儲存的.dSYM檔案進行了符號化的操作。
並且,崩潰日誌也有UUID資訊,這個UUID和對應的.dSYM檔案是一致的,即只有當三者的UUID一致時,才可以正確的把函式地址符號化。

3. 符號表怎麼生成?

一般地,Xcode專案預設的配置是會在編譯後生成.dSYM,開發者無需額外修改配置。

專案的Build Settings的相關配置如下:

    Generate Debug Symbols = Yes
    Debug Information Format = DWARF with dSYM File

採用不同的編譯打包方式,產生的.dSYM檔案的路徑也不相同。

下面是幾種常用的編譯打包方式:

1、使用xcodebuild編譯打包

Xcode中編譯專案後,會在工程目錄下的build/ConfigurationName-iphoneos目錄下生成.app.app.dSYM檔案。

如果使用xcodebuild命令進行編譯打包,則可以指定編譯結果的儲存路徑,同樣會有.app.app.dSYM生成。

一般地,我們推薦打包釋出時,使用xcodebuild編譯打包,方便.app.app.dSYM的匹配儲存,避免.app.dSYM檔案丟失的情況。

2、使用Xcode的Archive匯出

如果開發者使用XcodeArchive匯出功能打包,可以切換到OrganizerProjects檢視,檢視對應專案的Derived Data路徑,在其中可以找到當前匯出過程產生的.app.app.dSYM檔案

3、使用make編譯打包

如果開發團隊不使用Xcode編譯打包,而是使用make編譯生成.o檔案,然後打包釋出。此時,編譯過程不會有.dSYM檔案生成。開發者可以使用dsymutil工具從.o檔案中提取符號資訊。

4. 符號表怎麼用?

在前面的內容可以知道,符號表的作用是把崩潰中的函式地址解析為函式名等資訊。

如果開發者能夠獲取到崩潰的函式地址資訊,就可以利用符號表分析出具體的出錯位置。

Xcode提供了幾個工具來幫助開發者執行函式地址符號化的操作。

例如,崩潰問題的函式地址堆疊如下:

錯誤地址堆疊

    3  CoreFoundation           0x254b5949 0x253aa000 + 1096008
    4  CoreFoundation           0x253e6b68 _CF_forwarding_prep_0 + 24
    5  SuperSDKTest             0x0010143b 0x000ef000 + 74808

符號化堆疊

    3   CoreFoundation          0x254b5949 <redacted> + 712
    4   CoreFoundation          0x253e6b68 _CF_forwarding_prep_0 + 24
    5   SuperSDKTest            0x0010143b -[ViewController didTriggerClick:] + 58

說明:

大部分情況下,開發者能獲取到的都是錯誤地址堆疊,需要利用符號表進一步符號化才能分析定位問題。

部分情況下,開發者也可以利用backtrace看到符號化堆疊,可以大概定位出錯的函式、但卻不知道具體的位置。通過利用符號表資訊,也是可以進一步得到具體的出錯位置的。

目前,許多崩潰監控服務都顯示backtrace符號化堆疊,增加了可讀性,但分析定位問題時,仍然要進一步符號化處理。

崩潰資訊的UUID

0xef000 - 0x17efff SuperSDKTest armv7  <38d66f9734ca3843a2bf628bb9015a8b> /var/mobile/.../SuperSDKTest.app/SuperSDKTest

下面,利用兩個工具來進行一下符號化的嘗試:

1、symbolicatecrash

symbolicatecrash是一個將堆疊地址符號化的指令碼,輸入引數是蘋果官方格式的崩潰日誌及本地的.dSYM檔案,執行方式如下:

$ symbolicatecrash XX.crash [XX.app.dSYM] > xx.sym.crash# 如果輸入.dSYM引數,將只解析系統庫對應的符號

使用symbolicatecrash工具的限制就在於只能分析官方格式的崩潰日誌,需要從具體的裝置中匯出,獲取和操作都不是很方便,而且,符號化的結果也是沒有具體的行號資訊的,也經常會出現符號化失敗的情況。
實際上XcodeOrganizer內建了symbolicatecrash工具,所以開發者才可以直接看到符號化的錯誤日誌。

2、atos

更普遍的情況是,開發者能獲取到錯誤堆疊資訊,而使用atos工具就是把地址對應的具體符號資訊找到。

atos實際是一個可以把地址轉換為函式名(包括行號)的工具,它的執行方式如下:

$ xcrun atos -o executable -arch architecture -l loadAddress
  address ...

說明:

loadAddress 表示函式的動態載入地址,對應崩潰地址堆疊中 + 號前面的地址,即0x000ef000

address 表示執行時地址、對應崩潰地址堆疊中第一個地址,即0x0010143b

實際上,崩潰地址堆疊中+號前後的地址相加即是執行時地址,即0x000ef000 + 74808 = 0x0010143b

執行命令查詢地址的符號,可以看到如下結果:

$ xcrun atos -o SuperSDKTest.app.dSYM/Contents/Resources/DWARF/SuperSDKTest -arch armv7 -l 0x000ef000
0x0010143b
-[ViewController didTriggerClick:] (in SuperSDKTest) (ViewController.m:35)

開發者在具體的運用中,是可以通過編寫一個指令碼來實現符號化錯誤地址堆疊的。

5. 結語

在實際的專案開發中,崩潰問題的分析定位都不是採用這種方式,因為它依賴於系統記錄的崩潰日誌或錯誤堆疊,在本地開發除錯階段,是沒有問題的。

如果在釋出的線上版本出現崩潰問題,開發者是無法即時準確的取得錯誤堆疊。一般地,開發者都是接入第三方的崩潰監控服務(如騰訊Bugly),實現線上版本崩潰問題的記錄和跟蹤。

目前,國內外提供崩潰監控服務的產品有好幾個,在崩潰問題的統計上可能不分伯仲。但提供自動符號化功能的產品卻基本沒有,大部分崩潰問題的堆疊只是簡單符號化以增強可讀性,沒有可以快速定位問題的行號資訊。

騰訊Bugly提供了地址堆疊符號化功能的崩潰監控服務,只要開發者配置了對應的符號表資訊,Bugly服務會自動對錯誤地址堆疊進行符號化,出錯位置清晰可見,分分鐘定位和解決崩潰問題。