15、iOS強(qiáng)化 --- dSYM

今天我們來探討一下dSYM文件。我們在使用第三方工具來檢測APP在運(yùn)行的過程中的崩潰情況的時(shí)候,往往會被要求上傳一個(gè)dSYM文件(比如Firebase)。那么dSYM文件究竟是什么、又有什么作用呢?


初識 dSYM

  • dSYM:保存按DWARF格式保存調(diào)試信息的文件。
  • DWARF:是一種被眾多編譯器和調(diào)試器使用的用于支持源代碼級別調(diào)試的調(diào)試文件格式。

那么我們的調(diào)試信息是怎么生成dSYM文件的呢?
i: 讀取debug map
ii: 從.o文件中加載__DWARF
iii: 重新定位所有地址
iiii: 最后將全部的DWARF打包成dSYM Bundle
有了dSYM后,我們就擁有了最標(biāo)準(zhǔn)的DWARF的文件,任何可以dwarf讀取工具(可以處理Mach-O二進(jìn)制文件)都可以處理該標(biāo)準(zhǔn)DWARF。

  • 首先我們來看一下這樣一個(gè)文件:



    執(zhí)行下面的指令:

clang -g -c main.m -o main.o
/*
-g 代表生成調(diào)試信息
*/

之后我們會得到一個(gè)__DWARFSection(這里面保存的就是調(diào)試信息);也就是說編譯器在編譯的時(shí)候會將調(diào)試信息存放在__DWARF里面,但是當(dāng)鏈接的時(shí)候,會將__DWARF段刪除,將調(diào)試信息放到符號表里面。
在終端執(zhí)行objdump --macho --private-headers main.o指令,可以在終端查看.o文件的內(nèi)容。

  • 生成dSYM文件
clang -g1 main.m -o main
/*
-g1 生成可執(zhí)行文件的時(shí)候,同時(shí)生成dSYM文件
*/
  • 查看dSYM文件
dwarfdump main.dSYM


可以看到dSYM文件里面保存了符號對應(yīng)的一些信息,比如:地址,名稱等等。這就是按一定的格式保存的調(diào)試信息。其實(shí)這就是將我們符號表里的調(diào)試信息,抽取出來,按照DWARF的格式,從新生成了dSYM文件。


dSYM 在實(shí)際開發(fā)中的應(yīng)用

首先我們來看一下我們的案例:



看到上面的代碼,大家都清楚,運(yùn)行起來會崩潰,因?yàn)閿?shù)組越界。
那么我們來看一下Xcode的打印信息:


Xcode打印的崩潰信息

可以看到Xcode可以精準(zhǔn)的打印出崩潰的代碼信息。這是因?yàn)閄code保存了我們的調(diào)試符號信息。

正常的開發(fā)過程中,APP上線之后我們并不能像這樣再Xcode里面查看崩潰信息,通常我們拿到的是一個(gè)crash文件。此時(shí)我們可以通過控制臺來模擬一下這個(gè)情況:

控制臺信息

  • 大家也知道,我們APP在上架的時(shí)候會進(jìn)行脫符號,這個(gè)時(shí)候就看不到具體的崩潰信息了。如下:


    脫符號
  • 此時(shí)我們添加一個(gè)腳本來生成我們的dSYM文件:
rm -rf -- "${SRCROOT}/../dSYM"  ///刪除dSYM目錄
mkdir -p -- "${SRCROOT}/../dSYM" ///生成dSYM目錄
cp -Rv -- ${BUILT_PRODUCTS_DIR} "${SRCROOT}/../dSYM" ///把編譯的產(chǎn)物,拷貝到指定的目錄下

/// 如果只想拷貝dSYM文件,可以這樣寫
/// cp -Rv -- ${BUILT_PRODUCTS_DIR}/*.dSYM "${SRCROOT}/../dSYM"
腳本
  • 我們再來運(yùn)行一下,看一下此時(shí)的控制臺的內(nèi)容:


    控制臺信息

    可以看到,此時(shí)控制臺并沒有清楚的打印出崩潰的符號信息,只剩下一個(gè)地址。

