Xcode如何找到FrameWork對應的源碼的

背景描述:

在cocpoads管理下自研庫和第三方的開源庫可以使用frameWork的方式集成到主工程中打毛,在我們編譯過程中柿赊,只要不改動pod下集成的庫代碼,第一次編譯后幻枉,第三方庫會編譯成frameWork碰声,通過Xcode 的 buildSetting 的 framework search Path 記錄所有生成的framework地址,在項目的編譯后期去link這些framework 熬甫。在沒有修改pod子工程的庫文件前提下胰挑,之后的每一次build都直接link緩存中編譯過的framework文件。但是當文件編譯成framework椿肩,成為了可執(zhí)行的二進制文件瞻颂,我們卻任然可以借助Xcode做源碼調(diào)試。那么Xcode工具是如何通過一個二進制文件執(zhí)行時找到它對應的源碼文件的郑象?

鑒于上個問題贡这,我們可以先看看Xcode的編譯過程

Xcode作為一個GUI工具,實際上是通過調(diào)用一系列的命令行工具厂榛,將命令行工具處理的結(jié)果匯總輸出盖矫。Xcode 使用clang編譯器進行編譯 會使用一系列 xcrun clang 的命令來編譯文件,xcrun是用來定位clang工具位置的

接著看編譯過程中都經(jīng)歷了些什么击奶?
大致過程如下:

1.文件預處理

符號化 (Tokenization)
宏定義的展開
include 的展開

2.語法語義分析

將符號化后的內(nèi)容轉(zhuǎn)化為一棵解析樹 (parse tree)
解析樹做語義分析
輸出一棵抽象語法樹(Abstract Syntax Tree* (AST))

3.代碼生成和優(yōu)化

將 AST 轉(zhuǎn)換為更低級的中間碼 (LLVM IR)
對生成的中間碼做優(yōu)化
生成特定目標代碼
輸出匯編代碼

4.匯編器

將匯編代碼轉(zhuǎn)換為目標對象文件辈双。

5.link文件

將多個目標對象文件合并為一個可執(zhí)行文件 (或者一個動態(tài)庫)

整個過程比較復雜,特別是語義分析柜砾,和代碼優(yōu)化過程湃望,可以先簡單的看一下與處理過程。clang 有很多命令,可以通過

`$xcrun clang —help `

查看提示信息

其中關(guān)于預編譯的:

-c                      Only run preprocess, compile, and assemble steps
-E                      Only run the preprocessor

我嘗試使用上面的命令預編譯了main.c文件
main.c文件:

#include <stdio.h>
int main(int argc, char *argv[])
{
    printf("Hello World!\n");
    return 0;
}

在main.c當前目錄下執(zhí)行
xcrun clang -E main.c | open -f

Open -f 是將預編譯結(jié)果在文件中打開证芭,預編譯部分結(jié)果截圖如下:

1.png

2.png

預編譯過程因為要展開所有的宏定義瞳浦,inclue , import。 輸出的文件中行前面的 “#”號 (hash) 接著的數(shù)字 代表的插入的源文件中的行號檩帐, 后面的文件路徑代表的是需要引入的文件的路徑 后面的數(shù)字代表的是引入的內(nèi)容在新生成的文件所在的行數(shù)术幔,hash下面跟的內(nèi)容是指定文件 指定行數(shù) 所引入的內(nèi)容,例如第二張圖中
將 /Application/Xcode.app/Contents/Developer/platforms/MacOSX10.12.sdk/usr/include/machine/_types.h 文件中的第33行湃密,34行诅挑,55行的代碼段
插入新生成的文件中。

Xcode也支持查看文件的預編譯結(jié)果 泛源,選中文件點擊product—>perform Action —>preprocess,之后便能看到預編譯的結(jié)果拔妥,可以對比所引入的文件所在行數(shù)和引入的內(nèi)容是否對應。

Xcode基于預編譯的結(jié)果去構(gòu)建語法樹达箍,生成中間字節(jié)碼没龙,下面是hello world的LLVM中間字節(jié)碼


3.png

可以簡單了解一下上面llvm中間碼的意思,@符號是LLVM中間字節(jié)碼(IR)的變量前綴缎玫,@代表全局變量標志硬纤,%代表局部變量標志。@.str是全局變量名赃磨,%cast210 是局部變量的名稱 筝家。i8, i32,i64代表的存儲字節(jié)類型邻辉,char是i8溪王,一個字節(jié),int是i32值骇,4個字節(jié)莹菱。@main,@put吱瘩,@puts是方法名道伟,在IR中function和全局變量統(tǒng)稱全局值(global values)都是@前綴標志。

根據(jù)中間字節(jié)碼(LLVM的字節(jié)碼)做代碼優(yōu)化使碾,優(yōu)化后輸出匯編代碼皱卓。

可以使用下面命令來查看生成的匯編代碼:
xcrun clang -S -o - main.c | open -f
結(jié)果如下圖:

4.png

