LLDB (Low Level Debugger) 轻量级高性能调试器,掌握 LLDB 可以有效的提升 Debug 能力,提高工作效率。
一、常用命令
对象操作 (p/po/e/call)
NSArray *array = @[@"a", @"b", @"b", @"c"];
//(lldb) p array
//(__NSArray0 *) $3 = 0x00007fff8db5c830 @"0 elements"
//(lldb) p array = @[@"a"]
//(__NSSingleObjectArrayI *) $4 = 0x00000001005013b0 @"1 element"
// (lldb) po array
//<__NSArrayI 0x1006022f0>(
//a,
//b,
//b,
//c
//)
ZSan *zsan = [[ZSan alloc] init];
zsan->_no = 1;
//(lldb) e zsan->_no = 2;
// (int) $2 = 2
lldb
中 p
打印对象的描述信息,包括类型,指针地址等信息;po
打印的是对象的详细信息。
po
同时也可以修改对象信息,e
可以修改对象中属性的值,call
可以让对象执行方法。
p/po/e/call
都可以打印对象的信息。
函数操作 (bt/frame/image)
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 断点处
NSArray *array = @[@"a", @"b", @"b", @"c"];
}
return 0;
}
// (lldb) bt
// * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
// * frame #0: 0x0000000100000d58 BLBaseNSObject`main(argc=1, argv=0x00007ffeefbff4f8) at main.m:122:22
// frame #1: 0x00007fff6c55e7fd libdyld.dylib`start + 1
// frame #2: 0x00007fff6c55e7fd libdyld.dylib`start + 1
//(lldb) frame select 0
//frame #0: 0x0000000100000d58 BLBaseNSObject`main(argc=1, argv=0x00007ffeefbff4f8) at main.m:122:22
// 119
// 120 NSArray *array = @[@"a", @"b", @"b", @"c"];
// 121
//-> 122 NSLog(@"%@", array);
// ^
// 123 }
// 124 return 0;
// 125 }
bt(backtrace)
打印当前调用堆栈(crash堆栈);frame
打印函数调用详情以及调用顺序;image
打印栈地址对应的代码。
frame selecte 0
可以查看当前函数调用的信息,通过 up
和 down
可以追踪函数的调用和被调用关系。
frame variable
很方便的查方法的调用者及方法名称。
image lookup -a 地址
这个方法主要用于寻址,常用与在崩溃的时候,查找崩溃地址对应的文件代码的位置。
当项目遇到崩溃的时候同时利用 bt
跟 image loopup -a 地址
可以更好的找到问题。
属性&变量操作 (watchpoint)
有时候我们开发过程中会遇到类似的问题,有一些属性或者变量值发生了变化,但是不知道具体是哪里开始发生的变化,导致最后的结果与我们预期有了出入。
这里就可以使用 watchpoint
来监听我们的属性或者变量。
ZSan *zsan = [[ZSan alloc] init];
zsan.ccc = 10;
zsan.ccc = 1000;
//(lldb) watchpoint set variable zsan->_ccc
//Watchpoint created: Watchpoint 1: addr = 0x100555c30 size = 4 state = enabled type = w
// declare @ '/Users/Charlyliu/Desktop/学习项目/OC/BLBaseNSObject/BLBaseNSObject/main.m:108'
// watchpoint spec = 'zsan->_ccc'
// new value: 0
//
//Watchpoint 1 hit:
//old value: 0
//new value: 10
//(lldb) pt
//error: 'pt' is not a valid command.
//(lldb) bt
//* thread #1, queue = 'com.apple.main-thread', stop reason = watchpoint 1
// * frame #0: 0x0000000100001a70 BLBaseNSObject`-[ZSan setCcc:](self=0x0000000100555c10, _cmd="setCcc:", ccc=10) at main.m:60:35
// frame #1: 0x0000000100001c69 BLBaseNSObject`main(argc=1, argv=0x00007ffeefbff4f8) at main.m:114:14
// frame #2: 0x00007fff6c55e7fd libdyld.dylib`start + 1
// frame #3: 0x00007fff6c55e7fd libdyld.dylib`start + 1
//(lldb) n
//(lldb) bt
//* thread #1, queue = 'com.apple.main-thread', stop reason = step over
// * frame #0: 0x0000000100001c69 BLBaseNSObject`main(argc=1, argv=0x00007ffeefbff4f8) at main.m:120:111
// frame #1: 0x00007fff6c55e7fd libdyld.dylib`start + 1
// frame #2: 0x00007fff6c55e7fd libdyld.dylib`start + 1
//(lldb) c
//Process 36061 resuming
//2019-12-27 13:40:11.600731+0800 BLBaseNSObject[36061:1628481] 测试多层继承关系成员变量大小的内存对齐逻辑---40
//2019-12-27 13:40:11.601062+0800 BLBaseNSObject[36061:1628481] 测试多层继承关系内存分配---48
//
//Watchpoint 1 hit:
//old value: 10
//new value: 1000
//(lldb) bt
//* thread #1, queue = 'com.apple.main-thread', stop reason = watchpoint 1
// * frame #0: 0x0000000100001a70 BLBaseNSObject`-[ZSan setCcc:](self=0x0000000100555c10, _cmd="setCcc:", ccc=1000) at main.m:60:35
// frame #1: 0x0000000100001cd5 BLBaseNSObject`main(argc=1, argv=0x00007ffeefbff4f8) at main.m:123:14
// frame #2: 0x00007fff6c55e7fd libdyld.dylib`start + 1
// frame #3: 0x00007fff6c55e7fd libdyld.dylib`start + 1
//(lldb) image lookup 0x0000000100001a70
//error: invalid combination of options for the given command
//(lldb) image lookup -a 0x0000000100001a70
// Address: BLBaseNSObject[0x0000000100001a70] (BLBaseNSObject.__TEXT.__text + 64)
// Summary: BLBaseNSObject`-[ZSan setCcc:] + 32 at main.m:60:35
//(lldb)
-
watchpoint set variable zsan->_ccc
注意,这里的zsan->_ccc
不能使用点语法,这条命令主要是监听属性地址,如果其地址内保存的值发生变化就会走进断点,而点语法实际上是调用的getter
方法。 -
watchpoint set variable testInt
设置变量观察,testInt
变量发生改变后触发。 -
watchpoint set expression -- 0x000000010f46c070
设置内存观察。 -
watchpoint list / watch l
当前所有观察列表。 -
watchpoint modify -c 'testInt == 2'
设置条件触发观察。 -
watchpoint delete 2
删除对应的观察。
这里我们可以配合 bt
堆栈信息使用,当发现值变化的时候可以查阅堆栈信息定位修改代码的位置。
内存操作 (memory/x {read/write})
ZSan *zsan = [[ZSan alloc] init];
zsan->_no = 1;
zsan->_num = 1;
zsan->_age = 18;
//(lldb) memory read zsan
//0x1007009a0: 21 23 00 00 01 80 1d 00 01 00 00 00 01 00 00 00 !#..............
//0x1007009b0: 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
// 表示修改 0x1007009a8 后的值,将其值修改为 4;根据刚才获取内存信息可知,从 0x1007009a8 地址之后是 _no 的值,值位 0x01,这里我们将其修改成为 0x04,也就是 zsan->_no = 4
//(lldb) memory write 0x1007009a8 4
//(lldb) po zsan->_no
//4
memory read
可以用 x
代替,使用起来更方便,用法 memory read/数量格式字节数 读取对象/或某个具体的内存地址
或者 x/数量格式字节数 读取对象/或某个具体的内存地址
。
/
后各个字段描述:
- 数量,表示读取从该对象起始地址或该内存地址起始地址后多长的地址
- 格式
-
x
是16
进制 -
f
是浮点 -
d
是10
进制
-
- 字节数
-
b
:byte 1
字节 -
h
:half word 2
字节 -
w
:word 4
字节 -
g
:giant word 8
字节
-
举例:读取 szan
对象地址,要求以 8
个字节,用 16
进制格式读取 4
组数据。
x/4xg szan
或者 x/4xg 0x10055d610
,其中 0x10055d610
是 szan
对象的地址。
memory write 地址 修改后的数据
,通过 write
可以修改内存中的数据。
断点操作 (breakpoind/b)
Xcode
工具为我们提供了断点调试的功能,为什么还要使用这个命令呢?LLDB
的断点使用起来速度更快,功能更全面。
0. 流程控制
-
c/continue
继续执行,跳到下一个断点或者没有断点程序执行完毕 -
next/n(step-over)
单步运行,将子函数当做整体一步运行 -
stepi/s(step-in)
单步运行,遇到子函数会进入 -
finish(step-out)
如果进入一个子函数,则可以通过这个方法退出子函数
1. 增删查
-
set
添加断点-
-a {内存地址}
根据函数地址打断点(常用与逆向) -
-n {xxx:}
设置方法名断点breakpoint/b set -n login:
-
-n { [Class xxxx]}
根据对应的类设置该类的方法名断点(可多个:一组)breakpoint/b set -n "-[Class1 xxx]" -n "-[Class2 xxx]"
-
-l {lineNumber}
根据行号设置断点 -
-f {fileName}
根据文件名中的信息设置断点 -
-F {函数全名}
根据函数全名打断点 -
-r {部分函数名}
根据部分函数名打断点 -
-N{别名}
给断点添加别名
-
-
delete {breakpoint_num}
删除一个断点 -
list {breakpoint_num}
列举指定断点信息,breakpoint_num
可选 -
enable/disable {breakpoint_num}
启用或禁用某个/某组断点 -
commond
执行一些特殊命令-
add {breakpoint_num} {特殊命令(如p/po/bt等)}
断点执行后执行一些特殊LLDB
操作 -
delete{breakpoint_num}
删除某个断点添加的特殊操作
-
2. 条件、命令
-
-i {number}
设置断点忽略次数 -
-o
只断住一次 -
-c {条件(类似数据库where操作)}
设置断点条件
其他操作
-
methods
命令可以打印当前对象的属性和方法 -
previews
命令可以打印当前视图的层级结构 -
help
获取帮助信息,查看更多LLDB
命令
网友评论