iOS Crash日誌分析必備:符號化系統庫方法

若是你有過度析iOS崩潰日誌的經驗,必定常常看到日誌裏出現不少<redacted>的字段。這篇文章就是幫助開發者將這些字段符號化爲對應的系統庫方法名。ios

若是你已經掌握了這方面的知識,就直接去這裏iOS-System-Symbols,下載我整理好的系統庫符號文件吧。git

符號化的做用

當獲取到app的crash日誌時,第一步就是將其符號化。做用是把日誌堆棧中的方法調用顯示出來,對於來自app內部的方法,還能直接給出方法對應.m文件的所在行。github

符號化前(這裏項目的Build Settings裏的Strip Style設爲了Debugging Symbols,因此這裏能直接看到MyApp的方法名。更多和symbol相關的設置,請看這裏):xcode

Thread 7:
0   libsystem_kernel.dylib          0x000000018efb416c 0x18efb3000 + 4460 (mach_msg_trap + 8)
1   libsystem_kernel.dylib          0x000000018efb3fdc 0x18efb3000 + 4060 (mach_msg + 72)
2   MyApp                           0x000000010091e558 0x1000bc000 + 8791384 (ksmachexc_i_handleExceptions + 148)
3   libsystem_pthread.dylib         0x000000018f097860 0x18f094000 + 14432 (<redacted> + 240)
4   libsystem_pthread.dylib         0x000000018f097770 0x18f094000 + 14192 (_pthread_start + 284)
複製代碼

符號化後:bash

Thread 7:
0   libsystem_kernel.dylib          0x000000018efb416c mach_msg_trap + 8
1   libsystem_kernel.dylib          0x000000018efb3fdc mach_msg + 72
2   MyApp                           0x000000010091e558 ksmachexc_i_handleExceptions (KSCrashSentry_MachException.c:233)
3   libsystem_pthread.dylib         0x000000018f097860 _pthread_body + 240
4   libsystem_pthread.dylib         0x000000018f097770 _pthread_body + 0
複製代碼

能夠發現,frame 3裏libsystem_pthread.dylib<redacted>變成了_pthread_body,frame 2裏MyAppksmachexc_i_handleExceptions變成了更爲完整的ksmachexc_i_handleExceptions (KSCrashSentry_MachException.c:233),直接給出了方法及其所在文件和行數。架構

詳細的符號化方法,請參考符號化iOS Crash文件的3種方法。這裏就不重複了。app

須要注意的是,不少時候,crash日誌裏並不會有MyApp的調用,而全都是系統庫的調用:iphone

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x000000018b816f30 0x18b7fc000 + 110384 (objc_msgSend + 16)
1   UIKit                           0x0000000192e0a79c 0x192c05000 + 2119580 (<redacted> + 72)
2   UIKit                           0x0000000192c4db48 0x192c05000 + 297800 (<redacted> + 312)
3   UIKit                           0x0000000192c4d988 0x192c05000 + 297352 (<redacted> + 160)
4   QuartzCore                      0x00000001900d6404 0x18ffc5000 + 1119236 (<redacted> + 260)
5   libdispatch.dylib               0x000000018bc551c0 0x18bc54000 + 4544 (<redacted> + 16)
6   libdispatch.dylib               0x000000018bc59d6c 0x18bc54000 + 23916 (_dispatch_main_queue_callback_4CF + 1000)
7   CoreFoundation                  0x000000018cd79f2c 0x18cc9d000 + 905004 (<redacted> + 12)
8   CoreFoundation                  0x000000018cd77b18 0x18cc9d000 + 895768 (<redacted> + 1660)
9   CoreFoundation                  0x000000018cca6048 0x18cc9d000 + 36936 (CFRunLoopRunSpecific + 444)
10  GraphicsServices                0x000000018e729198 0x18e71d000 + 49560 (GSEventRunModal + 180)
11  UIKit                           0x0000000192c80628 0x192c05000 + 505384 (<redacted> + 684)
12  UIKit                           0x0000000192c7b360 0x192c05000 + 484192 (UIApplicationMain + 208)
13  MyApp                           0x0000000100016e54 0x100004000 + 77396 (_mh_execute_header + 77396)
14  libdyld.dylib                   0x000000018bc885b8 0x18bc84000 + 17848 (<redacted> + 4)
複製代碼