這里要補(bǔ)充一個(gè)知識點(diǎn):ASLR地址空間配置隨機(jī)加載。也就是說我們的在運(yùn)行時(shí)調(diào)試到的地址實(shí)際上是這樣的:
調(diào)試地址 = 虛擬地址 + ASLR

通過上面我們知道,dSYM文件是編譯鏈接的時(shí)候生成的,而ASLR所產(chǎn)生的偏移地址是dyld在調(diào)用程序的時(shí)候才加上去的。所以dSYM里面保存的是偏移前的虛擬內(nèi)存地址。

在我們的Mach-o中,第一個(gè)地址的起始地址是:


那么在Mach-o中進(jìn)行偏移的話,也是以Mach-o為單位進(jìn)行偏移的。

  • 我們再來看一下控制臺信息,獲取偏移地址量:


    偏移地址

    錯(cuò)誤信息地址

    那么偏移前的內(nèi)存地址就是:

/// 偏移前的內(nèi)存地址 = 偏移后的地址 - 偏移量
0x0000000100001E70 = 0x0000000101ae6e70 - 0x1ae5000
  • 下面我們通過計(jì)算出來的地址,在dSYM文件中查找一下我們要的崩潰信息:
dwarfdump --lookup 0x0000000100001E70 TestInject.app.dSYM
dSYM文件中篩選的信息

這樣就得到了我們需要的崩潰信息。這也就是我們在使用第三方工具的時(shí)候,能夠精準(zhǔn)定位到我們的報(bào)錯(cuò)代碼的原因。


如何查找Xcode幫我們生產(chǎn)的dSYM文件

  • 打包時(shí)
    我們的每一次Archive都會生成一條記錄。找到記錄所在的目錄,在.achive目錄下就可以找到dSYM文件。
  • debug
    debug的時(shí)候,如果不想通過上面腳本的方式將dSYM文件拷貝出來,可以在編譯產(chǎn)物里面查找:

另外我們還可以選擇是否生成dSYM File:


  • tips
    我們在進(jìn)行算術(shù)運(yùn)算的時(shí)候,可以通過(lldb)終端命令來計(jì)算:

    --:表示后面的不再是e的指令
    d:代表十進(jìn)制
    b:代表二進(jìn)制
    x:代表十六禁止

如果想要進(jìn)制轉(zhuǎn)換,直接帶上數(shù)字就可以了:

(lldb) e -f x -- 10
(int) $2 = 0x0000000a

這樣我們在Xcode的控制臺就可以很方便的進(jìn)行算術(shù)運(yùn)算了。

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

相關(guān)閱讀更多精彩內(nèi)容

  • 一. Macho格式解析 準(zhǔn)備test.m文件,內(nèi)容如下 二. 崩潰日志與dSYM dSYM文件就是按DWARF格...
    淺墨入畫閱讀 750評論 0 2
  • 一、符號表 1、概念:debugger Symbols 的簡稱。符號表就是指在Xcode項(xiàng)目編譯后,在編譯生成的....
    codeTao閱讀 19,947評論 2 17
  • iOS 項(xiàng)目打包成功后為 xcarchive 后綴的文件, 里面不但包含了 app 運(yùn)行所需要的二進(jìn)制文件和資源文...
    uniapp閱讀 3,355評論 0 5
  • 目的 探索iOS Crash分類及捕獲流程 了解Crash文件結(jié)構(gòu)及段含義 了解Mach-o文件結(jié)構(gòu) 分析Cras...
    lltree閱讀 1,486評論 0 8
  • 1. 為什么崩潰日志需要解析 如圖所示是崩潰日志線程回溯信息,其中的調(diào)用堆棧都是二進(jìn)制地址,而不是可讀的函數(shù)名稱因...
    落葉情思閱讀 1,813評論 0 1

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