天天看點

xcode反彙編調試iOS模拟器程式(五)調試objc_msgSend函數

反彙編調試objective-c,遇到最多的就是objc_msgSend這函數了,本節主要講講它的實作以及調試過程的一些技巧。

以UIWebView為例子,看看它在loadRequest時做了什麼。

首先必須明白,原始代碼中調用

的實質是調用了

編寫一個用到UIWebView的demo,主要功能是打開一個網頁。

在main函數加斷點,觸發後,在指令行輸入:

然後continue,直到觸發斷點,如下圖:

用step over跑到第17行,或直接在那加個斷點continue到那。旁邊的注釋已經顯示,call的是存儲了objc_msgSend這個函數的偏移位址的代碼位置。

17行的前三行,可以看出其動作是往棧上傳參數,這三個參數原本是放在edx,ecx,eax的,是以如果參數不多,也可以不用esp為基址來查參數。

在目前的指令行輸入

來檢視各寄存器的值。lldb會把目前值的意義也輸出來。但gdb不會,gdb對應的指令是

結果如下圖:

從ecx的内容可以看出,要call的selector的名字同樣是loadRequest:,後面會驗證。

接着,step into,可以看到:

那裡隻有一個跳轉指令,繼續step into,跳到objc_msgSend真正的位址,看到下圖所示的代碼:

簡單點說,這些代碼做了這些事:

1. 先判斷傳來的對象是否nil,是的話,把傳回值(esp+4)置0就傳回了,不是就進行下一步。即使是void型的函數,也是被當做有傳回值的,隻是沒用。

2. 查找這個method有沒有被cache,有就jmpl到cache了的IMP位址;沒有就以selector代表的字元串從這個類的method list裡找出method來(第13到20行的循環),cache後再jmpl。如果找不到method就抛出異常然後程式崩潰了。

一個小技巧是,如果想省去點好多次step over來跳過查找的步驟,可以在兩個jmpl *%eax的地方加斷點,然後run到那裡(圖中的第31行和38行)。如果傳來的對象不是nil,最後都會到這來。此時eax裡儲存的是函數的位址,即objective-c運作時庫定義的IMP(指向函數的指針),jump過去就能到目标函數裡了。

另外,在調試反彙編時,step over和step into不要用快捷鍵,要用調試工具欄上的按鈕。不知道為什麼按快捷鍵都等于run了……

接着,在jmpl處step into,就到真實的函數了:

證明了剛才ecx是傳了selector名字。

在lldb中搜尋

可以看到:

objc_msgSend會有好多個版本:

objc_msgSend是普通調用,傳回值為void、id、指針、int等32bit能表示的資料的objective-c函數會用到它。

objc_msgSend_stret在傳回值為結構體時用到,stret表示structure return。值得一提的是,C++類也算是結構體哦。

objc_msgSend_fpret在傳回值為浮點數時用到,fpret表示floating point return

帶Super的表示調用父類的函數。

如上節所說,在obj_msgSend的第一行加自動斷點 p (char*)*(SEL*)($esp+8) 就會列印多到你不想看的selector名字。注意這個地方不能去po對象,因為po的實質是調用對象的description,這個會再調用obj_msgSend,無限遞歸就挂了。

xcode反彙編調試iOS模拟器程式

<a href="http://blog.csdn.net/hursing/article/details/8697654">(一)檢視反彙編</a>

<a href="http://blog.csdn.net/hursing/article/details/8700964">(二)看懂反彙編</a>

<a href="http://blog.csdn.net/hursing/article/details/8721870">(三)檢視Objective-C函數與參數</a>

<a href="http://blog.csdn.net/hursing/article/details/8752235">(四)自動斷點應用之NSNotificationCenter</a>

<a href="http://blog.csdn.net/hursing/article/details/8755491">(五)調試objc_msgSend函數</a>

<a href="http://blog.csdn.net/hursing/article/details/8766487">(六)函數出入口處的處理與局部變量</a>

<a href="http://blog.csdn.net/hursing/article/details/8766719">(七)Debug與Release的差別</a>