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 v
是frame 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 i
是watchpoint 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