一、概述
LLDB全稱 [ Low Level Debugger ], 默認內(nèi)置于Xcode中的動態(tài)調(diào)試工具。標準的 LLDB 提供了一組廣泛的命令,旨在與熟悉的 GDB 命令兼容。 除了使用標準配置外,還可以很容易地自定義 LLDB 以滿足實際需要。
語法結構
<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]
乍一看,有點懵,其實是這樣的:
<command>(命令)和<subcommand>(子命令):LLDB調(diào)試命令的名稱。
命令和子命令按層級結構來排列:一個命令對象為跟隨其的子命令對象創(chuàng)建一個上下文,子命令又為其子命令創(chuàng)建一個上下文,依此類推。
<action>:執(zhí)行命令的操作
<options>:命令選項
<arguement>:命令的參數(shù)
[]:表示命令是可選的,可以有也可以沒有
例如:
breakpoint set -n viewDidLoad
這個命令對應到上面就是:
command: breakpoint 表示斷點命令
action: set 表示設置斷點
option: -n 表示根據(jù)方法name設置斷點
arguement: viewDidLoad 表示方法名為mian
二、LLDB調(diào)試命令
調(diào)試時,添加斷點,暫停運行時,此時就可以在 Xcode 下方的控制臺使用 lldb 調(diào)試:
常用調(diào)試命令:
- 打印某個變量或對象:
po / print / p / call / e 變量名/ 對象
po 命令只是打印數(shù)值,同于 NSLog 打印對象,而 print、p、call 命令還打印了變量的類型。
如圖:
- 打印某個變量或對象:

在打印變量的值的時候,我們還可以使用 print/<fmt> 或者簡化的 p/<fmt>指定打印格式,例如打印十六進制:

p/x 變量名
x 代表十六進制格式、t 代表二進制格式,其他格式類型請點擊這里查看。
如果需查看內(nèi)存數(shù)據(jù):可以在輸出窗口采用gdb命令:x /nfu <addr>
n表示要顯示的內(nèi)存單元的個數(shù)
-----------------------------------------
f表示顯示方式, 可取如下值:
x 按十六進制格式顯示變量
d 按十進制格式顯示變量
u 按十進制格式顯示無符號整型
o 按八進制格式顯示變量
t 按二進制格式顯示變量
a 按十六進制格式顯示變量
i 指令地址格式
c 按字符格式顯示變量
f 按浮點數(shù)格式顯示變量
-----------------------------------------
u表示一個地址單元的長度:
b表示單字節(jié)
h表示雙字節(jié)
w表示四字節(jié)
g表示八字節(jié)
-------------------------------------------
例如x/16xb self
會顯示self指針地址內(nèi)容,16個字節(jié),16進制
- expression 命令(簡寫 expr/e/p)
從前面的命令列表可以看到 print、p、po、call 都是 expression 命令的簡寫,而 expression命令的作用是執(zhí)行一個表達式,并將表達式返回的結果輸出。 常用于調(diào)試時修改當前線程上變量的值,也就是說我們可以利用它們更改變量的值,而不需要修改代碼再重新編譯就可以看到效果,簡寫為 expr
例如我們將 number 的值修改為100:

也可以用于修改某屬性的值,例如:
// 修改顏色
expression self.view.backgroundColor = [UIColor purpleColor]
// 刷新界面
expression -- (void)[CATransaction flush]
也可作為打印命令:
expression -- self.view

我們知道,OC里所有的對象都是用指針表示的,所以一般打印的時候,打印出來的是對象的指針,而不是對象本身。如果我們想打印對象。我們需要使用命令選項:-O。為了更方便的使用,LLDB為expression -O --定義了一個別名:po

