在分析Safari行為的時候想到要用objective-c的特性隨時可以語義化的查看一下UIView的各種狀態,比如在UIView方法內部設了個斷點,想看一下當前視圖結構。只要得到當前執行個體的控制代碼就可以了。查了一些資料,記錄一下。
函數參數的傳遞
iOS Simulator裡應用是跑在32bits模式下的(在Activity Monitor可以看到),依據<<Mac OS Debug Magic>>裡關於Intel 32bits參數傳遞的定義:
Table 2 : Accessing parameters on Intel 32-bit(64bits是先使用通用寄存器來傳遞參數,不足時再使用其它方式)
What |
GDB Syntax |
return address |
*(int*)$esp |
first parameter |
*(int*)($esp+4) |
second parameter |
*(int*)($esp+8) |
... and so on |
|
如果已經進入到函數體,也就是過函數參數處理部分(開場位置, prologue), 參數就要到調用幀寄存器(frame register)ebp中去擷取了。
Table 3 : Accessing parameters after the prologue
What |
GDB Syntax |
previous frame |
*(int*)$ebp |
return address |
*(int*)($ebp+4) |
first parameter |
*(int*)($ebp+8) |
second parameter |
*(int*)($ebp+12) |
... and so on |
|
傳回值存放在EAX寄存器中。
既然知道參數是如何儲存的,那C++和Objective-C是如何傳遞當前執行個體的控制代碼的呢?
答案在同一份文檔的這裡:
當在組合語言下調試Cocoa代碼,請記住以下運行時特性:
The Objective-C compiler adds two implicit parameters to each method, the first of which is a pointer to the object being called (self
).
The second implicit parameter is the method selector (_cmd
). In Objective-C this is of type SEL
;
in GDB you can print this as a C string.
The Objective-C runtime dispatches methods via a family of C function. The most commonly seen is objc_msgSend
, but some architectures use objc_msgSend_stret
for
methods which returns structures, and some architectures useobjc_msgSend_fpret
for methods that return floating point values. There are also equivalent functions for calling super
(objc_msgSendSuper
and
so on).
The first word of any Objective-C object (the isa
field) is a pointer to the object's class.
就是函數調用時第一個參數就是操作對應的對象(如果自己的方法,就是self了), 第二參數就是selector method.
實戰分析一下CALayer::addSublayer中的執行情況,
在這裡使用lldb memory指令:
(lldb) me read -s4 -fx -c4 `$esp`
0xb01dd28c: 0x0000a07c
0x0929e170 0x04e7aad3 0x1386d750再調用一個檢查一下控制代碼:
(lldb)
po [0x0929e170 description] 或者
(lldb)
po [`*(int*)($esp+4)` description]
(id) $102 = 0x0929e210 <CALayer: 0x929e170>
(*注意, `不是單引號! 如果這個對象是UIView, 使用recursiveDescription你就知道它的威力了! )
(lldb)
po [*(0x0929e170) isHidden]
(id) $105 = 0x00000001 [no Objective-C description available]這樣就可以調用其它方法進行操作了。再次驗證一下第二個參數:
(lldb)
me read -s4 -fs 0x4e7aad3
或者
(lldb)
me read -s4 -fs `*(int*)($esp+8)`
0x04e7aad3: "addSublayer:"
0x04e7aae0: NULL用一個檢查UIView層次的執行個體來展示它的強大:
(lldb) po [[`*(int*)($esp+4)` superview] recursiveDescription]
(id) $7 = 0x0719f940 <UIWebSelectionView: 0x107d74e0; frame = (0 0; 0 0); layer = <CALayer: 0x107d7620>>
| <UIView: 0x107d7770; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x107d77d0>>
| <UIWebSelectionOutline: 0x759b340; frame = (-2 -2; 4 4); userInteractionEnabled = NO; layer = <CALayer: 0x75963e0>>
| | <UIView: 0x759b3f0; frame = (0 0; 0 0); layer = <CALayer: 0x759d580>>
| | <UIView: 0x759da60; frame = (0 0; 0 0); layer = <CALayer: 0x759bfb0>>
| | <UIView: 0x759be40; frame = (0 0; 0 0); layer = <CALayer: 0x759db30>>
| | <UIView: 0x718d150; frame = (0 0; 0 0); layer = <CALayer: 0x719f650>>
附註:*如果是C++, 則第一個參數就是this,所以也很方便查。而函數傳回值放在EAX中,在ret位置設個斷點,也可以很方便查看。*這個調試過程最好使用LLDB, 它對Objective-C的支援要好很多。
Reference: iOS Debug Magic Mac OS Debug Magic
轉載請註明出處: http://blog.csdn.net/horkychen