[iOS開發(fā)]iOS 符號表dSYM

一、符號表

1、概念:debugger Symbols 的簡稱。符號表就是指在Xcode項目編譯后,在編譯生成的.app的同級目錄下生成的同名的.dSYM文件。
符號表是內(nèi)存地址與函數(shù)名,文件名,行號的映射表。 符號表元素如下所示:

<起始地址> <結(jié)束地址> <函數(shù)> [<文件名:行號>]

.dSYM文件其實是一個目錄,在子目錄中包含了一個16進(jìn)制的保存函數(shù)地址映射信息的中轉(zhuǎn)文件,所有Debug的symbols都在這個文件中(包括文件名、函數(shù)名、行號等),所以也稱之為調(diào)試符號信息文件。

2、作用:符號表就是用來符號化 crash log(崩潰日志)。crash log中有一些方法16進(jìn)制的內(nèi)存地址等,通過符號表就能找到對應(yīng)的能夠直觀看到的方法名之類。

3、獲取途徑:在Archive的時候會生成.xcarchive文件,然后顯示包內(nèi)容就能夠在里面找到.dsYM文件和.app文件。

  • 一般Xcode項目每次編譯后, 都會產(chǎn)生一個新的.dSYM文件和.app文件, 這兩者有一個共同的UUID.
  • 注:項目編譯完dSYM文件和app文件在同一個目錄,Xcode Debug 編譯默認(rèn)不會生成.dSYM文件, Release 編譯才會生成
  • 注:為了方便找回Crash對應(yīng)的dSYM文件和還原堆棧,建議每次構(gòu)建或者發(fā)布APP版本的時候,備份好dSYM文件。

二、符號化文件

1、 Xcode分析

1>、要使用Xcode符號化 crash log,你需要下面所列的3個文件:
①crash報告(.crash文件)
②符號文件 (.dsymb文件)
③應(yīng)用程序文件 (.app文件)

2>、把這3個文件放到同一個目錄下,打開Xcode的Window菜單下的organizer,然后點(diǎn)擊Devices tab,然后選中左邊的Device Logs。
然后把.crash文件拖到Device Logs或者選擇下面的import導(dǎo)入.crash文件。
這樣你就可以看到crash的詳細(xì)log了。

2、使用命令行工具symbolicatecrash

1>、將“.app“, “.dSYM”和 ".crash"文件放到同一個目錄./Crash 下。
2>、在Xcode中找到 symbolicatecrash 工具

使用命令

find /Applications/Xcode.app -name symbolicatecrash -type f

可以輕松找到。找到后你會發(fā)現(xiàn)有多個其中

/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash

對應(yīng)的是真機(jī), 找到后將 symbolicatecrash 拷貝到 ./Crash 目錄下

3>、切換到 ./Crash目錄下。 打開終端(Terminal)然后輸入如下的命令:

export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer

然后輸入命令:

./symbolicatecrash appName.crash appName.app > appName.log

現(xiàn)在,符號化的crash log就保存在appName.log中了。

如果報No such file or directory : at ./symbolicatecrash line 909.錯誤,嘗試執(zhí)行