p (expression)也可用于調(diào)試時,動態(tài)注入代碼,像正常寫代碼一樣,比較強大的。
-
call 命令 調(diào)用某個方法
相當于在 lldb 中實時執(zhí)行所添加的代碼
例如: 調(diào)試界面時,查看某個控件的位置等,可以直接設置一下背景,而不用重新運行才能看到。
call self.topIV.backgroundColor = [UIColor orangeColor]
-
call 命令 調(diào)用某個方法
-
d 反匯編當前目標中的指定指令。
默認為當前線程和當前函數(shù)
堆棧框架??梢圆榭串斍胺椒ǖ膮R編代碼,包括:內(nèi)存地址、所占字節(jié)、匯編指令等,無意間發(fā)現(xiàn)的。(應該是 dis 命令的簡寫)
如圖:
-
d 反匯編當前目標中的指定指令。

- image 命令
由于LLDB給 target modules 取了個別名 image,所以 target modules lookup 這個命令我們又可以寫成 image lookup。
- (1)image lookup --address/a 尋址,定位異常代碼位置
當我們有一個地址,想查找這個地址具體對應的文件位置,可以使用 image lookup --address ,簡寫為 image lookup -a

當程序崩潰的時候,可以通過 image lookup --address 內(nèi)存地址,來精確定位崩潰的具體位置,很實用。
例如:
NSString *testStr = @"12345";
NSString *subString = [testStr substringToIndex:10];

運行越界崩潰:

具體的調(diào)用堆棧信息居然沒有,很神奇吧?但是不同非凡的 Me 兩次居然就找到了,呵呵

- (2)image lookup –name
當我們想查找一個方法或者符號的信息,比如所在文件位置等。我們可以使用image lookup --name,簡寫為image lookup -n。
適用于查找同名方法,不只是自己寫的方法, 系統(tǒng)的和第三方的 .a 都可以搜索得到,而工程中的搜索是辦不到的,
例如,隨便找的:

- (3)image lookup --type查看類型
當我們想查看一個類型的時候,可以使用image lookup --type,簡寫為image lookup -t:
定義代碼如下:
@interface ViewController ()
{
NSString *address;
float height;
}
/** Description */
@property (nonatomic, copy) NSString *name;
/** Description */
@property (nonatomic, assign) int age;
@end
打印信息如下:

可以看到,LLDB把 ViewController 這個class的所有屬性和成員變量都打印了出來,當我們想了解某個類的時候,直接使用image lookup -t即可
image list 查看項目所調(diào)用的庫,第一個為Mach-o 其余為相關的庫,相當于 Windows 的鏡像。
-
- thread 查看線程堆棧信息
- thread backtrace & bt 查看堆棧調(diào)用,效果是一樣的,如下:

- up 查看上一步的堆棧調(diào)用信息,如下:

down 查看下一步的堆棧調(diào)用信息,類似 up
frame select 編號,跳轉至指定堆棧查看,源碼和匯編(系統(tǒng)的或打包的),定位某個方法的具體實現(xiàn)。

堆棧信息的編號,指定查看:

- frame variable 查看方法的所有參數(shù)。

注:三個參數(shù)因為 OC 中每個方法默認都有的兩個隱式參數(shù),第三個才為我們傳的參數(shù),此時也可以通過 p 修改相關的數(shù)據(jù)。
修改,上面的 up 和 down 只是查看,thread return 則是讓代碼回滾到上一步返回,也不會執(zhí)行,相當于代碼中的 return。
-
breakpoint 斷點(代碼斷點)
斷點可能是在我們調(diào)試過程中用的最多的功能了,但是我們不一定都了解斷點的各種用法。
-
breakpoint 斷點(代碼斷點)
手動打斷點時:
- 斷點的編輯,如:
1.設置觸發(fā)條件

