1. 你好空免,DTrace
DTrace可以使用prob鉤住一個(gè)函數(shù)或一組函數(shù)∨璧ⅲ可以執(zhí)行自定義操作來查詢特定進(jìn)程中的信息蹋砚。如果曾經(jīng)使用過Instruments應(yīng)用程序,那么它下面的許多功能都是由DTrace
提供的摄杂。
1.2 初識(shí)DTrace
打開模擬器和終端窗口:
sudo dtrace -n 'objc$target:*ViewController::entry' -p `pgrep SpringBoard`
加上sudo是因?yàn)?code>DTrace是很強(qiáng)大坝咐,甚至可以查詢電腦上其他用戶的信息。這個(gè)DTrace
命令有兩個(gè)選項(xiàng)析恢,name選項(xiàng)(-n
)和PID選項(xiàng)(-p
)墨坚。
如果輸入的所有內(nèi)容都正確,將在終端窗口中得到類似的輸出
以下內(nèi)容:
dtrace: description 'objc$target:*ViewController::entry' matched 42264 probes
每次探測(cè)命中將打印包含以“ViewController”結(jié)尾的Objective-C類映挂。由于將function字段留空框杜,只要類名以ViewController
結(jié)尾,它就會(huì)輸出每個(gè)匹配的Objective-C方法袖肥。
sudo dtrace -n 'objc$target:UIViewController:-viewWillAppear?:entry { ustack(); }' -p `pgrep SpringBoard`
- 將
*ViewController
查詢更改為UIViewController
咪辱。 - 將
-viewWillAppear?
添加到了function位置。這個(gè)新的DTrace
腳本將只匹配-[UIViewController viewWillAppear:]
椎组,而不是匹配任何包含字符串“ViewController”的類的每個(gè)函數(shù)油狂。?
表示DTrace
中的通配符,它將解析為viewWillAppear:
方法中的“:”寸癌。 - 在一個(gè)大括號(hào)中使用一個(gè)名為
ustack()
的函數(shù)专筷。每次命中-[UIViewController viewWillAppear:]
時(shí)都會(huì)調(diào)用此邏輯。ustack()
是DTrace
的內(nèi)置函數(shù)之一蒸苇。當(dāng)這個(gè)方法被命中時(shí)磷蛹,它會(huì)打印調(diào)用棧。
輸入正確的話會(huì)得到以下輸出:
dtrace: description 'objc$target:UIViewController:-viewWillAppear?:entry ' matched 1 probe
當(dāng)-[UIViewController viewWillAppear:]
命中時(shí)溪烤,堆棧跟蹤將在終端中打印出來味咳。
當(dāng)objc_msgSend
執(zhí)行時(shí),函數(shù)簽名將如下所示:
objc_msgSend(self_or_class, SEL, ...);
可以使用arg0
參數(shù)在DTrace
中獲取第一個(gè)參數(shù)檬嘀,也就是UIViewController
的實(shí)例槽驶。不幸的是,我們只能獲得指針的引用鸳兽,不能運(yùn)行任何Objective-C代碼掂铐,如[arg0 title]
。
在DTrace
命令的ustack()
函數(shù)之前添加printf("\nUIViewcontroller is: 0x%p\n", arg0);
:
sudo dtrace -n 'objc$target:UIViewController:-viewWillAppear?:entry
{ printf("\nUIViewcontroller is: 0x%p\n", arg0); ustack(); }' -p `pgrep SpringBoard`
dtrace: description 'objc$target:UIViewController:-viewWillAppear?:entry ' matched 1 probe
CPU ID FUNCTION:NAME
0 142401 -viewWillAppear::entry
UIViewcontroller is: 0x7ff224830000
UIKitCore`-[UIViewController viewWillAppear:]
SpringBoard`-[SBIconController viewWillAppear:]+0x2a
UIKitCore`-[UIViewController _setViewAppearState:isAnimating:]+0x297
UIKitCore`-[UIViewController __viewWillAppear:]+0x73
BaseBoardUI`-[UIViewController(BaseBoardUI) bs_beginAppearanceTransition:animated:]+0x64
BaseBoardUI`-[UIViewController(BaseBoardUI) bs_beginAppearanceTransitionForChildViewController:toVisible:animated:]+0xb6
SpringBoard`-[SBHomeScreenViewController setIconControllerHidden:]+0x106
SpringBoard`-[SBUIController restoreContentWithOptions:]+0x54e
SpringBoard`-[SBUIController beginRequiringContentForReason:options:]+0x125
SpringBoard`-[SBToAppsWorkspaceTransaction transaction:performTransitionWithCompletion:]+0x10d
SpringBoard`-[SBSceneLayoutWorkspaceTransaction _beginLayoutTransition]+0x93
SpringBoard`__55-[SBSceneLayoutWorkspaceTransaction _performTransition]_block_invoke_2+0x3c
BaseBoard`-[BSBlockTransaction _begin]+0x85
BaseBoard`__22-[BSTransaction begin]_block_invoke+0xa5
BaseBoard`-[BSTransaction _preventTransactionCompletionForReason:ignoringAuditHistory:andExecuteBlock:]+0x55
BaseBoard`-[BSTransaction begin]+0x3b3
BaseBoard`-[BSTransaction _noteFinishedWork]+0x1fd
BaseBoard`-[BSTransaction _checkAndReportIfCompleted]+0xc2
BaseBoard`-[BSTransaction _removeMilestones:ignoringAuditHistory:]+0x498
BaseBoard`__49-[BSTransaction evaluateMilestone:withEvaluator:]_block_invoke+0x9c
現(xiàn)在在打印出堆棧跟蹤之前,打印對(duì)調(diào)用viewWillAppear的UIViewController
的引用全陨。如果復(fù)制DTrace
的這個(gè)指針的地址并將LLDB附著到SpringBoard
爆班,我們會(huì)發(fā)現(xiàn)它指向一個(gè)有效的UIViewController
(如果還沒有被釋放的話)。
sudo dtrace -n 'objc$target:::entry { @[probemod] = count() }' -p `pgrep SpringBoard`
暫時(shí)還不會(huì)得到任何輸出辱姨,但是一旦使用Ctrl + C終止這個(gè)腳本蛋济。我們將得到一個(gè)聚合列表,列出了執(zhí)行特定類的方法的所有次數(shù)炮叶。從我的輸出中可以看到碗旅,SpringBoard
有12878個(gè)由NSObject
實(shí)現(xiàn)的方法調(diào)用。
區(qū)分父類子類的調(diào)用很重要镜悉。例如祟辟,調(diào)用-[UIViewController class]
將被視為對(duì)NSObject
執(zhí)行的方法總數(shù)的命中。因?yàn)?code>UIViewController沒有重寫Objective-C方法class
侣肄,UIViewController
的父類UIResponder
也沒有重寫旧困。
1.2 DTrace專業(yè)用語
我們可以將探測(cè)視為查詢。這些探測(cè)是DTrace
可以在特定進(jìn)程中監(jiān)視的事件稼锅,也可以跨計(jì)算機(jī)全局監(jiān)視吼具。
dtrace -n 'objc$target:NSObject:-description:entry / arg0 != 0 / { @[probemod] = count(): }' -p `pgrep SpringBoard`
這個(gè)例子將監(jiān)視NSObject
在名為SpringBoard
的進(jìn)程中對(duì)description
方法的實(shí)現(xiàn)。此外矩距,一旦description
方法開始拗盒,就執(zhí)行邏輯來聚合調(diào)用該方法的次數(shù)。
-
Probe Description:封裝一組指定0個(gè)或多個(gè)探測(cè)的項(xiàng)锥债。它由
provider
陡蝇、module
、function
和name
組成哮肚,每個(gè)都用冒號(hào)分隔登夫。在冒號(hào)之間省略這些項(xiàng)將導(dǎo)致探測(cè)描述包含所有匹配項(xiàng)。你可以用*
或?
用于模式匹配的運(yùn)算符允趟。?
運(yùn)算符將充當(dāng)單個(gè)字符的通配符恼策,而*
將匹配任何字符。 -
Provider:將
provider
視為一組代碼或公共功能潮剪。我們將主要使用objcprovider
程序來跟蹤Objective-C方法調(diào)用涣楷。objcprovider
程序?qū)⒕酆纤蠴bjective-C代碼。
注意:
$target
關(guān)鍵字是一個(gè)特殊關(guān)鍵字鲁纠,它將匹配我們給DTrace提供的任何PID总棵。某些provider
(比如objc)希望提供這個(gè)關(guān)鍵字鳍寂。把
$target
看作實(shí)際PID的占位符改含,它監(jiān)視特定進(jìn)程中的Objective-C。如果確實(shí)引用了$target
占位符迄汛,則必須在DTrace命令中通過-p
或-c
選項(xiàng)標(biāo)志指定目標(biāo)PID捍壤。通常骤视,如果我們知道確切的PID,這可以通過
-p
PID完成鹃觉,或者可能通過-p "pgrep NameOFProcess"
完成专酗。pgrep
命令將查找進(jìn)程名為NameOFProcess
的PID,然后返回該P(yáng)ID盗扇,然后將其應(yīng)用于$target
變量祷肯。
Module:在objc提供程序中,
Module
部分是指定要觀察的類名的位置疗隶。在這個(gè)意義上佑笋,使用objc提供程序有點(diǎn)獨(dú)特。因?yàn)橥ǔDK用于引用代碼來自的庫斑鼻。事實(shí)上蒋纬,在一些提供商中,根本沒有模塊坚弱!然而蜀备,objc provider
的作者選擇使用模塊來引用Objective-C類名。對(duì)于這個(gè)例子來說荒叶,模塊是NSObject
碾阁。Function:探測(cè)描述中可以指定要觀察的函數(shù)名。對(duì)于這個(gè)例子來說些楣,函數(shù)是-description瓷蛙。
objc provider
的作者使用+
或-
來確定Objective-C函數(shù)是類還是實(shí)例方法。如果將函數(shù)更改為+description
戈毒,它將查詢?nèi)魏螏в?code>+[NSObject description]的探測(cè)艰猬。Name:這通常指定函數(shù)中探測(cè)的位置。entry表示進(jìn)入函數(shù)埋市,return表示離開函數(shù)冠桃。此外,在
objc provider
中道宅,還可以指定要在其上創(chuàng)建探測(cè)的任何匯編指令偏移量食听!對(duì)于這個(gè)例子來說,名稱是entry
污茵,或者函數(shù)的開始樱报。Predicate:一個(gè)可選表達(dá)式,用于評(píng)估操作是否是
action
的候選者泞当。把謂詞看作if語句中的條件迹蛤。只有謂詞的計(jì)算結(jié)果為true時(shí),才會(huì)執(zhí)行action
部分。如果省略謂詞部分盗飒,則每次對(duì)給定探測(cè)執(zhí)行操作塊嚷量。對(duì)于這個(gè)特定的例子,謂詞是/ arg0 = 0 /
逆趣,這意味著只有當(dāng)arg0
不是nil時(shí)蝶溶,才會(huì)計(jì)算謂詞后面的內(nèi)容。Action:如果探測(cè)與探測(cè)描述匹配宣渗,并且謂詞的計(jì)算結(jié)果為true抖所,則要執(zhí)行的操作『鄞眩可以執(zhí)行將某些內(nèi)容打印到控制臺(tái)部蛇,或者更高級(jí)的功能。對(duì)于本例咐蝇,操作是
@[probemod] = count();
代碼涯鲁。
簡(jiǎn)單來說,它的結(jié)構(gòu)是這樣:
provider:module:function:name / predicate / { action }
DTrace
可以包含多個(gè)子句有序。這些子句可以使用探測(cè)描述監(jiān)視不同的項(xiàng)抹腿,檢查謂詞中的不同條件,并使用不同的操作執(zhí)行不同的邏輯旭寿。
dtrace -n 'objc$target:NSView:-init*:entry' -p `pgrep -x Xcode`
有一個(gè)objc$target:NSView:-init*:entry
的探測(cè)描述警绩,其中包括NSView
作為模塊,-init*
作為函數(shù)盅称,entry
作為名稱肩祥,沒有謂詞和操作。DTrace
生成一個(gè)用于跟蹤的默認(rèn)輸出(可以使用-q
選項(xiàng)使其保持沉默)缩膝。這個(gè)默認(rèn)輸出僅顯示函數(shù)和名稱混狠。例如,如果在跟蹤-[NSObject init]
時(shí)沒有使默認(rèn)DTrace
操作靜音疾层,則DTrace輸出將如下所示:
dtrace: description ’objc$target:NSObject:-init:entry’ matched 1 probe
CPU ID FUNCTION:NAME
2 512130 -init:entry
2 512130 -init:entry
2 512130 -init:entry
2 512130 -init:entry
從輸出來看将饺,跟蹤進(jìn)程時(shí)-[NSObject init]
被命中4次。我們可以告訴DTrace
使用不同格式的輸出痛黎,方法是將-q
選項(xiàng)與一個(gè)打印函數(shù)組合起來予弧,以顯示輸出的其他格式。
-n
參數(shù)指定可以采用provider:module:function:name
湖饱、module:function:name
或function:name
格式的DTrace名稱掖蛤。此外,name
選項(xiàng)可以接受可選的探測(cè)子句井厌。這就是為什么要將所有一行腳本內(nèi)容用單引號(hào)括起來傳遞給-n
參數(shù)的原因蚓庭。
1.3 列出探測(cè)器
-l
將列出在探測(cè)描述中匹配的所有探測(cè)致讥。當(dāng)我們使用-l
選項(xiàng)時(shí),DTrace
將只列出探測(cè)彪置,而不執(zhí)行任何操作拄踪。這使得-l
選項(xiàng)成為一個(gè)很好的工具蝇恶,可以用來學(xué)習(xí)哪些要工作拳魁,哪些不工作。
在構(gòu)建DTrace腳本時(shí)撮弧,我們將再次查看探測(cè)描述并系統(tǒng)地限制其范圍潘懊。請(qǐng)考慮以下情況,但不要執(zhí)行此操作:
sudo dtrace -ln ’objc$target:::’ -p `pgrep -x Finder`
這將在Finder
應(yīng)用程序中的每個(gè)Objective-C類贿衍、方法和匯編指令上創(chuàng)建探測(cè)描述授舟。對(duì)于DTrace
腳本來說,這是一個(gè)非常糟糕的主意贸辈。最好不要運(yùn)行释树,因?yàn)閷@得大量的命中。
注意:我們向
pgrep
提供了-x
選項(xiàng)擎淤。因?yàn)槲覀兛赡塬@得多個(gè)pid
奢啥,這將破壞占位符$target
。-x
選項(xiàng)表示返回與Finder
名稱完全匹配的PID嘴拢。如果一個(gè)進(jìn)程有多個(gè)實(shí)例桩盲,可以使用-o
或-n
選項(xiàng)在pgrep
中獲得最老的或最新的實(shí)例。
sudo dtrace -ln 'objc$target:NSView::' -p `pgrep -x Finder`
這將列出NSView
實(shí)現(xiàn)的每個(gè)方法以及每個(gè)方法中的每個(gè)匯編指令的探測(cè)席吴。仍然是一個(gè)可怕的想法赌结,但至少這個(gè)會(huì)在一秒鐘后打印出來。這有多少個(gè)探測(cè)器孝冒?我們可以通過將輸出發(fā)送到wc
命令來獲得答案:
~> sudo dtrace -ln 'objc$target:NSView::' -p `pgrep -x Finder` | wc -l
41307
我們?cè)龠^濾一下:
sudo dtrace -ln 'objc$target:NSView:-initWithFrame?:' -p `pgrep -x Finder`
這將把探測(cè)描述篩選到-[NSView initWithFrame:]
中執(zhí)行的每個(gè)匯編指令柬姚。注意到?
的用法了嗎?而不是冒號(hào)來指定Objective-C選擇器庄涡。如果使用冒號(hào)伤靠,則DTrace
將錯(cuò)誤地分析輸入,認(rèn)為函數(shù)部分已完成啼染,并已轉(zhuǎn)到DTrace
探測(cè)中指定名稱宴合。函數(shù)描述的開頭還有-
表示這是一個(gè)實(shí)例Objective-C方法。
仍然輸出太多迹鹅,我們只想監(jiān)視-[NSView initWithFrame:]
方法的開頭卦洽。
~> sudo dtrace -ln 'objc$target:NSView:-initWithFrame?:entry' -p `pgrep -x Finder`
Password:
ID PROVIDER MODULE FUNCTION NAME
1156826 objc358 NSView -initWithFrame: entry
1.4 一個(gè)創(chuàng)建DTrace腳本的腳本
在使用DTrace
時(shí),不僅要處理異常陡峭的學(xué)習(xí)曲線斜棚,如果遇到構(gòu)建時(shí)或運(yùn)行時(shí)DTrace錯(cuò)誤阀蒂,還要處理一些神秘錯(cuò)誤该窗。
為了幫助您在學(xué)習(xí)DTrace時(shí)減輕這些構(gòu)建問題,這里創(chuàng)建了一個(gè)的小腳本tobjectivec.py
(trace Objective-C)蚤霞。這是一個(gè)LLDB Python腳本酗失,會(huì)為我們生成一個(gè)自定義DTrace腳本。
通過tobjectivec.py探索DTrace
運(yùn)行Allocator項(xiàng)目昧绣,然后在調(diào)試器中暫停规肴。
(lldb) tobjectivec -g
通常,tobjectivec
腳本將在計(jì)算機(jī)的/tmp/
目錄中生成一個(gè)腳本夜畴。但是拖刃,這個(gè)-g
選項(xiàng)表示我們正在調(diào)試腳本并將輸出顯示到LLDB,而不是在/tmp/
中創(chuàng)建文件贪绘。使用-g
(--debug
)選項(xiàng)時(shí)兑牡,當(dāng)前腳本將顯示在控制臺(tái)上。這個(gè)沒有額外參數(shù)的tobjectivec.py
運(yùn)行將產(chǎn)生以下輸出:
#!/usr/sbin/dtrace -s /* 1 */
#pragma D option quiet /* 2 */
dtrace:::BEGIN { printf("Starting... use Ctrl + c to stop\n"); } /* 3 */
dtrace:::END { printf("Ending...\n" ); }
/* Script content below */
objc$target:::entry /* 5 */
{
printf("0x%016p %c[%s %s]\n", arg0, probefunc[0], probemod, (string)&probefunc[1]); /* 6 */
}
- 執(zhí)行
DTrace
腳本時(shí)税灌,第一行必須是#均函!/usr/sbin/dtrace-s
,否則腳本可能無法正常運(yùn)行菱涤。 - 表示在探測(cè)觸發(fā)時(shí)不列出探測(cè)計(jì)數(shù)苞也,也不執(zhí)行默認(rèn)的
DTrace
操作。相反狸窘,我們將給DTrace
設(shè)置自定義操作墩朦。 - 這是此腳本中
DTrace
子句的三分之一。讓DTrace
用于監(jiān)視某些DTrace
事件翻擒。比如當(dāng)DTrace
腳本即將啟動(dòng)時(shí)氓涣。一旦DTrace開始,就打印出“Starting... use Ctrl + c to stop“字符串陋气。 -
DTrace
腳本完成時(shí)劳吠,打印“Ending...”。 - 我們感興趣的
DTrace
探測(cè)描述巩趁。意思是在提供給腳本的進(jìn)程ID中跟蹤找到的所有Objective-C代碼痒玩。 - 這個(gè)子句的
action
部分,輸出觸發(fā)的Objective-C探測(cè)的實(shí)例议慰,然后輸出Objective-C樣式的輸出蠢古。在這里,可以看到使用probefunc
和probemod
别凹,這將是函數(shù)和模塊的char*
表示草讶。DTrace
有幾個(gè)可以使用的內(nèi)置變量,probefunc
炉菲、probemod
堕战、probeprov
和probename
坤溃。記住,模塊將表示類名嘱丢,而函數(shù)將表示Objective-C方法薪介。這里用到了probemod
和probefunc
,并以我們習(xí)慣的C語法顯示它越驻。
重新執(zhí)行:
(lldb) tobjectivec
Copied script to clipboard... paste in Terminal
在終端窗口粘貼執(zhí)行:
~> sudo /tmp/lldb_dtrace_profile_objc.d -p 73610
Password:
Starting...use Ctrl + c to stop
在Xcode的LLDB中輸入po [NSObject class]
:
如果我們隨便玩一玩這個(gè)app會(huì)發(fā)現(xiàn)有大量的輸出汁政。東西太多了,下面我們通過向模塊說明符添加內(nèi)容來過濾一些噪聲伐谈。在LLDB中鍵入以下內(nèi)容:
tobjectivec -m *StatusBar* -g
我們看一下這次的探測(cè)描述:
objc$target:*StatusBar*::entry
{
printf("0x%016p %c[%s %s]\n", arg0, probefunc[0], probemod, (string)&probefunc[1]);
}
注意探針的模塊部分是如何改變的烂完。在正則表達(dá)式中试疙,*
可以被認(rèn)為是任何我們感興趣的诵棵。當(dāng)探測(cè)進(jìn)入函數(shù)的開頭時(shí),查詢包含任何Objective-C類的區(qū)分大小寫單詞StatusBar的探測(cè)祝旷。在LLDB中履澳,刪除-g選項(xiàng)以便將此腳本復(fù)制到剪貼板,然后重新執(zhí)行該命令怀跛。
(lldb) tobjectivec -m *StatusBar*
終端中粘貼:
~> sudo /tmp/lldb_dtrace_profile_objc.d -p 73610
Password:
Starting...use Ctrl + c to stop
跳轉(zhuǎn)到模擬器并使用? + Y切換通話狀態(tài)欄距贷,或使用? + ←或? + →旋轉(zhuǎn)模擬器,同時(shí)注意DTrace終端窗口吻谋。再次得到大量的輸出忠蝗。我們可以使用DTrace
在代碼上撒下一個(gè)大網(wǎng),并在需要時(shí)快速向下深挖漓拾。
跟蹤調(diào)試命令
我們來觀察一下要調(diào)用多少Objective-C方法才能生成一個(gè)簡(jiǎn)單的Objective-C NSString阁最。在LLDB中,輸入以下內(nèi)容:
(lldb) tobjectivec
然后在LLDB中輸入:
(lldb) po @"hi this is a long string to avoid tagged pointers"
我們剛剛打印了一個(gè)簡(jiǎn)單的
NSString
骇两,看看這需要多少Objective-C調(diào)用速种!
返回到LLDB并鍵入以下內(nèi)容:
expression -l swift -O -- class b { }; let a = b()
我們使用Swift調(diào)試上下文創(chuàng)建一個(gè)純Swift類,然后將其實(shí)例化低千。創(chuàng)建這個(gè)類時(shí)配阵,請(qǐng)觀察Objective-C方法調(diào)用。
0x0000000105f81c58 +[_TtCs12_SwiftObject class]
0x00000001088db7f8 +[_TtCs12_SwiftObject initialize]
0x00000001088db7f8 -[_TtCs12_SwiftObject self]
如果把DTrace
拋出的地址復(fù)制出來示血,然后po
一下棋傍。你會(huì)看到這個(gè)純Swift類調(diào)用了多少Objective-C方法。一個(gè)“純粹的”Swift并不像我們想象的那樣純粹难审,對(duì)吧瘫拣?
跟蹤一個(gè)對(duì)象
我們可以使用DTrace
輕松跟蹤特定引用的方法調(diào)用。暫停應(yīng)用程序剔宪,使用LLDB獲取對(duì)UIApplication
的引用拂铡。
(lldb) po UIApp
<UIApplication: 0x7ffc65601750>
復(fù)制引用并使用它來構(gòu)建一個(gè)謂詞壹无,該謂詞僅在該引用為arg0
時(shí)停止。
(lldb) tobjectivec -g -p 'arg0 == 0x7ffc65601750'
#!/usr/sbin/dtrace -es
#pragma D option quiet
dtrace:::BEGIN { printf("Starting...use Ctrl + c to stop\n"); }
dtrace:::END { printf("Ending...\n" ); }
/* Script content below */
objc$target:::entry / arg0 == 0x7ffc65601750 /
{
printf("0x%016p %c[%s %s]\n", arg0, probefunc[0], probemod, (string)&probefunc[1]);
}
然后去掉-g
選項(xiàng):
(lldb) tobjectivec -p 'arg0 == 0x7ffc65601750'
觸發(fā)模擬器中的home
按鈕(?+Shift + H)或狀態(tài)欄(? + Y)感帅。
這將打印[UIApplication sharedApplication]
實(shí)例上的每個(gè)Objective-C方法調(diào)用斗锭。
是不是輸出太多內(nèi)容了?我們來將內(nèi)容聚合:
(lldb) tobjectivec -g -p 'arg0 == 0x7ffc65601750' -a '@[probefunc] = count()'
#!/usr/sbin/dtrace -es
#pragma D option quiet
dtrace:::BEGIN { printf("Starting...use Ctrl + c to stop\n"); }
dtrace:::END { printf("Ending...\n" ); }
/* Script content below */
objc$target:::entry / arg0 == 0x7ffc65601750 /
{
@[probefunc] = count()
}
在不使用-g
選項(xiàng)的情況下重新運(yùn)行上面的tobjectivec
命令失球,然后將剪貼板內(nèi)容粘貼到終端并在LLDB中繼續(xù)執(zhí)行岖是。這時(shí)終端中尚未顯示任何內(nèi)容。但DTrace
正在悄悄地聚合發(fā)送到UIApplication
實(shí)例的每個(gè)方法实苞。
在模擬器中隨意玩一玩豺撑,獲取發(fā)送到UIApplication的方法的正常計(jì)數(shù)。一旦使用通常的Ctrl + C終止腳本黔牵,DTrace
將打印應(yīng)用于UIApplication
實(shí)例的所有Objective-C方法的總數(shù)聪轿。
其他DTrace小技巧
追蹤所有對(duì)象的所有初始化方法:
(lldb) tobjectivec -f ?init*
檢測(cè)進(jìn)程內(nèi)通信相關(guān)的邏輯(比如,Webviews猾浦、keyboards等等):
(lldb) tobjectivec -m NSXPC*
打印出在iOS設(shè)備上處理開始觸摸事件的UIControl
的子類 :
(lldb) tobjectivec -m UIControl -f -touchesBegan?withEvent?