按照上面說的步驟,就進入了調(diào)用匯編器編譯匯編代碼了部逮,匯編器將匯編代碼轉(zhuǎn)換成機器碼,稱為目標對象文件嫂易,在MacOSX兄朋, ios下為 Mach-O文件格式下圖是蘋果官方文檔對mach-o文件格式的介紹:

5.png

Mach-O 的組成結(jié)構(gòu)如下圖所示包括了Header、Load commands、Data(包含Segement的具體數(shù)據(jù))
我們可以在工程的編譯路徑下找到編譯后生成的可執(zhí)行文件APP颅和,我本地路徑為~/Library/Developer/Xcode/DerivedData/App-ackwqnrbjrdvslercxzskjictqru/Build/Intermediates/App.build/Release-iphonesimulator/App.build/Objects-normal/i386
在此路徑下使用size工具查看文件結(jié)構(gòu)
xcrun size -x -l -m App
輸出
6.png

剛好與蘋果給出的結(jié)構(gòu)圖相匹配,可以暫時先簡單的了解下傅事,__TEXT segment 包含了被執(zhí)行的代碼,它被以只讀和可執(zhí)行的方式映射峡扩。__DATA segment 中包含了可讀寫數(shù)據(jù)蹭越, 以可讀寫和不可執(zhí)行的方式映射,它包含了將會被更改的數(shù)據(jù)教届。__LINKEDIT segment 包含了動態(tài)鏈接器的原始數(shù)據(jù)响鹃,如符號,字符串和重定位的表的入口.

7.png

最后進入連接器連接的階段
鏈接器解決了目標文件和庫之間的鏈接案训,鏈接器需要將所需的lib函數(shù)(可以理解為系統(tǒng)提供的函數(shù))买置,庫函文件的內(nèi)存地址編碼進最后的可執(zhí)行文件中,接著鏈接器會輸出可以運行的執(zhí)行文件:a.out强霎,得到a.out 命令為:
xcrun clang man.c
用size 工具查看a.out的文件結(jié)構(gòu)

8.png

可以看到 main.c文件生成的可執(zhí)行文件a.out 的虛擬地址空間從0x10000000 開始的忿项,之前的地址是不可訪問

此時在借助mac下可執(zhí)行文件的閱讀器。machOView工具城舞,看生成的a.out的文件結(jié)構(gòu)和內(nèi)容轩触,發(fā)現(xiàn)了一張叫symbols的表


9.png

這里面就很清楚的記錄了,編譯前的字符串家夺,在編譯成二進制可執(zhí)行文件后的虛擬地址脱柱,和app打包生成的dsym基本類似,這就可以猜想秦踪,蘋果是如何通過crash的二進制棧信息解析出可讀性的程序代碼調(diào)用棧的褐捻。借助symbols表給我的希望,我用machOView打開了我編譯生成的frameWork

原諒我把圖片糊得像翔椅邓。柠逞。。景馁。因為是公司的項目的frameWork

首先第一張里表示了在不同平臺下的可執(zhí)行數(shù)據(jù)板壮,當前frameWork可在ARM,X86合住,Arm64绰精,X86_64平臺下執(zhí)行


一.png

第二張圖是所有frameWork內(nèi)的類名對應的編譯生成的虛擬地址


二.png

第三張是挑了第二張圖中的一個類的symbols表,記錄的是當前文件編譯后的字符對照表透葛。


三.png

那么有了以上三張表的對比后我們很容易的了解到Xcode工具如何通過運行期間的二進制地址對應到具體文件的具體代碼調(diào)用了笨使。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市僚害,隨后出現(xiàn)的幾起案子硫椰,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件靶草,死亡現(xiàn)場離奇詭異蹄胰,居然都是意外死亡,警方通過查閱死者的電腦和手機奕翔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門裕寨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人派继,你說我怎么就攤上這事宾袜。” “怎么了互艾?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵试和,是天一觀的道長。 經(jīng)常有香客問我纫普,道長阅悍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任昨稼,我火速辦了婚禮节视,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘假栓。我一直安慰自己寻行,他們只是感情好,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布匾荆。 她就那樣靜靜地躺著拌蜘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪牙丽。 梳的紋絲不亂的頭發(fā)上简卧,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機與錄音烤芦,去河邊找鬼举娩。 笑死,一個胖子當著我的面吹牛构罗,可吹牛的內(nèi)容都是我干的铜涉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼遂唧,長吁一口氣:“原來是場噩夢啊……” “哼芙代!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起盖彭,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤链蕊,失蹤者是張志新(化名)和其女友劉穎事甜,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滔韵,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年掌实,在試婚紗的時候發(fā)現(xiàn)自己被綠了陪蜻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡贱鼻,死狀恐怖宴卖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情邻悬,我是刑警寧澤症昏,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站父丰,受9級特大地震影響肝谭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蛾扇,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一攘烛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧镀首,春花似錦坟漱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至成翩,卻和暖如春觅捆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捕传。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工惠拭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人庸论。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓职辅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親聂示。 傳聞我的和親對象是個殘疾皇子域携,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容