這個功能也比較實用,調(diào)試過程中,可以跟蹤數(shù)據(jù)或界面等的變化,自動觸發(fā)。
-
設置觸發(fā)事件,可以看到有以下幾種:
image.png
-
可以試一下,探索一下。
斷點 lldb 調(diào)試命令:
- breakpoint set 設置斷點
- 使用-n根據(jù)方法名給當前類設置斷點:
breakpoint set -n viewWillAppear:
給 viewWillAppear 方法設置一個斷點:
set 是子命令
-n 是選項 是--name 的縮寫!
- 使用-n根據(jù)方法名給指定類多個方法設置斷點:
breakpoint set -n "-[ViewController save:]" -n "-[ViewController continueGame:]" -n "-[ViewController pauseGame:]"
注意:"" 和參數(shù)的 :,簡寫 b -n 方法名,或 b 方法名
b -n "-[ViewController touchesBegan:withEvent:]"
b pauseGame:
- 給整個項目某個指定方法設置斷點:
breakpoint set --selector 方法名
如:給 touchesBegan:withEvent: 設置斷點
breakpoint set --selector touchesBegan:withEvent:
包含系統(tǒng)的方法,
- 使用-f指定文件和方法
breakpoint set -f ViewController.m -n viewDidAppear:
給ViewController.m文件中的viewDidAppear 方法設置斷點:
注意方法后面的 :冒號,不添加無效果。
shift +Command + j 調(diào)轉至當前類文件處
- 使用-l指定文件某一行設置斷點
breakpoint set -f ViewController.m -l 33
在 ViewController.m 的 33 行設置一個斷點。
breakpoint set --file ViewController.m --selector touchesBegan:withEvent:
給 ViewController.m 的 touchesBegan:withEvent: 方法添加斷點。
這些都可以通過上面手動來添加,只不過是兩種方式罷了。
給某個內(nèi)存地址設置斷點
b -a 地址
查看斷點列表
$breakpoint list刪除
breakpoint delete 刪除所有斷點
$breakpoint delete 組號(一組的斷點)
breakpoint delete 組分號
breakpoint delete 1.1 不會刪除該斷點,會禁用該斷點禁用/啟用
breakpoint disable 禁用
簡寫:break dis
breakpoint enable 啟用
簡寫:break en
禁用某一個斷點
breakpoint disable 4.1
- 遍歷整個項目中的所有方法包含 Game: 這個字符的所有方法
breakpoint set -r Game:
流程控制
繼續(xù)執(zhí)行
$continue c單步運行,將子函數(shù)當做整體一步執(zhí)行
$n next-
單步運行,遇到子函數(shù)會進去
$s- lldb 調(diào)試時,按住 control 進入?yún)R編指令,流程控制。
watchpoint 內(nèi)存斷點
- watchpoint 內(nèi)存斷點,查看某個值的變化。

watchpoint delete 刪除內(nèi)存斷點
同 breakpoint 用法。break command add 斷點編號,執(zhí)行至該斷點時做相應操作。
如下:

執(zhí)行結果:

- break command delete 4
- break command list
同 breakpoint 用法。
stop-hook
讓你在每次stop的時候去執(zhí)行一些命令,(除了Debug 控制臺中的暫停和 Debug View hierarchy 查看)只對breadpoint,watchpoint 有效。
- 添加一條斷點指令,打印變量,只要程序停止就會執(zhí)行。
target stop-hook add -o "frame variable"
-o one line 一行 感覺像輸出 -output 簡寫
- 查看方法實現(xiàn),僅限于在源碼中調(diào)試
target stop-hook add -o "frame select"
"" 中可以添加任意想要查看的 指令,eg: p ...
每次 stop 時,結果如下:

- 查看所有的 stop-hook 指令
target stop-hook list

刪除 stop-hook 指令
刪除指定標號的
target stop-hook delete 1
刪除所有的
target stop-hook delete
有一點特殊的:
undisplay 3
移除指定標號的 stop-hook 指令同 delete
同 breakpoint 用法,help target stop-hook 查看相關的命令。
.lldbinit
以上都是在 lldb 調(diào)試時,手動添加配置指令。
- 自動配置
在用戶目錄下找到 .lldbinit 文件,沒有的話就新建一個,可以添加一條指令測試一下,如下:
target stop-hook add -o "frame variable"
注:用 Mac 的文本編輯工具創(chuàng)建編輯后保存不要使用任何格式,多信息的會有很多附加的設置信息,如:


這樣就可以實現(xiàn)斷點無須手動輸入指令查看,但是 .lldbinit 一般用于導入配置文件,更能方便的使用 LLDB 的功能。

