本文介紹了如何解析 iOS 的 crash 堆棧,分別使用了 symbolicatecrash
來自動解析整個堆棧,以及使用 atos
來解析單個地址的符號。在 iOS 開發中,解決 crash 問題是比較常見的工作。其中能夠解析出符號當然是定位問題的開始。實際工作中,也有看到很多人其實會卡在解析符號這裡,遇到這種情況,可以按照本文中的做法解決。
symbolicatecrash
是 Xcode 自帶的 crash 符號解析工具,可以自動搜索本地符號表,解析整個 crash 堆棧。
首先,需要確認 Xcode 的環境,執行以下代碼,獲取當前 Xcode 的目錄。
/usr/bin/xcode-select -print-path
結果應該是:
/Applications/Xcode.app/Contents/Developer/
如果結果不是上述的路徑,則指定一下路徑:
sudo /usr/bin/xcode-select -switch /Applications/Xcode.app/Contents/Developer/
需要先找到 symbolicatecrash 所在的路徑,以 Xcode 7.3
版本為例,執行:
find /Applications/Xcode.app -name symbolicatecrash -type f
將會返回:
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash
可以做一個快捷方式:
alias symbolicatecrash='/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash'
需要先配置好 DEVELOPER_DIR
,否則會報錯。如下:
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer/
准備好 dSYM 文件和 app 文件,可以存放在任何位置,只要 mac 系統的 spotlight 能夠找到就行。
接著執行
symbolicatecrash xxx.crash
就可以解析符號了。
首先,需要確認一下符號表是不是正確的。可以通過以下方式看看符號文件和堆棧是否是對應的 (判斷 uuid 是否相同):
dwarfdump --uuid MyApp.app/MyApp dwarfdump --uuid xxx.app.dSYM/Contents/Resources/DWARF/Resources/MyApp grep "0x.*com.wison.xxx .*<" NoSymbolsTestxxx.crash
如果不一樣,那麼說明崩潰堆棧和符號文件對應不上,很可能是搞錯版本,或者打包的時候有問題導致符號文件生成不正確。
如果輸出一樣的 uuid,那麼就是對應的,此時 symbolicatecrash
應該可以正常解析符號。
如果還是不能正確解析,那麼很可能是 mdfind 自動查找的問題。
Xcode 找符號文件的時候,是通過 mdfind 來找的,比如:
mdfind 'com_apple_xcode_dsym_uuids = *'
該命令會把當前環境下的所有符號文件找出來。
如果你的符號文件不在此列表中,說明 mdfind 找不到我們的符號,
那麼就在執行 symbolicatecrash
的時候顯式指定dSYM文件的路徑:
symbolicatecrash xxx.crash xxx.dSYM/Contents/Resources/DWARF/MyApp
如果還是不能解析,試一試把 App 文件也指定:
symbolicatecrash xxx.crash xxx.dSYM/Contents/Resources/DWARF/MyApp MyApp.app/MyApp
有時候我們需要解析單個地址的符號,比如 lr
寄存器的地址對應的符號,就需要用到 atos
用法如下:
atos -arch [armv7 or arm64] -o [BinaryFile or dSYMFile] -l loadAddress address
其中-arch
指定二進制的架構,比如 armv7,armv7s,arm64 等等。-o
指定符號文件,可以是 dSYM 文件,也可以是包含了符號表的可執行文件。-l
是加載地址,由於 Xcode 默認打開 PIE 選項,所以加載地址每次都不一樣,所以需要指定,可以在 crash 堆棧的 Binary Image 那段看到應用的加載地址。
最後一個參數是需要解析符號的地址。