./symbolicatecrash ./*.crash ./*.app.dSYM>Symbol_Crash.crash

3、atos

  • atos 是一個可以把地址轉(zhuǎn)換為函數(shù)名(包括行號)的工具, 它和dwarfdump 為mac os自帶工具.
    我們使用atos命令來完成符號化,具體命令如下:
    $ atos -arch <Binary Architecture> -o <Path to dSYM file>/Contents/Resources/DWARF/<binary image name> -l <load address> <address to symbolicate>

其中:

  • Binary Architecture: arm64、armv6、armv7 armv7s 根據(jù)自己的情況來寫。
  • Path to dSYM file: dSYM文件的路徑。
  • binary image name: 你工程的名字。
  • load address: 是運(yùn)行時起始地址(基地址),如果我們的崩潰日志中沒有這個信息(比如上面的Crash信息中就沒有包含),就需要我們手動去計算這個load * address:laod address = address to symbolicate - offset,比如:0x0000000102838119轉(zhuǎn)化為十進(jìn)制為4337139993,再減去偏移量265,為4337139728,在轉(zhuǎn)化為十六進(jìn)制0x0000000102838010
  • address to symbolicate:運(yùn)行時堆棧地址,當(dāng)前方法的內(nèi)存地址。

具體示例:
atos -arch arm64 -o CrashDemo.app.dSYM/Contents/Resources/DWARF/CrashDemo -l 0x0000000102838010 0x0000000102838119

這樣crash文件就被符號化完成了,打開符號化如下圖:

三、Crash分析

以上圖為例,大部分字段都是不言而喻的,下面列舉一些有用處的。(在官方文檔都有解釋,這里做歸納與翻譯)

Incident Identifier: 報告的唯一標(biāo)識符,兩份報告決不會共享同一個事件標(biāo)識符。
CrashReporter Key:每個設(shè)備的匿名標(biāo)識符,來自同一設(shè)備的兩個報告將包含相同的值。
Process:很明顯是我們的進(jìn)程名稱。
Date/Time 與 Launch Time:報告生成時間與程序開始運(yùn)行時間
Exception Type:異常類型
Exception Note:不屬于異常類型的附加信息,如果這個字段包含SIMULATED(不是崩潰),那這個進(jìn)程不是崩潰的,而是在系統(tǒng)的請求下被殺死,通常是看門狗機(jī)制起了作用(APP內(nèi)一段時間內(nèi)無法響應(yīng)用戶的操作,會被系統(tǒng)kill)。
Termination Reason:閃退的原因,比如常見的數(shù)組越界啊,什么的。
Triggered by Thread:出現(xiàn)問題在哪個線程,這個比較重要,首先確定在哪個線程中出了問題,然后再去定位。
接著是最重要的堆棧信息,由下到上為最后調(diào)用的順序:

image

可以很明顯的看到,一個名為ViewController的對象在viewDidLoad方法中調(diào)用了第35行的testMethodTwo方法,并執(zhí)行testMethodTwo方法中的61行時代碼,在Backtrace第2行可以發(fā)現(xiàn)調(diào)用了未識別的方法導(dǎo)致崩潰,我們來看下代碼。

最終我們找到了崩潰的原因:一個NSArray調(diào)用了addObject方法,so easy!

一些較常見的異常類型(如果翻譯錯誤請指正):

內(nèi)存訪問不良[EXC_BAD_ACCESS // SIGSEGV // SIGBUS]

通常用于訪問了不該訪問的內(nèi)存導(dǎo)致或者嘗試以不允許的方式訪問內(nèi)存(例如只讀屬性,比如在上一篇我們提到的通過KVO更改只讀屬性),并且" Exception SubType"字段會包含kern_return_t來描述錯誤和未正確訪問的內(nèi)存地址。
下面是官方給出的建議:

  • 如果objc_msgSendobjc_release接近崩潰線程的Backtraces(堆棧信息回溯)的頂部,則該進(jìn)程可能試圖向釋放的對象發(fā)送消息,可以使用Zombie Instrument來分析應(yīng)用程序,以更好地了解此次崩潰的情況。
  • 如果gpus_ReturnNotPermittedKillClient接近崩潰線程的Backtraces的頂部,則該進(jìn)程被終止,因為它嘗試在后臺使用OpenGL ES或Metal進(jìn)行渲染。
異常退出[EXC_CRASH // SIGABRT]

該進(jìn)程異常退出,此異常類型崩潰的最常見原因是向?qū)ο蟀l(fā)送了無法識別的消息,比如上文中向NSArray發(fā)送了addObject消息。
另外如果App Extensions需要太多時間來初始化(看門狗機(jī)制),那么App Extensions將終止于此異常類型,如果擴(kuò)展因啟動時掛起而死亡,則生成的崩潰報告的Exception Subtype將會是LAUNCH_HANG,由于擴(kuò)展沒有main函數(shù),任何花在初始化上的時間都會在+load擴(kuò)展庫和相關(guān)庫中的靜態(tài)構(gòu)造函數(shù)和方法中,你應(yīng)該盡可能多地推遲這項工作。

資源限制[EXC_RESOURCE]

該過程超出了資源消耗限制,這是來自操作系統(tǒng)的通知,該進(jìn)程正在使用太多的資源,確切的資源列在Exception SubType字段中。如果Exception Note字段包含NON-FATAL CONDITION,則即使生成崩潰報告,該進(jìn)程也不會被終止。

  • 異常子類型MEMORY表示該進(jìn)程已超過系統(tǒng)施加的內(nèi)存限制。
  • 異常子類型WAKEUPS表示進(jìn)程中的線程每秒被喚醒的次數(shù)過多,這迫使CPU醒來的頻率很高,并且消耗電池壽命。

四、符號化dSYM常見問題

如何查看dsYM文件的UUID?

方法一: 通過命令行查看dSYM文件的UUID

 xcrun dwarfdump --uuid <dSYM文件>

方法二:通過符號表文件查看UUID
符號表文件的UUID與dSYM文件的UUID是一致的,因此可以通過符號表工具生成的符號表文件來查看dSYM文件的UUID:
生成符號表文件(.zip) ---> 解壓符號表文件(.symbol) ---> 使用文本編輯器打開符號表文件

其中符號表文件的“UUID”信息即Debug SO文件的UUID,亦是符號表文件的UUID,如果文件較大,建議使用“Sublime Text”等文本編輯器來打開符號表文件。

如何定位dSYM文件?

一般情況下,項目編譯完dSYM文件跟app文件在同一個目錄下,下面以XCode作為IDE詳細(xì)說明定位dSYM文件。

-> 進(jìn)入XCode;
-> 打開工程(已編譯過);
-> 在左欄找到“Product”項;
-> 鼠標(biāo)右鍵點(diǎn)擊編譯生成的“xxx.app”;
-> 點(diǎn)擊“Show in Finder”;

如下圖所示:

如果有多個dSYM文件,可以在使用工具時指定輸入為dSYM文件所在的目錄或者工程目錄。

Xcode編譯后沒有生成dSYM文件?

XCode Release編譯默認(rèn)會生成dSYM文件,而Debug編譯默認(rèn)不會生成,對應(yīng)的Xcode配置如下:

XCode -> Build Settings -> Code Generation -> Generate Debug Symbols -> Yes

XCode -> Build Settings -> Build Option -> Debug Information Format -> DWARF with dSYM File

image.png

開啟Bitcode之后需要注意哪些問題?

  • 在點(diǎn)“Upload to App Store”上傳到App Store服務(wù)器的時候需要聲明符號文件(dSYM文件)的生成:


  • 在配置符號表文件之前,需要從App Store中把該版本對應(yīng)的dSYM文件下載回本地(參考“如何找回已發(fā)布到App Store的App對應(yīng)的dSYM文件?”),然后用符號表工具生成和上傳符號表文件。

  • 不需要配置自動生成符號表的腳本了,也不要用本地生成的dSYM文件來生成符號表文件,因為本地編譯生成的dSYM文件的符號表信息都被隱藏了。如果用本地編譯生成的dSYM文件生成符號表文件并配置到Bugly平臺之后,還原出來的結(jié)果將是類似于“__hiden#XXX”這樣的符號。

如何判斷dSYM文件是否與Crash的UUID匹配?

Bugly還原Crash堆棧時,需要根據(jù)UUID來匹配符號表文件,因此只有上傳的符號表文件的UUID與Crash對應(yīng)APP的UUID一致時,才能準(zhǔn)確地對堆棧進(jìn)行還原。

  • 查看符號表文件的UUID(“如何查看dSYM文件的UUID?”)

  • 查看Crash對應(yīng)的APP的UUID

如何找回已發(fā)布到App Store的App對應(yīng)的dSYM文件?

1> 通過Xcode找回
  1. 打開 Xcode 頂部菜單欄 -> Window -> Organizer 窗口:
  1. 打開 Xcode 頂部菜單欄,選擇 Archive 標(biāo)簽:
  1. 找到發(fā)布的歸檔包,右鍵點(diǎn)擊對應(yīng)歸檔包,選擇Show in Finder操作:


  2. 右鍵選擇定位到的歸檔文件,選擇顯示包內(nèi)容操作:

  1. 選擇dSYMs目錄,目錄內(nèi)即為下載到的 dSYM 文件:
2>通過mdfind工具找回

在Bugly的issue頁面查詢到crash對應(yīng)的UUID:

然后在Mac的Shell中,用mdfind命令定位dSYM文件:

mdfind "com_apple_xcode_dsym_uuids == <UUID>"

注意,使用mdfind時,UUID需要格式轉(zhuǎn)換(增加“-”): 12345678-1234-1234-1234-xxxxxxxxxxxx

例如,要定位的dSYM的UUID為:E30FC309DF7B3C9F8AC57F0F6047D65F 則定位dSYM文件的命令如下:

mdfind "com_apple_xcode_dsym_uuids == E30FC309-DF7B-3C9F-8AC5-7F0F6047D65F"
                                     |12345678-1234-1234-1234-xxxxxxxxxxxx|

建議每次構(gòu)建或者發(fā)布APP版本的時候,備份App對應(yīng)的dSYM文件!

參考:
iOS開發(fā)符號表(dSYM)知識總結(jié)
bugly文檔
iOS Crash收集與分析詳解(基礎(chǔ)篇)
iOS Crash監(jiān)測及處理上傳

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容