iOS dSYM檔案結構剖析(下)
在上次分享中,主要介紹了檔案頭資料的讀取過程,實際上檔案頭的主要內容,標識檔案結構,檔案型別,各個Section在檔案中的位置(偏移量)。正確讀取了這些基本資訊之後,就可以根據我們日常開發中的不同需求,去讀取不同的內容了。瞭解了基本結構,以後如果有某些需求的話,就可以很快的進行資料的分析。今天就來說一說其中用的最多,也是最重要的一個功能,就是用來符號化,下面我們就來了解下是如何通過dSYM檔案做符號化的。
符號表
在前面最後一節中瞭解了符號表資料在檔案中的位置及其讀取方法,符號表在dSYM檔案中是連續的,以0結尾的字串。在檔案中它是怎麼存在的。如圖1所示:
通過對符號表二進位制的讀取,最終我們可以整理出如圖2一些資料。
前面兩列就是符號相對於載入地址的起始結束地址。為了便於展示,Demo中沒有實現過多的函式,如果是比較大點的工程,這個列表就會變的很長。
除錯行資訊
通過前面對Section的讀取,我們可以得到__debug_line在檔案中的位置資訊,如下圖。這裡主要儲存了行號資訊,是符號化必須的資料。這裡的offset不是絕對的,是相對於Arch資訊在檔案中的偏移量來決定的。如圖3所示。
__debug_line在dSYM中是由如下的多塊連續資料構成的,大小是由Section中的size欄位決定的。如圖4所示。
通過上面的二進位制資料,可以整理出如下(圖5)一些資料,這裡是一些頭部資訊,可以得到本段的長度資訊,檔名,檔案所在的路徑。特別要注意的是version,因為不同版本可能存在著差異。
符號時,我們可能不需要知道檔案所在的路徑,但是我們需要知道符號所在的檔案,所以在這裡需要記下每個檔案的序號,稍後解析行號的時候需要用到。在上篇分享中,讀取資料都是有一定的結構的,解析起來相對容易,但是在讀取除錯資訊時,可能沒有固定的結構了,更多的就是檔案儲存,所以在讀取時要遵循DWARF的標準去操作,不然很容易出現錯誤。
行號資訊
現在就可以讀取行號資訊了,也就是圖4中最後標記的那塊資料。整理之後就像圖6這樣的一些資料,在這裡可以得到符號的起始地址,檔案序號,在檔案中的行號。讀取64-bit方法相同,只是有些資料的長度不同,比如地址長度是64位的。
通過對__debug_line資料讀取整理後,我們最終可以得到如下圖7的一組資料,有了圖2和圖7中的資料,最終我們可以得到符號所在檔案的行號和起始結束地址。
到此,符號化的過程基本上就結束了,在得到程式的崩潰地址,就可以在我們整理出的資料中查到相應的行號資訊。當然這裡忽略了讀取資料的一些細節,讀取這些資料是相對繁瑣的一個過程,而且容易出錯,除非對DWARF格式十分的瞭解和熟悉。這裡主要分享下解析的過程和原理,細節過多,不做贅述,當然符號化不止這一種方法,這是我實驗的一種方法,還有一種方法可能更簡單和直接。
對於iOS dSYM檔案的分析,到這裡基本就結束了,本來還想繼續分享比如對__debug_pubnames, __debug_info, __debug_abbrev等等的除錯資訊的解析,但是想來想去在實際的開發工作中也用不到幾次。所以在結束時,想到了我們用到的最多的符號化。至於其它的,以後有機會可以繼續分享。其實,瞭解了符號的過程,其他的資料基本上也是大同小異,關鍵的難點不在於如何讀取或者解析dSYM檔案,而是在於DWARF這種除錯格式檔案本身,及其背後的一套邏輯。
以上是工作中需要處理的問題的一個過程,拿來分享。至於瞭解這些有何用處,那就是仁者見仁,智者見智。
最重要的還是過程。