LLDB闡述
LLDB 是一個有著 REPL 的特性和 C++ ,Python 插件的開源調(diào)試器。LLDB 綁定在 Xcode 內(nèi)部岳链,存在于主窗口底部的控制臺中花竞。調(diào)試器允許你在程序運行的特定時暫停它,你可以查看變量的值掸哑,執(zhí)行自定的指令约急,并且按照你所認(rèn)為合適的步驟來操作程序的進(jìn)展。(摘自與調(diào)試器共舞)
它的基本語法為
[[...]][-options [option-value]] [argument [argument...]]
在XCode中苗分,我們需要在程序暫停進(jìn)入調(diào)試狀態(tài)時才能使用LLDB厌蔽,可以通過breakpoint、watchpoint摔癣、或者XCode的調(diào)試臺自帶的暫停按鈕使程序暫停奴饮。
快捷鍵
為了方便查詢,就直接在文章開頭po出常用的快捷鍵菜單把~
快捷鍵功能命令
暫停/繼續(xù)cmd + ctrl + Y
控制臺顯示/隱藏cmd + Y
光標(biāo)切換到控制臺cmd + shift + C
清空控制臺cmd + K
step overF6
step intoF7
step outF8
HELP
LLDB的入門與Linux命令入門類似择浊,可以通過執(zhí)行help命令來查詢這個命令的意義和詳細(xì)參數(shù)
從描述中我們能看出thread backtrace是用來查詢暫停時的線程堆棧的戴卜,并了解了可以帶入的入?yún)ⅰ?/p>
唯一匹配原則
LLDB有個很省事的特性,如果輸入的字母已經(jīng)能匹配到某個命令琢岩,就可以直接執(zhí)行投剥,等于輸入了完整的命令。
可以看到expression與e是等價的
變量查詢與修改
expression
expression可簡寫為e担孔,作用為執(zhí)行一個表達(dá)式江锨,首當(dāng)其沖,它肯定可以用來查詢當(dāng)前堆棧變量的值糕篇。
當(dāng)然e的更主要的用法是通過執(zhí)行表達(dá)式啄育,動態(tài)修改當(dāng)前線程堆棧變量的值,從而達(dá)到調(diào)試的目的(其實查詢也很主要拌消,只是會用另一種方式查詢)挑豌。
比如,我們可以在某個if..else..的語句前打上斷點,直接修改條件表達(dá)式的值浮毯,使程序覆蓋了不同分支完疫,而不用苦心積慮地停止程序、hard code變量值來進(jìn)行調(diào)試债蓝,節(jié)省了一大坨修改與編譯時間壳鹤。
在上面這份測試代碼,在進(jìn)入條件判斷語句前打了斷點饰迹,那我們可以通過e命令芳誓,來自由控制程序走向任何一個分支。
我們也可以通過執(zhí)行表達(dá)式啊鸭,實時改變當(dāng)前的UI界面锹淌,方便界面代碼的調(diào)試,比如我們可以執(zhí)行下面代碼來改變當(dāng)前UI赠制,讓cellItem的邊框顯示出來赂摆,以判斷我們的界面布局是否正確。
e @importUIKite cellItem.layer.borderWidth=1
這里有個特殊的問題钟些,由于程序已經(jīng)被斷點暫停了烟号,因此執(zhí)行UI更新的線程也被暫停了。我們可以通過讓程序繼續(xù)運行政恍,也可以通過另一條表達(dá)式來更新UI汪拥。
e (void)[CATransactionflush]
我們也可以用call來代替expression --,其實我覺得用e更方便篙耗。 =迫筑。=
p、po
在上面說過宗弯,在調(diào)試中脯燃,我們一般用e命令來修改變量,而查詢變量一般用p與po命令罕伯。
po的作用為打印對象曲伊,事實上,我們可以通過help po得知追他,po是expression -O ?--的簡寫,我們可以通過它打印出對象岛蚤,而不是打印對象的指針邑狸。而值得一提的是,在help expression返回的幫助信息中涤妒,我們可以知道单雾,po命令會嘗試調(diào)用對象的description方法來取得對象信息,因此我們也可以重載某個對象的description方法,使我們調(diào)試的時候能獲得可讀性更強(qiáng)硅堆,更全面的信息屿储。
-(NSString*)description{return[NSStringstringWithFormat:@"Portal[%@, %@, %@, %@, %@, %@, %@]", ssid, mpUrl, ticket, authUrl, _openid, _tid, extend];}
p即是print,也是expression --的縮寫渐逃,與po不同够掠,它不會打出對象的詳細(xì)信息,只會打印出一個$符號茄菊,數(shù)字疯潭,再加上一段地址信息。由于po命令下面殖,對象的description有可能被隨便亂改竖哩,沒有輸出地址消息。
$符號在LLDB中代表著變量的分配脊僚。每次使用p后相叁,會自動為你分配一個變量,后面再次想使用這個變量時辽幌,就可以直接使用钝荡。我們可以直接使用這個地址做一些轉(zhuǎn)換,獲取對象的信息
斷點
breakpoint
所有調(diào)試都是由斷點開始的舶衬,我們接觸的最多埠通,就是以breakpoint命令為基礎(chǔ)的斷點。
一般我們對breakpoint命令使用得不多逛犹,而是在XCode的GUI界面中直接添加斷點端辱。除了直接觸發(fā)程序暫停供調(diào)試外,我們可以進(jìn)行進(jìn)一步的配置虽画。
添加condition舞蔽,一般用于多次調(diào)用的函數(shù)或者循壞的代碼中,在作用域內(nèi)達(dá)到某個條件码撰,才會觸發(fā)程序暫停
忽略次數(shù)渗柿,這個很容易理解,在忽略觸發(fā)幾次后再觸發(fā)暫停
添加Action脖岛,為這個斷點添加子命令朵栖、腳本、shell命令柴梆、聲效(有個毛線用)等Action陨溅,我的理解是一個腳本化的功能,我們可以在斷點的基礎(chǔ)上添加一些方便調(diào)試的腳本绍在,提高調(diào)試效率门扇。
自動繼續(xù)雹有,配合上面的添加Action,我們就可以不用一次又一次的暫停程序進(jìn)行調(diào)試來查詢某些值(大型程序中斷一次還是會有卡頓)臼寄,直接用Action將需要的信息打印在控制臺霸奕,一次性查看即可。
除去在代碼中直接點擊添加斷點外吉拳,我們也可以在command + 7breakpoint頁面下直接添加相關(guān)的斷點质帅。我們常用的有 Exception Breakpoint 與 Symbolic Breakpoint
Add Exception Breakpoint
Exception Breakpoint為異常斷點。在某些情況下合武,TableView的數(shù)據(jù)源與UI操作不一致临梗,或者容器插入了nil的指針,將消息傳至野指針稼跳,都會導(dǎo)致程序的crash盟庞,并且LLDB輸出的信息不是很友好。加上異常斷點汤善,能夠使程序在拋出異常的棧自動暫停什猖,可直接定位導(dǎo)致拋出異常的代碼。在一般的開發(fā)流程中红淡,都建議開啟這個異常斷點不狮,反正你總是會crash的嘿嘿。
Add Symbolic Breakpoint
Symbolic Breakpoint 為符號斷點在旱。有時候摇零,我們并不清楚程序會在什么情況下調(diào)用某一個函數(shù),那我們可以通過符號斷點來獲取調(diào)用該函數(shù)時的程序堆棧桶蝎。當(dāng)然驻仅,在自己實現(xiàn)的類,我們也可以在該函數(shù)實現(xiàn)的地方打上斷點登渣,但如果需要定位其他框架提供的API的調(diào)用噪服,就只能使用符號斷點啦。
當(dāng)然胜茧,LLDB的breakpoint命令也可以實現(xiàn)上述的功能粘优,因為不常用,所以這里就簡單列舉一些用法呻顽。 ?breakpoint set -n trigger //在所有類的trigger函數(shù)實現(xiàn)中打上斷點
breakpointset-fViewController.m-ntrigger//在ViewController.m中的trigger方法打上斷點 ?breakpointset-fViewController.m-l50//在ViewController.m的50行打上斷點 ?breakpointset-fViewController.m-ntrigger: -ctestCondition >5//在ViewController.m中的trigger方法打上斷點并添加condition雹顺, testCondition大于5時觸發(fā)斷點 ?breakpointset-ntrigger-o //單次斷點 ?breakpoint commandadd-o"frame info"3//在設(shè)置的三號斷點加入子命令frame info ?breakpointlist// 列出所有斷點 ?breakpointdelete3//刪除3號斷點
watchpoint
有時候我們會關(guān)心類的某個屬性什么時候被人修改了,最簡單的方法當(dāng)然就是在setter的方法打斷點芬位,或者在@property的屬性生命行打上斷點无拗。這樣當(dāng)對象的setter方法被調(diào)用時,就會觸發(fā)這個斷點昧碉。
當(dāng)然這么做是有缺點的英染,對于直接訪問內(nèi)存地址的修改,setter方法的斷點并沒有辦法監(jiān)控得到被饿,因此我們需要用到watchpoint命令四康。
watchpoint命令在XCode的GUI中也可以直接使用,當(dāng)程序暫停時狭握,我們能對當(dāng)前程序棧中的變量設(shè)置watchpoint闪金。值得注意的是,watchpoint是直接設(shè)置到該變量所在的內(nèi)存地址上的论颅,所以當(dāng)這個變量釋放了后哎垦,watchpoint仍然是對這個地址的內(nèi)存生效的。
我們也可以在LLDB中直接用watchpoint命令恃疯,可以通過選項實現(xiàn)更多效果漏设。
watchpoint setself->testVar//為該變量地址設(shè)置watchpointwatchpoint set expression0x00007fb27b4969e0//為該內(nèi)存地址設(shè)置watchpoint,內(nèi)存地址可從前文提及的`p`命令獲取watchpoint command add -o'frame info'1//為watchpoint 1號加上子命令 `frame info`watchpointlist//列出所有watchpointwatchpoint delete// 刪除所有watchpoint
堆棧
thread和bt
bt即是thread backtrace今妄,作用是打印出當(dāng)前線程的堆棧信息郑口。當(dāng)程序發(fā)生了crash后,我們可以用該命令打印出發(fā)生crash的當(dāng)前的程序堆棧盾鳞,查詢出發(fā)生crash的調(diào)用路徑犬性。由于比較常用,所以LLDB直接給它一個特殊的bt別名腾仅。
thread另一個比較常用的用法是thread return乒裆,調(diào)試的時候,我們希望在當(dāng)前執(zhí)行的程序堆棧直接返回一個自己想要的值推励,可以執(zhí)行該命令直接返回鹤耍。
threadreturn
在這個斷點中,我們可以執(zhí)行thread return NO讓該函數(shù)調(diào)用直接返回NO吹艇,在調(diào)試中輕松覆蓋任何函數(shù)的返回路徑惰蜜。
frame
frame即是幀,其實就是當(dāng)前的程序堆棧受神,我們輸入bt命令抛猖,打印出來的其實是當(dāng)前線程的frame。
在調(diào)試中鼻听,一般我們比較關(guān)心當(dāng)前堆棧的變量值财著,我們可以使用frame variable來獲取全部變量值。當(dāng)然也可以輸入特定變量名撑碴,來獲取單獨的變量值撑教,如frame v self-> testVar來獲取testVar的值。
End
原文鏈接:http://www.reibang.com/p/d6a0a5e39b0e