開始學(xué)習(xí)LLDB命令(第九章:正則命令)

在前面的章節(jié)中, 你已經(jīng)學(xué)習(xí)了為命令創(chuàng)建別名并將它們保存在lldbinit文件中.不幸的是, 命令別名有一些局限性.
用這種方法創(chuàng)建的別名如果你用來執(zhí)行靜態(tài)命令會表現(xiàn)的很好, 但是有時候你想在命令中輸入一些內(nèi)容以便得到一些有用的輸出.
用命令別名的本質(zhì)是用實(shí)際的命令替換了別名. 如果你想在命令的中間輸入一些東西, 比如一條獲取對象實(shí)例的類的命令, 提供需要輸入的對象?
一種極其拙劣的解決方案就是用命令別名做下面的事情(請永遠(yuǎn)不要這樣做):

(lldb) po id $INPUT = @"input test";
(lldb) command alias getcls po -l objc -O -- [$INPUT class]

這在LLDB中創(chuàng)建了一個叫做$INPUT的臨時變量然后使用$INPUT獲取類.但是這種方式很拙劣. 你不得不每次都要重新聲明一個$INPUT, 這完全違背了使用快捷命令的初衷.
然而, 不要絕望 - 這里有一種優(yōu)雅的解決方案可以支持輸入.

命令正則

在LLDB中command regex命令實(shí)際上很像命令別名, 除非你可以為輸入的將會作為命令的一部分執(zhí)行的內(nèi)容提供一個正則表達(dá)式.
command regex帶來了一種輸入語法類似于下面的樣子:

s/<regex>/<subst>/

這是一個普通的正則表達(dá)式. 它是以s/開頭的, 這指定了一個流編輯器將輸入的內(nèi)容作為替換命令.<regex>是將要被替代的部分, <subst>部分是用來替代的部分.

注意:這種語法衍生自`sed`終端命令. 知道這點(diǎn)是很重要的, 因?yàn)槿绻銍L試使用高級模式, 你可以查看`sed`的主頁來看看在替換格式語法中可能是哪些內(nèi)容.

到了看一個具體例子的時間了. 打開Signals的Xcode項(xiàng)目. 構(gòu)建并運(yùn)行, 然后將應(yīng)用程序暫停在調(diào)試器中. 一旦LLDB的控制臺出現(xiàn)并準(zhǔn)備接受輸入, 在LLDB中輸入下面的內(nèi)容:

(lldb) command regex rlook 's/(.+)/image lookup -rn %1/'

你輸入的這條命令會使你的 image正則搜索更簡單. 你已經(jīng)創(chuàng)建了一個叫做rlook的新命令. 這條新命令會獲取rlook后面的所有東西并用image lookup -rn作為它的前綴. 這條命令做了這樣一件事情, 用image lookup -rn %1替換可以匹配一個或多個字符的正則表達(dá)式(圓括號) 內(nèi)的所有內(nèi)容. %1表示這匹配到的內(nèi)容.
所以, 例如, 你輸入了這樣的內(nèi)容:

rlook FOO

LLDB實(shí)際執(zhí)行的的是下面的內(nèi)容:

image lookup -rn FOO

現(xiàn)在你就可以通過僅僅輸入rlook 來替代輸入長長的image lookup -rn命令.
但是等一下, 現(xiàn)在變得好一點(diǎn)了!假如與rl字符沒有沖突, 你也可以用rl字符替代. 你可以指定任何命令, 可以是內(nèi)置的或者你自己的, 只要是與其他命令沒有沖突的前綴.
這就意味著你可以使用更簡潔的輸入來搜索viewDidLoad方法. 現(xiàn)在來試一下:

(lldb) rl viewDidLoad

這回提取出當(dāng)前可執(zhí)行文件中所有模塊中的viewDidLoad的實(shí)現(xiàn). 嘗試將搜索范圍限定在viewDidLoadAPP中:

(lldb) rl viewDidLoad Signals

現(xiàn)在你已經(jīng)確信了這條命令, 講下面這行代碼添加到~/.lldbinit文件中:

command regex rlook 's/(.+)/image lookup -rn %1/'
注意:實(shí)現(xiàn)一個正則命令的最佳方式是在程序運(yùn)行中用LLDB實(shí)現(xiàn). 這可以讓你在命令正則中重復(fù)聲明(在你對它不滿意的時候重新聲明)并且可以在不重啟LLDB的情況下測試它.如果你對命令很滿意, 那么將它添加到`~/.lldbinit`文件中以便LLDB每次啟動的時候都可以使用.

從現(xiàn)在開始rlook就變得可用了, 你再也不用輸入令人頭疼的image lookup -rn的完整命令了.太棒了!

執(zhí)行復(fù)雜的邏輯

是時候把命令的正則表達(dá)式提升一個等級了.實(shí)際上你可以用一條命令的別名來執(zhí)行多條指令. 現(xiàn)在LLDB應(yīng)該依然在暫停狀態(tài), 輸入下面這條新的命令:

(lldb) command regex -- tv 's/(.+)/expression -l objc -O -- @import
QuartzCore; [%1 setHidden:!(BOOL)[%1 isHidden]]; (void)[CATransaction
flush];/'

