lldb的Xcode默認的調試器,它與LLVM編譯器一起,帶給我們更豐富的流程控制和數據檢測的調試功能。平時用Xcode運行程序,實際走的都是lldb。熟練使用lldb,可以讓你debug事半功倍
lldb 用法
首先在應用程序內打斷點。
接下來一個一個的去介紹和使用。-
apropos :調試器命令列表相關的詞或主題
語法:apropos <search-word>
作用:輸出你想要搜索的關鍵詞的相關內容。
例子:apropos log
結果:apropos.png -
breakpoint :命令操作斷點
語法:breakpoint <subcommand> [<command-options>]
作用:可以通過命令來對斷點進行增加、刪除等操作。
一些子命令如下:
1、clear:刪除或禁用斷點匹配指定的源文件和行。
2、command:命令添加,刪除和清單LLDB命令在遇到斷點時執行。
3、delete:刪除指定的斷點(s)。如果沒有斷點指定,刪除它們。
4、disable:禁用指定斷點(s),而不刪除它們。如果沒有指定,禁用所有斷點。
5、enable:使指定的禁用斷點(s)。如果沒有斷點指定,使所有的人。
6、list:列舉一些或所有斷點配置的詳細級別。
7、modify:修改選項斷點或設置的斷點可執行文件。如果沒有指定斷點,作用于最后創建斷點。
8、name:命令來管理斷點的名字標簽
9、set:設置一個斷點或設置斷點的可執行文件。
例子:通過 breakpoint 來添加、刪除以及查找斷點。
查看當前斷點列表

紅色框框里面表示斷點的行數。可以看出來現在也就只有2個斷點,一個在73行,一個在80行。
- 添加一個95行的斷點
breakpoint set -f ViewController.m -l 95
-f 后面的是文件名 -l 后面是行數
- 再次查看當前斷點列表

- 刪除 80 行的斷點
breakpoint clear -f ViewController.m -l 80
- 結果列表中就沒有 80 行的斷點信息了。