常用命令
- p
- b -[xxx xxx]
- x memory read 的縮寫
- register read
- po
- image list
注:其實上面的所有命令,都可以通過 help 命令查看其相關的所有指令及用法,
如:thread help 就可以查看 thread 相關的所有命令
直接在 lldb 中 help 就可以看到所有的可操作的功能的列表和一些當前基本的命令
如下:
(lldb) help
Debugger commands:
apropos -- List debugger commands related to a word or subject.
breakpoint -- Commands for operating on breakpoints (see 'help b' for
shorthand.)
bugreport -- Commands for creating domain-specific bug reports.
command -- Commands for managing custom LLDB commands.
disassemble -- Disassemble specified instructions in the current
target. Defaults to the current function for the
current thread and stack frame.
expression -- Evaluate an expression on the current thread. Displays
any returned value with LLDB's default formatting.
frame -- Commands for selecting and examing the current thread's
stack frames.
gdb-remote -- Connect to a process via remote GDB server. If no host
is specifed, localhost is assumed.
gui -- Switch into the curses based GUI mode.
help -- Show a list of all debugger commands, or give details
about a specific command.
kdp-remote -- Connect to a process via remote KDP server. If no UDP
port is specified, port 41139 is assumed.
language -- Commands specific to a source language.
log -- Commands controlling LLDB internal logging.
memory -- Commands for operating on memory in the current target
process.
platform -- Commands to manage and create platforms.
plugin -- Commands for managing LLDB plugins.
process -- Commands for interacting with processes on the current
platform.
quit -- Quit the LLDB debugger.
register -- Commands to access registers for the current thread and
stack frame.
script -- Invoke the script interpreter with provided code and
display any results. Start the interactive interpreter
if no code is supplied.
settings -- Commands for managing LLDB settings.
source -- Commands for examining source code described by debug
information for the current target process.
target -- Commands for operating on debugger targets.
thread -- Commands for operating on one or more threads in the
current process.
type -- Commands for operating on the type system.
version -- Show the LLDB debugger version.
watchpoint -- Commands for operating on watchpoints.
Current command abbreviations (type 'help command alias' for more info):
add-dsym -- Add a debug symbol file to one of the target's current modules
by specifying a path to a debug symbols file, or using the
options to specify a module to download symbols for.
attach -- Attach to process by ID or name.
b -- Set a breakpoint using one of several shorthand formats.
bt -- Show the current thread's call stack. Any numeric argument
displays at most that many frames. The argument 'all' displays
all threads.
c -- Continue execution of all threads in the current process.
call -- Evaluate an expression on the current thread. Displays any
returned value with LLDB's default formatting.
continue -- Continue execution of all threads in the current process.
detach -- Detach from the current target process.
di -- Disassemble specified instructions in the current target.
Defaults to the current function for the current thread and
stack frame.
dis -- Disassemble specified instructions in the current target.
Defaults to the current function for the current thread and
stack frame.
display -- Evaluate an expression at every stop (see 'help target
stop-hook'.)
down -- Select a newer stack frame. Defaults to moving one frame, a
numeric argument can specify an arbitrary number.
env -- Shorthand for viewing and setting environment variables.
exit -- Quit the LLDB debugger.
f -- Select the current stack frame by index from within the current
thread (see 'thread backtrace'.)
file -- Create a target using the argument as the main executable.
finish -- Finish executing the current stack frame and stop after
returning. Defaults to current thread unless specified.
image -- Commands for accessing information for one or more target
modules.
j -- Set the program counter to a new address.
jump -- Set the program counter to a new address.
kill -- Terminate the current target process.
l -- List relevant source code using one of several shorthand formats.
list -- List relevant source code using one of several shorthand formats.
n -- Source level single step, stepping over calls. Defaults to
current thread unless specified.
next -- Source level single step, stepping over calls. Defaults to
current thread unless specified.
nexti -- Instruction level single step, stepping over calls. Defaults to
current thread unless specified.
ni -- Instruction level single step, stepping over calls. Defaults to
current thread unless specified.
p -- Evaluate an expression on the current thread. Displays any
returned value with LLDB's default formatting.
parray -- Evaluate an expression on the current thread. Displays any
returned value with LLDB's default formatting.
po -- Evaluate an expression on the current thread. Displays any
returned value with formatting controlled by the type's author.
poarray -- Evaluate an expression on the current thread. Displays any
returned value with LLDB's default formatting.
print -- Evaluate an expression on the current thread. Displays any
returned value with LLDB's default formatting.
q -- Quit the LLDB debugger.
r -- Launch the executable in the debugger.
rbreak -- Sets a breakpoint or set of breakpoints in the executable.
repl -- Evaluate an expression on the current thread. Displays any
returned value with LLDB's default formatting.
run -- Launch the executable in the debugger.
s -- Source level single step, stepping into calls. Defaults to
current thread unless specified.
si -- Instruction level single step, stepping into calls. Defaults to
current thread unless specified.
sif -- Step through the current block, stopping if you step directly
into a function whose name matches the TargetFunctionName.
step -- Source level single step, stepping into calls. Defaults to
current thread unless specified.
stepi -- Instruction level single step, stepping into calls. Defaults to
current thread unless specified.
t -- Change the currently selected thread.
tbreak -- Set a one-shot breakpoint using one of several shorthand
formats.
undisplay -- Stop displaying expression at every stop (specified by stop-hook
index.)
up -- Select an older stack frame. Defaults to moving one frame, a
numeric argument can specify an arbitrary number.
x -- Read from the memory of the current target process.
For more information on any command, type 'help <command-name>'.
命令很多,要查看某一個相關,可以繼續(xù) help , 熟悉熟悉,就會發(fā)現(xiàn)新大陸。
不常用調(diào)試命令:
apropos -- 列出與單詞或主題相關的調(diào)試器命令
breakpoint -- 在斷點上操作的命令 (詳情使用'help b'查看)
bugreport -- 用于創(chuàng)建指定域的錯誤報告
command -- 用于管理自定義LLDB命令的命令
disassemble -- 拆分當前目標中的特定說明。 默認為當前線程和堆棧幀的當前函數(shù)
expression -- 求當前線程上的表達式的值。 以LLDB默認格式顯示返回的值
frame -- 用于選擇和檢查當前線程的堆棧幀的命令
gdb-remote -- 通過遠程GDB服務器連接到進程。 如果未指定主機,則假定為localhost
gui -- 切換到基于curses的GUI模式
help -- 顯示所有調(diào)試器命令的列表,或提供指定命令的詳細信息
kdp-remote -- 通過遠程KDP服務器連接到進程。 如果沒有指定UDP端口,則假定端口41139
language -- 指定源語言
log -- 控制LLDB內(nèi)部日志記錄的命令
memory -- 用于在當前目標進程的內(nèi)存上操作的命令
platform -- 用于管理和創(chuàng)建平臺的命令
plugin -- 用于管理LLDB插件的命令
process -- 用于與當前平臺上的進程交互的命令
quit -- 退出LLDB調(diào)試器
register -- 命令訪問當前線程和堆棧幀的寄存器
script -- 使用提供的代碼調(diào)用腳本解釋器并顯示任何結果。 如果沒有提供代碼,啟動交互式解釋器。
settings -- 用于管理LLDB設置的命令
source -- 檢查當前目標進程的調(diào)試信息所描述的源代碼的命令
target -- 用于在調(diào)試器目標上操作的命令
thread -- 用于在當前進程中的一個或多個線程上操作的命令
type -- 在類型系統(tǒng)上操作的命令
version -- 顯示LLDB調(diào)試器版本
watchpoint -- 在觀察點上操作的命令
add-dsym -- ('target symbols add') 通過指定調(diào)試符號文件的路徑,或使用選項指定下載符號的模塊,將調(diào)試符號文件添加到目標的當前模塊中的一個
attach -- ('_regexp-attach') 通過ID或名稱附加到進程
b -- ('_regexp-break') 使用幾種簡寫格式之一設置斷點
bt -- ('_regexp-bt') 顯示當前線程的調(diào)用堆棧。通過數(shù)字參數(shù)設置最多顯示幀數(shù)。參數(shù)“all”顯示所有線程
c -- ('process continue') 繼續(xù)執(zhí)行當前進程中的所有線程
call -- ('expression --') 計算當前線程上的表達式,使用LLDB的默認格式顯示返回的值
continue -- ('process continue') 繼續(xù)執(zhí)行當前進程中的所有線程
detach -- ('process detach') 脫離當前目標進程
di -- ('disassemble') 拆分當前目標中的特定說明。 默認為當前線程和堆棧幀的當前函數(shù)
dis -- ('disassemble') 同上
display -- ('_regexp-display') 在每次停止時計算表達式(請參閱'help target stop-hook')
down -- ('_regexp-down') 選擇一個新的堆棧幀。默認為移動一個幀,數(shù)字參數(shù)可以指定值
env -- ('_regexp-env') 查看和設置環(huán)境變量的簡寫
exit -- ('quit') 退出LLDB調(diào)試器
f -- ('frame select') 從當前線程中通過索引選擇當前堆棧幀(參見'thread backtrace')
file -- ('target create') 使用參數(shù)作為主要可執(zhí)行文件創(chuàng)建目標
finish -- ('thread step-out') 完成當前堆棧幀的執(zhí)行并返回后停止。 默認為當前線程
image -- ('target modules') 用于訪問一個或多個目標模塊的信息的命令
j -- ('_regexp-jump') 將程序計數(shù)器設置為新地址
jump -- ('_regexp-jump') 同上
kill -- ('process kill') 終止當前目標進程
l -- ('_regexp-list') 使用幾種簡寫格式之一列出相關的源代碼
list -- ('_regexp-list') 同上
n -- ('thread step-over') 源級單步執(zhí)行、步進調(diào)用,默認當前線程
next -- ('thread step-over') 同上
nexti -- ('thread step-inst-over') 指令級單步執(zhí)行、步進調(diào)用,默認當前線程
ni -- ('thread step-inst-over') 同上
p -- ('expression --') 計算當前線程上表達式的值,以LLDB默認格式顯示返回值
parray -- ('expression -Z %1 --') 同上
po -- 計算當前線程上的表達式。顯示由類型作者控制的格式的返回值。
poarray -- ('expression -O -Z %1 --') 計算當前線程上表達式的值,以LLDB默認格式顯示返回值
print -- ('expression --') 同上
q -- ('quit') 退出LLDB調(diào)試器
r -- ('process launch -X true --') 在調(diào)試器中啟動可執(zhí)行文件
rbreak -- ('breakpoint set -r %1') 在可執(zhí)行文件中設置斷點或斷點集
repl -- ('expression -r -- ') E計算當前線程上表達式的值,以LLDB默認格式顯示返回值
run -- ('process launch -X true --') 在調(diào)試器中啟動可執(zhí)行文件
s -- ('thread step-in') 源級單步執(zhí)行、步進調(diào)用,默認當前線程
si -- ('thread step-inst') 指令級單步執(zhí)行、步進調(diào)用,默認當前線程
sif -- 遍歷當前塊,如果直接步入名稱與TargetFunctionName匹配的函數(shù),則停止
step -- ('thread step-in') 源級單步執(zhí)行、步進調(diào)用,默認當前線程
stepi -- ('thread step-inst') 指令級單步執(zhí)行、步進調(diào)用,默認當前線程
t -- ('thread select') 更改當前選擇的線程
tbreak -- ('_regexp-tbreak') 使用幾種簡寫格式之一設置單次斷點
undisplay -- ('_regexp-undisplay') 每次停止時停止顯示表達式(由stop-hook索引指定)
up -- ('_regexp-up') 選擇較早的堆棧幀。 默認為移動一個幀,數(shù)值參數(shù)可以指定任意數(shù)字
x -- ('memory read') 從當前目標進程的內(nèi)存中讀取
寫這個小結也參考了大牛一些優(yōu)秀的文章, 非常感謝,共同學習。
這是一位曾經(jīng)供職于百度的技術大牛伯樂在線的個人主頁,文章受益匪淺。
