LLDB 常用命令总结

LLDB 是 Xcode 的默认调试器,支持在桌面和 iOS 设备和模拟器上调试 C,Objective-C 和 C ++。此文总结常用的一些 LLDB 命令。

查看命令 print && po && v && frame variable

查看打印变量的值可以使用print、po、v 和 frame variable 命令。如果打印的是简单类型,print、v 、frame variable 命令会列出简单类型的类型和值,po 只会打印值;如果是对象,会打印出对象指针地址,在 func 方法中设置断点,分别查看他们的值。如果想一次查看所有的变量值,输入frame variable命令即可。frame vframe variable的简写,执行命令效果相同。

// 在 func 方法中设置断点
- (void)func{
NSInteger a = 8;
NSString *aStr = @"xyzm";
NSObject *aObj = [[NSObject alloc] init];
}

分别使用 LLDB 的 print、po 和 v 命令效果如下:

(lldb) print a
(NSInteger) $0 = 8
(lldb) print aStr
(__NSCFConstantString *) $1 = 0x000000010027a368 @"xyzm"
(lldb) print aObj
(NSObject *) $2 = 0x0000000170016350
(lldb) po a
8

(lldb) po aStr
xyzm

(lldb) po aObj
<NSObject: 0x170016350>

(lldb) v a
(NSInteger) a = 8
(lldb) v aStr
(__NSCFConstantString *) aStr = 0x000000010027a368 @"xyzm"
(lldb) v aObj
(NSObject *) aObj = 0x0000000170016350
(lldb) frame variable
(GMViewController *) self = 0x0000000102009d20
(SEL) _cmd = "func"
(NSInteger) a = 8
(__NSCFConstantString *) aStr = 0x000000010027a368 @"xyzm"
(NSObject *) aObj = 0x0000000170016350
(lldb) frame variable a
(NSInteger) a = 8
(lldb) frame variable aStr
(__NSCFConstantString *) aStr = 0x000000010027a368 @"xyzm"
(lldb) frame variable aObj
(NSObject *) aObj = 0x0000000170016350

修改命令 expression

程序员在自测调试的过程中,需要经常改变变量的值,以测试多种逻辑。通过改变代码的方式,需要每次打包,耗时耗力,使用 LLDB 的 expression 命令就简单了许多。在 Debug 调试的过程中,通过expression 变量名=新值的方式动态改变内存里面的变量。

例如如下代码常见,cardID 是后台返回的标识,值为 AA,执行逻辑 A;不重新打包,我们想执行逻辑 B 怎么办?在 if 逻辑判断处打断点,执行exp cardID=@"BB"即可修改 cardID 的值为 BB,执行逻辑 B。e 和 exp 是 expression 的简写,执行命令效果相同。

- (void)func{
NSString *cardID = @"AA";
if ([cardID isEqualToString:@"AA"]) {
NSLog(@"执行逻辑 A");
}else{
NSLog(@"执行逻辑 B");
}
}

执行 exp 命令,修改 cardID 的值:

(lldb) v cardID
(__NSCFConstantString *) cardID = 0x00000001002023a8 @"AA"
(lldb) exp cardID=@"BB"
(NSTaggedPointerString *) $0 = 0xa000000000042422 @"BB"
(lldb) v cardID
(NSTaggedPointerString *) cardID = 0xa000000000042422 @"BB"

当然,expression 作用不仅如此,例如新建对象,修改界面,调用函数等等。

(lldb) exp [self.view setBackgroundColor:[UIColor lightGrayColor]];
(lldb) exp [self.view setBackgroundColor:[UIColor greenColor]];
(lldb) exp @import UIKit
(lldb) exp (void)[self testFunc]
(lldb) exp id $vc = [UIViewController new]
(lldb) exp (void)[[$vc view] setBackgroundColor:[UIColor yellowColor]]

设置条件断点 watchpoint

调试的过程中,可能要持续监测某一变量,例如 for 循环 100 次,我们需要在第 50 次断点,我们在 for 循环内部打一个断点。

for (NSInteger i = 0; i < 100; i++) {
// 循环内部任意执行逻辑
NSInteger temp = 50;
temp = 51;
}

监测变量 i 的值,在 i=50 的时候停止执行。执行watch set v i watchpoint modify -c '(i==50)'即可。其中watch set v iwatchpoint set variable i的简写。

(lldb) watch set v i
Watchpoint created: Watchpoint 1: addr = 0x16fd45958 size = 8 state = enabled type = w
declare @ '/Users/lifei/Desktop/GitHub/GMObjC/Example/GMObjC/GMViewController.m:84'
watchpoint spec = 'i'
new value: 0

(lldb) watchpoint modify -c '(i==50)'

Watchpoint 1 hit:
old value: 0
new value: 50

其实,还有更简单的方法,Xcode 很强大,在断点上右键选择 Edit Breakpoint…,然后在 Condition 输入框输入 i==50 即可。

其他命令

列举其他一些不太常用的命令,例如 image、thread 等,作为了解。

frame info                       当前的行数和源码文件,以及其他一些信息
thread backtrace all             查看所有线程调用栈
thread list                      列出所有线程
thread return <exp>              可用来控制程序流程, 伪造返回值
image list                       查看工程中使用的库
image lookup --address 0x0000000100004af8   最后为栈地址
breakpoint set --file foo.c --line 12       在程序 foo.c 的第 12 行设置断点
image lookup --type NSURL        image lookup命令来查看具体的类型
lldb ~/Desktop/App.app           在命令行中可执行 lldb 命令加载 app
run                              启动程序,app 需要支持 x86 模拟器
q                                退出lldb

参考链接

The LLDB Debugger