1. 為什么崩潰日志需要解析
如圖所示是崩潰日志線(xiàn)程回溯信息,其中的調(diào)用堆棧都是二進(jìn)制地址,而不是可讀的函數(shù)名稱(chēng)因此需要對(duì)崩潰日志進(jìn)行解析,解析成可以理解的函數(shù)調(diào)用堆棧。
2.生成dSYM符號(hào)文件
crashlog 解析需要調(diào)試符號(hào)表文件 dSYM(debugging symbols), dSYM 文件實(shí)際上是從Mach-O 文件抽取調(diào)試信息得到的文件目錄。在編譯工程時(shí), debug 模式會(huì)默認(rèn)選中生成dSYM文件, 該配置可在 Build Setting|Build Option 中更改。 dSYM文件生成比較耗時(shí),如果不需要進(jìn)行 crashlog 解析,可以選擇不生成。
2.1 Debug下可以在DeriveData的目錄下獲取到dSYM文件
2.2 打包的時(shí)候可以在生成的.achive目錄下找到對(duì)應(yīng)的dSYM文件
2 解析方法
2.1 Xcode 解析
將crashlog、 dSYM 文件和可執(zhí)行文件放在同一目錄下,然后將 crashlog 拖拽至 Devicelog中,右鍵 Re-symbolicate Log 就能解析。
2.2 使用 symbolicatecrash 命令行解析
- 1.首先找到
symbolicatecrash的路徑
image
通常symbolicatecrash的路徑為/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash - 2.命令行解析
首先將崩潰日志,dSYM以及symbolicatecrash復(fù)制出來(lái)放到同一個(gè)文件夾,然后cd到當(dāng)前文件夾
,運(yùn)行如下命令解析./symbolicatecrash temp.crash testxcConfig.app.dSYM > result.log
image - 3.首次運(yùn)行需要先運(yùn)行命令
export DEVELOPER_DIR="/Applications/XCode.app/Contents/Developer"
3.解析原理
dSYM 文件介紹
其中真正保存保存數(shù)據(jù)的是 DWARF 文件, DWARF(Debuging With Arbitrary Format)是ELF 和 Mach-O 等文件格式中用來(lái)存儲(chǔ)和處理調(diào)試信息的標(biāo)準(zhǔn)格式。 DWARF 中的數(shù)據(jù)是高度 壓 縮 的 , 可以通過(guò)
dwarfdump命令提取可讀信息,比如提取關(guān)鍵的調(diào)試信息.debug_info、.debug_line。注釋?zhuān)?
ELF、Mach-O用于存儲(chǔ)二進(jìn)制文件、可執(zhí)行文件、目標(biāo)代碼和共享庫(kù)的格式文件。解析流程
- 計(jì)算崩潰地址對(duì)應(yīng)符號(hào)表中的地址
以某 crashlog 文件為例,如下圖所示。是一個(gè)Exception類(lèi)型的異常,從下至上依次為該線(xiàn)程的調(diào)用堆棧,右邊紅色框第一列為運(yùn)行時(shí)的堆棧地址,第二列為進(jìn)程運(yùn)行時(shí)的起始地址(testxcConfig 所有行起始地址都相同),第三列為運(yùn)行時(shí)的偏移地址。
image
運(yùn)行時(shí)堆棧地址=運(yùn)行時(shí)起始地址+偏移地址,以第 4 行為例。0x1022cd990=0x1022c8000 + 0x5990(22928),以上地址均為 app 發(fā)生崩潰時(shí)的運(yùn)行地址,根據(jù)虛擬內(nèi)存偏移地址不變的原理,只要知道符號(hào)表 TEXT 段的起始地址,加上偏移量(0x5990)就能得到崩潰地址對(duì)應(yīng)符號(hào)表中的地址, 符號(hào)表 TEXT 段的起始地址可通過(guò)以下命令獲得。
image
那么崩潰地址(0x1022cd990)對(duì)應(yīng)符號(hào)表中的地址為:0x100005990 =0x0000000100000000+0x5990 - 地址重映射
獲取符號(hào)表地址后,在debug-info章節(jié)中查找包含該地址的DIE(Debug Information Entry)單元就能獲知該符號(hào)地址對(duì)應(yīng)的函數(shù)名稱(chēng)(name)、 函數(shù)所在的文件路徑(decl file)和函數(shù)所在行數(shù)(decl line),如下圖所示。
image
上述步驟解析出了函數(shù)相關(guān)信息, 下面進(jìn)一步獲取該地址對(duì)應(yīng)的準(zhǔn)確行數(shù), 這需要借助debug_line章節(jié),debug_line章節(jié)以文件為單位,準(zhǔn)確記錄了文件中的每一行對(duì)應(yīng)的符號(hào)表地址,0x100005990對(duì)應(yīng)AppDelegate.m的第20行。
image - 手動(dòng)解析 crashlog
當(dāng)有完整的crashlog文件和對(duì)應(yīng)的dSYM文件時(shí),以上過(guò)程可以由Xcode自動(dòng)完成。但對(duì)于用戶(hù)反饋的crash, 需要用戶(hù)手動(dòng)復(fù)制本地的crashlog文件,而通常crashlog 文本較長(zhǎng),完整復(fù)制其實(shí)比較麻煩,那么此時(shí)可以只復(fù)制崩潰線(xiàn)程的crash信息,并通過(guò)手動(dòng)解析。手動(dòng)解析crash可以使用dwarfdump、 atos工具, 命令如下。
-
方法一
image -
方法二
image - 方法三
image
方法二、三都使用了atos解析,區(qū)別是方法三不需要獲取符號(hào)表地址, 其后倒數(shù)第一個(gè)地址為運(yùn)行時(shí)堆棧地址,倒數(shù)第二個(gè)地址為進(jìn)程起始地址。
手動(dòng)解析另一個(gè)應(yīng)用場(chǎng)景是,若開(kāi)發(fā)人員為了跟進(jìn)某一偶現(xiàn)問(wèn)題在日志中記錄的是運(yùn)行時(shí)的二進(jìn)制地址,那么可以通過(guò)對(duì)應(yīng)的dSYM文件手動(dòng)解析出調(diào)用函數(shù)明文。
4.常見(jiàn)問(wèn)題
-
如何找到
crashlog對(duì)應(yīng)的dSYM文件?
打開(kāi)終端,使用以下命令獲取dSYM文件對(duì)應(yīng)的uuid, 并與crashlog文件Binary Image后面的字符對(duì)比,如果字符完全相同,就說(shuō)明dSYM文件與crashlog對(duì)應(yīng)。
image
image
另外可以使用mdfind命令去尋找指定uuid的dSYM文件,如下,uuid需大寫(xiě)并轉(zhuǎn)化成格式,如下圖
mdfind "com_apple_xcode_dsym_uuids == D5644244-F2C4-3C96-BD63-EF0F4DA518FA"
image -
如何手動(dòng)生成
dSYM文件?
如果在編譯之前忘記在buildsetting中選中生成dSYM文件,然而 app 又發(fā)生了崩潰,那么可以通過(guò) app 的可執(zhí)行文件再手動(dòng)生成dSYM文件。
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/dsymutil /Users/ranjingfu/Desktop/testxcConfig/testxcConfig.app/testxcConfig -o out.dSYM
image
值得注意的是,只有可執(zhí)行文件為debug模式產(chǎn)物時(shí),才能使用上述方式手動(dòng)抽取調(diào)試符號(hào)表文件(dSYM),release模式無(wú)法抽取。 因?yàn)?code>debug產(chǎn)物會(huì)保存調(diào)試信息,而release產(chǎn)物不會(huì),dSYM文件就是從調(diào)試信息中抽取出來(lái)的。