bugreport :命令來創建特定于域的bug報告
語法:bugreport <subcommand> [<subcommand-options>]
作用:創建一份 bug 報告
例子:
bug report unwind XXX(XXX 是你想看的方法名)
結果會輸出一堆東西。you can try!-
command :管理自定義命令LLDB命令(創建別名)
語法:command <subcommand> [<subcommand-options>]
一些子命令:
1、alias:定義一個自定義命令
2、delete:刪除一個或多個自定義命令的命令
3、history:當前執行的歷史命令
4、regex:定義一個現有命令的自定義命令
5、script:來管理自定義命令實現的腳本解釋器
6、source:從文件讀取和執行命令LLDB
7、unalias:刪除一個或多個自定義命令定義為“命令別名”
例子:
想知道你執行 LLDB 幾條命令,輸入
command history
還有個實用的例子:
比如上面的添加斷點命令過長,那么我們可以這樣做。
command alias bkt breakpoint set -f %1 -l %2
然后再添加斷點。
bkt ViewController.m 90
你看結果會發現已經添加上了,是不是很方便?
別名添加斷點.png
如果不想要這個別名了就可以執行下列命令把它給刪除。
command unaries but -
disassemble :拆卸指定的指令
語法:disassemble [<cmd-options>]
例子:
disassemble -b
這樣會顯示你當前斷點所在的方法內所有的操作碼字節。
效果:
操作碼字節.png
紅色框內的信息能更好的幫助你調試程序。
如果你想拆卸某一行可以用下面的命令:
disassemble -c 84(這個數字就是你想要拆卸的行數,當然了他會聯系上下文給你拆卸這個對象的信息) expression (我用到的: 修改程序中的代碼)
場景:假設你程序運行后發現有個視圖的背景顏色不好看,需要改,好吧,在代碼中改一下,再運行。發現不好看,再改。這樣太過麻煩,但是我們可以用 expression 來實現,代碼:
expression imageView.backgroundColor = [UIColor redColor]
然后再運行你就會發現這個視圖的顏色變成紅色了。不止顏色,一些數值也是可以改的。-
frame 命令選擇與當前線程的堆棧幀
子命令:
1、info:列表當前堆棧幀在當前的信息線程
2、select:選擇當前堆棧框架內通過索引當前線程
3、variable:顯示變量當前堆棧幀。默認為所有參數和局部變量的范圍
效果:
frame效果圖.png
1中,箭頭表示的是你斷點所在的位置
后面的就是你所寫的代碼
2中,有你當前所在的類的名字,所在方法的方法名以及一些創建的對象
3中,就是列舉方法名,行數,類名等信息。
根據自己的喜好選擇相應的命令。 quit 退出當前的LLDB。
register 訪問當前線程的寄存器和堆棧幀
子命令:
1、read:讀取當前的寄存器值當前幀
2、write:修改一個寄存器值settings 管理 LLDB 的設置
子命令:
1、append:將值附加到調試器里面。數組、字典或者字符串設置。
2、clear:清除調試器
3、insert-after:在指定的元素的索引,將一個或多個值插入一系列調試器設置
4、insert-before:在指定的元素的索引,立刻將一個或多個值插入一系列調試器設置
5、list:調試器列表
6、remove:移除設置
7、replace:替換設置中的值
8、set:設置指定的調試器的設置值
9、show:顯示調試器設置和他們目前的值。source 檢查源代碼所描述的調試信息當前目標的過程
子命令:
1、info:顯示一行信息來源為當前目標的過程。默認為當前堆棧幀中指令指針
2、list:顯示指定的當前目標過程的源代碼-
thread 操作在一個或多個線程在當前過程
子命令:
1、backtrace:顯示線程調用堆棧。默認為當前可以指定線程,線程索引作為參數。使用thread-index看到所有線程。
2、continue:繼續執行當前目標的過程。
3、info:顯示一個擴展的總結一個或多個線程。
4、jump:將程序計數器設置為一個新的地址。
5、list:顯示每個線程在當前目標的總結的過程。
6、plan:管理線程控制計劃執行。
7、return:返回從堆棧幀,短路執行更新的框架和選擇屈服指定的值。
8、select:更改當前選中的線程。
9、step-in:進入調用
10、step-init:單步調用
11、step-ints-over:單步,跨過調用。
12、step-out:執行完當前堆棧幀并停止之后返回。
13、step-over:單步,跨過調用。
14、step-scripted:C中選擇的腳本類。
15、until:到達到行號或地址當前或指定的線程,停止時返回從當前函數作為一種安全措施。
例子:
thread info
當前線程的信息.png -
type 命令操作的類型系統
子命令:- 1??、category:操作類型分類
- define:定義一個新的類別
- delete:刪除一個類別
- disable:禁用一個類別
- enable:啟用一個類別
- list:現有的類別的列表
- 2??、filter:操作類型過濾器
- add:添加一個新的過濾器的類型
- clear:刪除所有現有的過濾器
- delete:刪除現有的濾波器類型
- list:顯示當前過濾器的列表
- 3??、format:自定義值顯示格式
- add:添加一個新的格式類型
- clear:刪除所有現有的格式樣式
- delete:刪除現有的格式風格類型
- info:評估提供的表達式和顯示格式應用于結果值
- list:顯示當前的列表格式
- 4??、lookup:當前查找類型和聲明
- 5??、summary:編輯變量匯總
- add:添加一個新的匯總的風格類型
- clear:刪除所有現有的總結
- delete:刪除現有的一種總結類型
- info:評估提供的表達式和顯示總結應用結果值
- list:顯示當前的列表格式
- 6??、synthetic:操作合成類型
- add:添加一個新類型合成提供者
- clear:刪除所有的類型
- delete:刪除現有的一種合成類型
- info:評估提供的表達式和顯示總結應用結果值
- list:顯示當前的列表格式
- 1??、category:操作類型分類
version 顯示調試器LLDB版本
-
watchpoint 操作檢查點,檢查內存的讀寫。
- 1??、command:添加,刪除和檢查LLDB命令當監視點
- add:添加一組命令LLDB監視點
- delete:刪除監視點
- list:監視點成功的列表
- 2??、delete:刪除指定的監視點
- 3??、disable:禁用指定的監視點,而不刪除它
- 4??、enable:使指定的禁用的監視點
- 5??、ignore:設置忽略依靠指定的監視點
- 6??、list:列出所有監測點配置的表
- 7??、modify:在監視點或者設置監測點上修改可執行文件,如果沒有指定監視點,就傳遞一個空參數做修改。
- 8??、set:設置監視點
例子:
創建一個監視點
watchpoint set expression -- a(這個a 在代碼中是 int a = 0;)
會輸出這樣的信息
Watchpoint created: Watchpoint 1: addr = 0x00000000 size = 8 state = enabled type = w
分別為:監視點的代號,內存地址,大小,狀態和類型。
再添加個對這個 a 的讀寫檢測
watchpoint set variable -w read_write a
則會輸出
- 1??、command:添加,刪除和檢查LLDB命令當監視點
Watchpoint created: Watchpoint 3: addr = 0x7fff54ed67c4 size = 4 state = enabled type = rw
declare @ '/Users/XXX/Desktop/Demozz/Demozz/ViewController.m:89'
watchpoint spec = 'a'
new value: 0
比上面的輸出相比,多了以下幾點改變
1、監視點的代號、內存地址、大小、類型都變了。
2、增加了declare(狀態聲明)
3、增加了監視點的規范
4、增加了輸出這個檢查的變量的值。
那我們打印一些監視點的列表
watchpoint list
則輸出
Number of supported hardware watchpoints: 4
Current watchpoints:
Watchpoint 1: addr = 0x00000000 size = 8 state = enabled type = w
Watchpoint 3: addr = 0x7fff54ed67c4 size = 4 state = enabled type = rw
declare @ '/Users/miya-shaocong/Desktop/Demozz/Demozz/ViewController.m:89'
watchpoint spec = 'a'
new value: 0
如果我們想刪除一個監視點,只需要把代號給提交過去就好了。
watchpoint delete 1
想刪除全部的話,就這樣
watchpoint delete
它會讓你確認
About to delete all watchpoints, do you want to do that?: [Y/n]
然后你輸入 Y 確定就好了。
- po 顯示任何返回值與控制的格式類型
- 變量
比如你想看某個變量的值,不需要在代碼中添加log,直接斷點到那個地方,然后 po 變量名,就會輸出你想要看到值
- 變量
(lldb) po b
100
- 坐標
比如你想看到某個視圖的坐標以及大小信息,那就直接 po 這個視圖的frame。
(lldb) po self.view.frame
(origin = (x = 0, y = 0), size = (width = 375, height = 667))
你還可以嘗試輸出其他(你想要看的東西)。
- print 更詳細的輸出,(包括類型)
(lldb) print a
(int) $5 = 0
(lldb) print b
(int) $6 = 100
(lldb) print self.view
(UIView *) $7 = 0x00007fd183d04cf0
(lldb) print self.view.frame
(CGRect) $8 = (origin = (x = 0, y = 0), size = (width = 375, height = 667))
$X 這種是命令結果的引用名,我們可以用于任何其他表達式或者接收參數的命令。
比如:
(lldb) print $5 + 109
(int) $9 = 109
// ---
(lldb) po $8
(origin = (x = 0, y = 0), size = (width = 375, height = 667))
- next 直接跨過當前的斷點,跳到下一個斷點位置,并輸出斷點所在的行數。
- run 重新啟動程序。
- kill 終止當前的程序
-
可視化工具操作
第一步:右鍵斷點,然后選擇Edit Breakponit
第二步:
Xcode可視化工具.png
第三步:運行到斷點看結果
結果.png