這是一條復(fù)雜而有用的命令, 將會創(chuàng)建一個名字叫tv (toggle view)的命令, 可用與當(dāng)調(diào)試器暫停的時候在UIView (或者 NSView)之間切換.
這條命令由三行代碼組成:

  1. @import QuartzCore, 在調(diào)試器的地址空間中導(dǎo)入QuartzCore框架. 這是必要的因?yàn)橹挥性谀懵暶髁舜a之后調(diào)試器才理解你在執(zhí)行什么. 你需要執(zhí)行QuartzCore框架中的代碼, 之前還沒有導(dǎo)入, 但是現(xiàn)在已經(jīng)導(dǎo)入了.
  2. [%1 setHidden:!(BOOL)[%1 isHidden]];, 在視圖的可見于不可見之間切換, 這取決于之前的狀態(tài)是可見的還是不可見的. 注意isHidden不知道返回值的類型, 因此你需要將它轉(zhuǎn)換為Objective-C中的Bool值.
  3. 最后一行代碼是, [CATransactionflush], 它會刷新CATransaction隊(duì)列. 調(diào)試器中控制UI也就是通常所說的屏幕在調(diào)試器繼續(xù)執(zhí)行之前不會反映出任何改變. 然而, 這個方法將會更新LLDB中執(zhí)行的結(jié)果而不需要continue就能展示視覺上的改變.
注意:由于輸入?yún)?shù)的限制, 多行輸入是不允許的, 所以你不得不將所有的指令都放在一行代碼中. 在手工控制正則命令的時候這很難看但卻很有必要.然而, 如果你曾經(jīng)在`Objective-C/Swift`的源代碼中做過這些, 那么蘋果上帝可能用很多次的審核嚴(yán)厲的懲罰過你!

如果LLDB依然在暫停狀態(tài), 執(zhí)行新創(chuàng)建的tv命令:

(lldb) tv [[[UIApp keyWindow] rootViewController] view]

page100image13312.png

查看模擬器里確認(rèn)一下視圖已經(jīng)消失了.
現(xiàn)在只需要簡單的在LLDB中按下Enter, LLDB就會重復(fù)你之前執(zhí)行的最后一條指令.視圖會刷新到之前的狀態(tài).
現(xiàn)在你已經(jīng)實(shí)現(xiàn)了tv的命令, 將它添加到~/.lldbinit文件中.

 command regex -- tv 's/(.+)/expression -l objc -O -- @import QuartzCore;
[%1 setHidden:!(BOOL)[%1 isHidden]]; (void)[CATransaction flush];/'
鏈接正則輸入

