iOS調試 - LLDB

開發iOS的時候常常會用到調試跟蹤,如何正確的使用調試器來debug十分重要。
Xcode里有內置的Debugger,老版使用的是GDB,Xcode自4.3之后默認使用的就是LLDB了。

GDB: UNIX及UNIX-like下的調試工具。

LLDB: 開源的內置于XCode的具有REPL(read-eval-print-loop)特征的Debugger,其可以安裝C++或者Python插件。

兩個都是調試用的Debugger,只是LLDB是比較高級的版本,或者在調試開發iOS應用時比較好用,lldb與gdb命令名的對照表:http://lldb.llvm.org/lldb-gdb.html

開始使用LLDB

在什么地方可以輸入這個命令?
首先, 在程序里你需要的地方設置斷點。
當斷點斷住的時候你就能看到我們進入LLDB調試器了。

這時就可以使用一些LLDB命令來進行一些調試了。

一些Xcode調試快捷鍵:
command+shift+Y 打開調試窗口
command+Y 調試運行程序
command+option+P 繼續
command+shift+O 跳過
command+shift+I 進入
command+shift+T 跳出

常用命令

<li>help</li>

最簡單命令 help 會列舉出所有的命令。如果你忘記了一個命令是做什么的,或者想知道更多的話,你可以通過 help <command> 來了解更多細節,例如 help print 或者 help thread。


<li>print</li>

試試 print 命令:



LLDB 實際上會作前綴匹配。所以你也可以使用 prin,pri,或者 p。但你不能使用 pr,因為 LLDB 不能消除和 process 的歧義。

結果中有個 $0。實際上你可以使用它來指向這個結果。試試 print $0 + 7,你會看到 106。任何以美元符開頭的東西都是存在于 LLDB 的命名空間的,它們是為了幫助你進行調試而存在的。

輸出view 下 subview 的數量

//由于 subview 的數量是一個 int 類型的值,所以我們使用命令p:
(lldb)p (int)[[[self view] subviews] count]

直接調用方法改變背景顏色之類

其實使用p,po,call都可以調用方法,只是p和po都是用于輸出的有返回值的。call一般只在不需要顯示輸出,或是方法無返回值時使用。
(lldb)p [self.view setBackgroundColor:[UIColor redColor]]
(lldb)p (void)[CATransaction flush]
上述的p一般使用call比較好,因為方法是沒有返回值的。

<li>p objects</li>

命令p objects跟p很像。p輸出的是基本類型,po輸出的Objective-C對象。調試器會輸出這個 object 的 description。
po (print object 的縮寫):


<li>expression</li>

如果想改變一個值怎么辦?其實這時候我們要用到的是 expression 這個方便的命令。
expression的簡寫就是e??梢杂胑xpression來聲明新的變量,也可以改變已有變量的值。我們看到e聲明的都是$開頭的變量。我們在使用時也需要加上$符號。

創建新的變量示例:



注意:如果上面這里輸入以下命令,會發生錯誤。說明lldb無法判定某一步的計算結果是什么數據類型,這時需要強制類型轉換來告訴lldb。

(lldb) p [[$array objectAtIndex:0] characterAtIndex:0]
error: no known method '-characterAtIndex:'; cast the message send to the method's return type
error: 1 errors parsing expression

(lldb) p (char)[[$array objectAtIndex:0] characterAtIndex:0]
'o'

修改已有變量示例:


<li>image</li>

image 命令可用于尋址,有多個組合命令。
比較實用的用法是用于尋找棧地址對應的代碼位置。
如:

NSArray *arr=[[NSArray alloc] initWithObjects:@"1",@"2", nil];
NSLog(@"%@",arr[2]);

這段代碼有明顯的錯誤,程序運行這段代碼后會拋出下面的異常:

 *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