這時候就必須符號化系統庫了。符號化後的日誌:工具

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x000000018b816f30 objc_msgSend + 16
1   UIKit                           0x0000000192e0a79c -[UISearchDisplayController _sendDelegateDidBeginDidEndSearch] + 72
2   UIKit                           0x0000000192c4db48 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 312
3   UIKit                           0x0000000192c4d988 -[UIViewAnimationState animationDidStop:finished:] + 160
4   QuartzCore                      0x00000001900d6404 CA::Layer::run_animation_callbacks(void*) + 260
5   libdispatch.dylib               0x000000018bc551c0 _dispatch_client_callout + 16
6   libdispatch.dylib               0x000000018bc59d6c _dispatch_main_queue_callback_4CF + 1000
7   CoreFoundation                  0x000000018cd79f2c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
8   CoreFoundation                  0x000000018cd77b18 __CFRunLoopRun + 1660
9   CoreFoundation                  0x000000018cca6048 CFRunLoopRunSpecific + 444
10  GraphicsServices                0x000000018e729198 GSEventRunModal + 180
11  UIKit                           0x0000000192c80628 -[UIApplication _run] + 684
12  UIKit                           0x0000000192c7b360 UIApplicationMain + 208
13  MyApp                           0x0000000100016e54 main (main.m:15)
14  libdyld.dylib                   0x000000018bc885b8 start + 4
複製代碼

能夠看出是UISearchControllerdelegate致使的問題,檢查一下就發現UISearchDisplayControllerdelegateassign的,是因爲點擊搜索條的同時pop了界面致使的crash。oop

從這裏能夠發現,符號化系統庫是頗有必要的。

##如何符號化系統庫

符號化本身app的方法名,須要編譯ipa時生成的dySYM文件。而要將系統庫的<redacted>符號化爲完整的方法名,也須要系統庫的符號文件。

1. 匹配對應的符號文件版本

系統庫符號文件不是通用的,而是對應crash所在設備的系統版本和CPU型號的。

crash日誌中有這樣兩個信息:

Code Type:       ARM-64
OS Version:      iOS 10.2 (14C82)
複製代碼

Code Type表示此設備的CPU爲armv7armv7s仍是arm64

OS Version表示此設備的系統版本號,括號中的字符串表明了此係統的build號。能夠在這裏查找build號:iOS SDKiOS version history

2. 將對應版本的符號文件放到指定目錄

這時候,把獲取到的對應版本的符號文件放到Mac的~/Library/Developer/Xcode/iOS DeviceSupport目錄下,再使用符號化iOS Crash文件的3種方法裏提到的Xcode自帶的符號化工具symbolicatecrash進行符號化。這個工具會自動搜索系統庫符號文件。

獲取系統符號文件的4個方法

從真機上獲取

大部分系統庫符號文件只能從真機上獲取,蘋果也沒有提供下載。 當你用Xcode第一次鏈接某臺設備進行真機調試時,會看到Xcode顯示Processing symbol files,這時候就是在拷貝真機上的符號文件到Mac系統的/Users/xxx/Library/Developer/Xcode/iOS DeviceSupport目錄下。

目錄下的10.2(14C82)這樣的文件夾就是對應的符號文件,一般都有1-3GB的大小,很佔用空間,動不動就累積成三、40GB。不少講清理Mac垃圾文件的教程都會說要刪除這個目錄下的文件,真是坑爹。正確作法是作成壓縮包保存到外部硬盤裏,須要符號化的時候再從新解壓到此目錄。

尋找蘋果官方的下載地址

以前watch的調試出現bug時,有人找出過幾個watch的符號文件下載地址。見No symbols for paired Apple Watch。 可是我嘗試按照對應的命名格式,並無找到iOS符號文件的下載地址。

從已解密的固件中提取符號文件

某些已經被破解的固件能夠直接提取系統文件,可是未破解的固件(較新的固件和arm64的固件),沒法用這種方式獲取。

固件解密步驟:

1.下載對應版本的.ipsw固件,直接解壓,解壓后里面有幾個.dmg格式的鏡像文件,最大的.dmg文件就是系統鏡像。
2.從Firmware_Keys找到對應固件的解密key(頁面上Root Filesystem字段的key)。
3.用一個dmg工具進行解密,下載地址。使用方式:cd到解壓後的ipsw文件夾,執行./dmg extract xxx-xxxx-xxx.dmg dec.dmg -k <key>extract後面跟兩個參數,分別是系統鏡像dmg的名字和解密後的文件名,-k 後面填寫第2步獲取到的key,若是key不對,解密會失敗。
4.等待。最終會生成一個dec.dmg文件,雙擊打開便可加載系統鏡像。

提取符號文件方法: 參考聊聊從iOS固件提取系統庫符號中的2、系統庫符號提取部分。

update:目前大多數固件都能解密了,並且iOS 10以後蘋果再也不進行加密,所以以後均可以用這個方式獲取符號文件。

下載舊版本Xcode,提取SDK

舊版本的Xcode裏包含了對應的iPhoneSDK,能夠從中得到符號文件。 路徑是/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/。裏面的System/Library裏就能夠看到framework,並且同時包含了armv7,armv7s,arm643個平臺的版本。

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/version.plist能夠查看是哪一個版本。把iPhoneOS.sdk文件夾的名字改爲對應的CFBundleVersion (ProductBuildVersion)格式,而後在裏面加一層Symbols子文件夾,把System,Library,usr都放進Symbols裏,就能夠和其餘符號文件同樣使用了。

可是當iOS版本只包含了bug修復,而沒有改變API,Xcode就不會有附帶對應的SDK,仍是須要從真機上獲取。並且從Xcode7開始,蘋果用tbd文件代替了真機符號文件,因此這個方法也失效了。 參考:Xcode software image for user iOS in order to symbolicate iOS calls, Missing iOS symbols at 「~/Library/Developer/Xcode/iOS DeviceSupport」

獲取符號文件的難題

這個時候,遊戲就開始了:

  • 不少時候crash日誌只給出了系統的調用棧,不能直接定位到本身app的代碼,所以須要符號化系統庫。
  • 用戶的crash來自各類系統版本,須要對應版本的系統符號文件才能符號化。
  • 系統庫符號文件只能從真機上獲取,蘋果沒有提供下載。
  • iOS 7.0(11A465)iOS 10.2(14C92)一共有50個build版本,公司的測試機是不會覆蓋到這麼變態的完整度的。
  • 同一個版本,有時候會給iPhone和iPad、甚至6和6s提供不一樣build的固件。
  • 某些版本是某些機子的特供版,例如10.0.3(14A551)是iPhone 7和 7 Plus獨有的,這就更加大了收集難度。
  • 同一個iOS版本可能有多個build,例如10.1(14B72)10.1(14B72c),蘋果以爲更新幅度過小,就沒有提高版本號。
  • 除了build號的區別,符號文件在不一樣CPU平臺上也有區別,意味着來自4s(armv7)和6s(arm64)的符號文件,即使build號是同樣的,也沒法通用。因此50個build號又要翻倍,達到了88個,因此精確來講我只是收集了(63/88)的進度。幸運的是,arm64機型的系統庫裏附帶了armv7s

規則好厲害的收集遊戲啊。收集品其實還有稀有度的區別,其中最厲害的應該是10.0,這是iPhone 7和7 Plus獨有的出廠系統,並且沒有固件能夠下載,所以即使有iPhone 7也不能經過刷機來獲得10.0

其實我一直很奇怪爲何不多見到開發者抱怨找不到系統符號文件,從而召集你們進行收集並分享,猜想可能的緣由是:

  • 懶。遇到沒法符號化的問題,沒有去解決。
  • 有些公司可能很早就開始對crash日誌自動符號化了,所以很早就開始收集符號文件。只要一直跟着蘋果的每個版本升級,收集起來仍是挺簡單的。而這些資源,開發者並不會注意到能夠共享出來。
  • crash收集和符號化使用的是第三方服務,第三方平臺會幫助符號化系統庫。

可是我找了一下,沒有找到一家明確聲明瞭可以符號化全部系統庫的第三方平臺。從騰訊的Bugly論壇裏也能發現,有些系統方法並無符號化出來,系統庫是缺失的。(update:找到了一個國外的平臺,在stack overflow上說能符號化全部版本的系統庫,可是是收費服務,我也沒有測試)