這條命令之所以選擇使用怪誕的流編輯器輸入是有原因的:這種格式可以讓你輕松的在一條命令中指定多個動作. 當(dāng)給出多個指令的時候, 這個正則表達(dá)式會試著匹配每一個輸入.如果輸入匹配到了, 匹配到的內(nèi)容就會應(yīng)用到指令的<subst>部分.如果輸入沒有匹配到指定的流, 他就會進(jìn)入下一條命令并且看看正則表達(dá)式是否能匹配到那些輸入.
當(dāng)我們在處理內(nèi)存中或者寄存器中的對象的時候使用Objective-C環(huán)境是普遍必要的. 因?yàn)? 以方括號[開始的任何語句或者@字符都是Objective-C里面的.這是因?yàn)镾wift在處理內(nèi)存數(shù)據(jù)的時候很難, 并且它不允許你訪問寄存器, 同時在處理swift表達(dá)式的時候也不是以[或者@開始的.
你可以使用這些信息自動檢測給定的輸入需要什么樣的環(huán)境.
讓我們看一下你應(yīng)該怎么去構(gòu)建一個獲取對象類信息的一條指令,:
? 在 Objective-C中, 你應(yīng)該使用[objcObject class].
? 在 Swift 中, 你應(yīng)該輸入 (of: swiftObject).
在Xcode中, 在MasterViewController.viewDidLoad () - > ()處創(chuàng)建一個斷點(diǎn)(不要忘記中間的空格).

page101image17376.png

構(gòu)建并運(yùn)行, 等待斷點(diǎn)被觸發(fā).像往常一樣, 轉(zhuǎn)到調(diào)試器里.
首先, 構(gòu)建出新命令getcls的Objective-C的實(shí)現(xiàn).

(lldb) command regex getcls 's/(([0-9]|\$|\@|\[).*)/cpo [%1 class]/'

哇, 這條正則表達(dá)式讓我們的眼睛都花了.我們來拆解一下:
首先, 這里有一個內(nèi)部分組說在起始部分可以匹配接下來的字符:
? [0-9]的意思是可以是0-9的數(shù)字.
? \$的意思是$的字面量將會被匹配
? \@的意思是@的字面量將會被匹配
? \[的意思是[的字面量將會被匹配
以上面的內(nèi)容為開始的字符都會生成一個匹配. 緊跟著的.*的意思是為一個或多個字符產(chǎn)生一個匹配.
整體看來,這句話的意思是一個數(shù)字或者$符號或者 @符號或者[符號, 后面跟著任何字符的內(nèi)容都會作為命令匹配到的結(jié)果并且運(yùn)行cpo [%1 class].再說一次, %1會被正則表達(dá)式中第一個匹配到的內(nèi)容替換. 在這里, 就是整條命令. 而內(nèi)部匹配器(匹配一個數(shù)字, $, 等等)將會作為%2.
現(xiàn)在用一組命令來實(shí)驗(yàn)一下getcls命令看看它是如何工作的:

(lldb) getcls @"hello world"
__NSCFString
(lldb) getcls @[@"hello world"]
__NSSingleObjectArrayI
(lldb) getcls [UIDevice currentDevice]
UIDevice
(lldb) cpo [UIDevice currentDevice]
<UIDevice: 0x60800002b520>
(lldb) getcls 0x60800002b520
UIDevice

很神奇吧!
然而, 這只能處理Objective-C環(huán)境中用命令匹配到的引用.例如, 試一下下面的內(nèi)容:

(lldb) getcls self

你會得到一個錯誤:

error: getcls

這是因?yàn)檎齽t表達(dá)式?jīng)]有匹配到你輸入的內(nèi)容. 讓我們在getcls中添加一個匹配其他形式的輸入. 現(xiàn)在在LLDB中輸入下面的內(nèi)容:

 (lldb) command regex getcls 's/(([0-9]|\$|\@|\[).*)/cpo [%1 class]/' 's/
(.+)/expression -l swift -O -- type(of: %1)/'

這看起來更復(fù)雜了, 但還不算太糟. 這條命令的第一部分與你在前面添加的一致. 但是現(xiàn)在你在末尾添加了另外一個正則表達(dá)式. 這一個正則表達(dá)式可以捕獲所有輸入, 就像你添加的rlook命令. 這里捕獲到的所有內(nèi)容的指令很簡單叫做type(of:)用輸入的內(nèi)容作為參數(shù).
self再次執(zhí)行這條命令:

(lldb) getcls self

你會得到期望中的Signals.MasterViewController輸出. 鑒于, 你是在Swift環(huán)境下匹配的內(nèi)容, 你可以用另外一種有趣的方法使用這條命令.

(lldb) getcls self .title

注意中間有一個空格, 而且這條命令依然起作用. 這是因?yàn)槟愀嬖Vswift環(huán)境獲取除了換行符以外的所有字符.
一旦, 你完成了練習(xí)并改進(jìn)了getcls命令, 別忘了把它加到~/.lldbinit文件中.

命令正則的局限性

LLDB中的命令正則在創(chuàng)造性應(yīng)用的數(shù)量上有些限制. LLDB的命令正則有一個你只能在<subst>上應(yīng)用一個參數(shù)的限制. 這就意味著你那些支持多個參數(shù)的高級命令也逃不出這個限制.
幸運(yùn)的是, LLDB有script bridging接口 - 一個完全由Python實(shí)現(xiàn)的在調(diào)試過程中用來實(shí)現(xiàn)高級LLDB指令的功能.在后面的章節(jié)中你會深入的學(xué)習(xí)script bridging.
但是現(xiàn)在, 簡單的使用command alias或者command regex來滿足你調(diào)試的需要.

我們?yōu)槭裁匆獙W(xué)習(xí)這些?

回到本章中你已經(jīng)創(chuàng)建并添加了語法和幫助文檔的正則表達(dá)式命令.
正如前面提到的, 你將會感謝你自己提供了這些幫助文檔來提醒你之前創(chuàng)建的命令的功能.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末娜氏,一起剝皮案震驚了整個濱河市宝恶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疟暖,老刑警劉巖紊搪,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜜葱,死亡現(xiàn)場離奇詭異,居然都是意外死亡耀石,警方通過查閱死者的電腦和手機(jī)牵囤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滞伟,“玉大人揭鳞,你說我怎么就攤上這事“鹉危” “怎么了野崇?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長亩钟。 經(jīng)常有香客問我舞骆,道長,這世上最難降的妖魔是什么径荔? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮脆霎,結(jié)果婚禮上总处,老公的妹妹穿的比我還像新娘。我一直安慰自己睛蛛,他們只是感情好鹦马,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布胧谈。 她就那樣靜靜地躺著,像睡著了一般荸频。 火紅的嫁衣襯著肌膚如雪菱肖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天旭从,我揣著相機(jī)與錄音稳强,去河邊找鬼。 笑死和悦,一個胖子當(dāng)著我的面吹牛退疫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鸽素,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼褒繁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了馍忽?” 一聲冷哼從身側(cè)響起棒坏,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遭笋,沒想到半個月后坝冕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坐梯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年徽诲,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吵血。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡谎替,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蹋辅,到底是詐尸還是另有隱情钱贯,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布侦另,位于F島的核電站秩命,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏褒傅。R本人自食惡果不足惜弃锐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望殿托。 院中可真熱鬧霹菊,春花似錦、人聲如沸支竹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饶碘,卻和暖如春目尖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扎运。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工瑟曲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绪囱。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓测蹲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鬼吵。 傳聞我的和親對象是個殘疾皇子扣甲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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