(
 0   CoreFoundation                      0x0000000101951495 __exceptionPreprocess + 165
 1   libobjc.A.dylib                     0x00000001016b099e objc_exception_throw + 43
2   CoreFoundation                      0x0000000101909e3f -[__NSArrayI objectAtIndex:] + 175
3   ControlStyleDemo                    0x0000000100004af8 -[RootViewController viewDidLoad] + 312
4   UIKit                               0x000000010035359e -[UIViewController loadViewIfRequired] + 562
5   UIKit                               0x0000000100353777 -[UIViewController view] + 29
6   UIKit                               0x000000010029396b -[UIWindow addRootViewControllerViewIfPossible] + 58
7   UIKit                               0x0000000100293c70 -[UIWindow _setHidden:forced:] + 282
8   UIKit                               0x000000010029cffa -[UIWindow makeKeyAndVisible] + 51
9   ControlStyleDemo                    0x00000001000045e0 -[AppDelegate application:didFinishLaunchingWithOptions:] + 672
10  UIKit                               0x00000001002583d9 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 264
11  UIKit                               0x0000000100258be1 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1605
12  UIKit                               0x000000010025ca0c -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 660
13  UIKit                               0x000000010026dd4c -[UIApplication handleEvent:withNewEvent:] + 3189
14  UIKit                               0x000000010026e216 -[UIApplication sendEvent:] + 79
15  UIKit                               0x000000010025e086 _UIApplicationHandleEvent + 578
16  GraphicsServices                    0x0000000103aca71a _PurpleEventCallback + 762
17  GraphicsServices                    0x0000000103aca1e1 PurpleEventCallback + 35
18  CoreFoundation                      0x00000001018d3679 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
19  CoreFoundation                      0x00000001018d344e __CFRunLoopDoSource1 + 478
20  CoreFoundation                      0x00000001018fc903 __CFRunLoopRun + 1939
21  CoreFoundation                      0x00000001018fbd83 CFRunLoopRunSpecific + 467
22  UIKit                               0x000000010025c2e1 -[UIApplication _run] + 609
23  UIKit                               0x000000010025de33 UIApplicationMain + 1010
24  ControlStyleDemo                    0x0000000100006b73 main + 115
25  libdyld.dylib                       0x0000000101fe95fd start + 1
26  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

現在,我們懷疑出錯的地址是0x0000000100004af8(可以根據執行文件名判斷,或者最小的棧地址)。為了進一步精確定位,我們可以輸入以下的命令:

(lldb)image lookup --address 0x0000000100004af8
(lldb)im loo -a 0x0000000100004af8

命令執行后返回:

Address: ControlStyleDemo[0x0000000100004af8] (ControlStyleDemo.__TEXT.__text + 13288)
Summary: ControlStyleDemo`-[RootViewController viewDidLoad] + 312 at RootViewController.m:53

可以看到,出錯的位置是<code>RootViewController.m</code>的第53行。

<li>call</li>

call即是調用的意思。其實上述的po和p也有調用的功能。
因此一般只在不需要顯示輸出,或是方法無返回值時使用call。
和上面的命令一樣,我們在viewDidLoad:里面設置斷點,然后在程序中斷的時候輸入下面的命令:

call [self.view setBackgroundColor:[UIColor redColor]]

繼續運行程序,看看view的背景顏色是不是變成紅色的了!
在調試的時候靈活運用call命令可以起到事半功倍的作用。

<li>bt</li>

打印調用堆棧,加all可打印所有thread的堆棧。

<li>流程控制命令</li>

實際上使用xcode自帶的可視化工具來控制“繼續”“暫停”“下一步”“進入”“跳出”更簡單,但這里還是列出其所對應的命令名:

繼續:process continue, continue, c

下一步:thread step-over, next, n

進入:thread step-in, step, s

跳出:thread step-out, finish, f

<li>thread return</li>

執行thread return命令可以使得當前函數立即返回,也就是說,后續代碼都不會執行了。當然執行此命令可能會使得arc的計數追蹤出現錯亂。

thread return命令需要一個參數來指明函數強制返回時的返回值。

<li>斷點命令</li>

斷點有很多進階使用方法:條件斷點、條件執行、記錄日志、自動繼續、重復斷點跳過。
使用xcode提供的可視化工具來操作是很容易的:


<li>調試中執行任意代碼</li>

(lldb) e char *$str = (char *)malloc(128)
(lldb) e (void)strcpy($str, "wxrld of warcraft")
(lldb) e $str[1] = 'o'
(char) $0 = 'o'
(lldb) p $str
(char *) $str = 0x00007fd04a900040 "world of warcraft"
(lldb) e (void)free($str)

所以,在debugger中可以修改view的顏色、尺寸、甚至創建controller來push。

<li>watchpoint</li>

watchpoint可以在某個變量被寫入/讀取時暫停程序運行:

(lldb) watchpoint set expression -- (int*)&_abc4
Watchpoint created: Watchpoint 7: addr = 0x15e36d3c size = 4 state = enabled type = w
    new value: 0x00000000
(lldb) watchpoint set v -w read _abc4
Watchpoint created: Watchpoint 8: addr = 0x15e36d3c size = 4 state = enabled type = r
    watchpoint spec = '_abc4'
    new value: 0
(lldb) watchpoint set v -w read_write _abc3
Watchpoint created: Watchpoint 9: addr = 0x15e36d38 size = 4 state = enabled type = rw
    watchpoint spec = '_abc3'
    new value: 0

實際上可以使用watchpoint來監視任意一段內存的讀寫。
使用XCode也可以方便地創建watchpoint。

XCode的可視化debug工具中的watch是一個write類型watchpoint(也就是默認的)

另外,上述語句中 v是variable的簡寫,同樣的,set可以簡寫為s,watch可以簡寫為wa,而-w后面的參數是不可以簡寫的必須為read、write或者read_write。

當前在arm和x86上,我們一次最多創建4個watchpoint,繼續創建會提示錯誤。

<li>查看內存</li>

使用XCode的可視化工具來查看memory,要注意watch memory of "p" 和watch memory of "*p"的區別。

手動執行命令可以help x或者 help memory。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容

  • [轉]淺談LLDB調試器文章來源于:http://www.cocoachina.com/ios/20150126/...
    loveobjc閱讀 2,549評論 2 6
  • Xcode的使用中總是離不開調試這個環境,在一年多的iOS開發時間中,我更多地依賴于XCode本身提供的GUI工具...
    王小明if閱讀 17,551評論 8 94
  • 轉載 與調試器共舞 - LLDB 的華爾茲: https://objccn.io/issue-19-2/ 推薦:i...
    F麥子閱讀 3,349評論 0 10
  • 前言 今天花了一天的時間終于把iOS的幾種常見的調試方法給學習了一下,在這里給大家分享一下LLDB的使用,同時也是...
    Peak_One閱讀 11,073評論 5 33
  • 被陰冷啟蒙 那一池的清澄 輸給了不絕的寒風 瑟瑟的冷 是被嚴冬同化的余生聲 風本無依 自無所系 不了解它的秘密 就...
    琴歌素簡閱讀 208評論 0 0