在公司小組裏,大部分時候都是我來分析crash日誌,因此當遇到缺乏系統符號文件的狀況,就會十分無奈。不少時候,沒有符號化的crash日誌根本沒法提供有用信息。

系統符號文件下載地址

暴力收集

收集不全一直讓我很不爽。以前搜刮了組內的測試機,只收集到了有限的幾個(感謝無私提供iPhone 7讓我刷機降級的同事)。終於,這週末特地跑去了一趟二手機市場尋找舊版本的設備來拷貝,總算是收集得完整了一點,可是也花了我121塊錢。

心情總算愉悅了。

其中大部分都是拷貝自arm64設備的,armv7的符號文件收集我是放棄了。有哪位大俠有興趣把這個遊戲玩通關的嗎?還有 tvOS 和 watchOS的符號,我也放棄了。 (update:又花了些時間從Xcode的SDK和固件裏提取了armv7sarmv7的固件,如今只剩下幾個arm64的版本了)。

整理了一下傳到了網盤,地址見下方,有須要的去下載吧。

目前還缺乏的符號文件

經過各類方式,目前已經收集得差很少了,只剩下最後一個10.0(14A346)版本沒有獲得。若是哪位小夥伴有這個版本,能夠分享一下。

分享能夠直接貼下載地址,也能夠提交到這個github項目iOS-System-Symbols。若是我獲得了新的符號文件,也會在這個項目裏更新。

缺失符號的版本 缺失的CPU版本 描述
10.0(14A346) arm64 iPhone 7 和 7 Plus獨佔,出廠自帶系統

網盤下載地址

下載地址請見這個項目:iOS-System-Symbols。若是我獲得了新的符號文件,會在這個項目裏更新。

我把裏面的那幾個dyld_shared_cache_xxxx大文件單獨拿出來了,目的是減少壓縮包大小。若是隻是符號化的話,用不到這幾個文件,只是在真機調試的時候才須要。

符號文件版本列表

這些是我已經收集到的符號文件,包括了對應的CPU信息。iOS10系統開始不支持armv7的機器。可是iOS9如下仍是支持armv7的。

查看是否帶有對應CPU架構的符號文件的方式:到10.2 (14C92)/Symbols/System/Library/Caches/com.apple.dyld這樣的目錄下,會有對應的dyld_shared_cache_arm64dyld_shared_cache_armv7sdyld_shared_cache_armv7文件,若是缺失了,就說明對應的CPU架構符號文件還不存在。(通過試驗,這幾個大文件並不影響符號化,只是在真機調試的時候纔有用,所以若是嫌太佔用空間,能夠刪去)。

版本 已收集到的CPU版本 描述
11.2.6 (15D100) arm64
11.2.5 (15D60) arm64
11.2.2 (15C202) arm64
11.2.1 (15C153) arm64
11.2 (15C114) arm64
11.2 (15C113) none 蘋果在發佈了15C114以後,又發佈了一個低版本的15C113,以後又移除了15C113的下載地址,所以這個固件目前沒法下載。應該只是誤發佈,能夠忽略這個版本
11.1.2 (15B202) arm64
11.1.1 (15B150) arm64
11.1 (15B101) arm64 iPad Pro2 12.9-inch and iPad Pro 10.5-inch only
11.1 (15B93) arm64
11.0.3 (15A432) arm64
11.0.2 (15A421) arm64
11.0.1 (15A403) arm64 iPhone 8 and 8 Plus only
11.0.1 (15A402) arm64
11.0 (15A372) arm64
10.3.3 (14G60) arm64,armv7s
10.3.2 (14F91) arm64,armv7s iPad mini4(Cellular) only
10.3.2 (14F90) arm64,armv7s iPad (5th gen) only
10.3.2 (14F89) arm64,armv7s
10.3.1 (14E304) arm64,armv7s
10.3 (14E277) arm64,armv7s
10.2.1 (14D27) arm64,armv7s
10.2 (14C92) arm64,armv7s
10.1.1 (14B150) arm64,armv7s
10.1.1 (14B100) arm64,armv7s
10.1 (14B72c) arm64,armv7s
10.1 (14B72) arm64,armv7s
10.0.3 (14A551) arm64,armv7s
10.0.2 (14A456) arm64,armv7s
10.0.1 (14A403) arm64,armv7s
10.0(14A346) none iPhone 7 和 7 Plus獨佔,出廠自帶系統
9.3.5 (13G36) arm64,armv7s,armv7
9.3.4 (13G35) arm64,armv7s,armv7
9.3.3 (13G34) arm64,armv7s,armv7
9.3.2(13F72) arm64,armv7s iPad Pro 9.7寸獨佔,修復了變磚的問題
9.3.2 (13F69) arm64,armv7s,armv7
9.3.1 (13E238) arm64,armv7s,armv7
9.3(13E237) armv7s,armv7 5s和更舊機型獨佔,修復了不能激活的問題
9.3(13E236) armv7 iPad2獨佔,修復了不能激活的問題
9.3(13E234) arm64,armv7s 6s, 6s Plus and iPad Pro 9.7寸獨佔
9.3 (13E233) arm64,armv7s,armv7
9.2.1 (13D20) arm64,armv7s iPhone 6 和更新的機型獨佔
9.2.1 (13D15) arm64,armv7s,armv7
9.2 (13C75) arm64,armv7s,armv7
9.1 (13B143) arm64,armv7s,armv7
9.0.2(13A452) arm64,armv7s,armv7
9.0.1(13A404) arm64,armv7s,armv7
9.0 (13A344) arm64,armv7s,armv7
8.4.1 (12H321) arm64,armv7s,armv7
8.4 (12H143) arm64,armv7s,armv7
8.3 (12F70) arm64,armv7s,armv7 iPhone獨佔
8.3 (12F69) arm64,armv7s,armv7 iPad獨佔
8.2 (12D508) arm64,armv7s,armv7
8.1.3 (12B466) arm64,armv7s,armv7
8.1.2 (12B440) arm64,armv7s,armv7
8.1.1 (12B436) arm64,armv7s iPhone 6 和更新的機型獨佔
8.1.1 (12B435) armv7s,armv7 5s和更舊機型獨佔
8.1 (12B411) arm64,armv7s,armv7 iPhone獨佔
8.1 (12B410) arm64,armv7s,armv7 iPad獨佔
8.0.2 (12A405) arm64,armv7s,armv7
8.0.1(12A402) armv7s,armv7 8.0.1有致使變磚的bug,發佈後很快就中止推送了
8.0 (12A366) arm64,armv7s 6 Plus獨佔
8.0 (12A365) arm64,armv7s,armv7
7.1.2 (11D257) armv7s,armv7
7.1.1 (11D201) arm64,armv7s,armv7
7.1 (11D167) arm64,armv7s,armv7
7.0.6 (11B651) arm64,armv7s,armv7
7.0.4 (11B554a) arm64,armv7s,armv7
7.0.3 (11B511) arm64,armv7s,armv7
7.0.2(11A501) armv7s,armv7
7.0.1(11A470a) armv7s 5s 和 5c 獨佔
7.0(11A465) arm64,armv7s,armv7

機型對應CPU架構

CPU 機型
armv6 iPhone, iPhone2, iPhone3G, iPod Touch 1 and 2
armv7 iPhone3GS, iPhone4, iPhone4S,iPad, iPad2, iPad3(The New iPad), iPad mini,iPod Touch 3G, iPod Touch4, iPod Touch5
armv7s iPhone5, iPhone5C, iPad4(iPad with Retina Display)
arm64 iPhone5S, iPad Air, iPad mini2(iPad mini with Retina Display), iPhone6, iPhone6s, iPhone7, iPhone7s and any new device in the future

結束語

最後再次呼籲一下,若是誰有上面缺失的符號文件,就請共享一下吧。雖然只是作一點微小的工做,可是可以有很大幫助。

不以爲填滿上面那個列表會很爽嗎?

update:如今基本上已經收集完了。

額外提示

其實這些符號文件就是真機上的系統庫,包括了完整的系統庫二進制文件。有時候要反編譯某些系統framework,可是模擬器SDK裏沒有對應的framework(好比只有真機上纔有的CoreMotion.framework),就能夠在這些真機上的系統庫裏找到了。

參考

相關文章
相關標籤/搜索