设置断点:
breakpoint set
使用breakpoint
的子命令 set
设置断点
具体信息可以通过help breakpoint set
查询所有可选的选项(options)以及参数(arguments).
下面使用之前的可执行文件Greeter
介绍一些常用的方法:
- 按方法名称设置--name(-n):
(lldb) breakpoint set -n greet
Breakpoint 2: where = Greeter`Greeter.Greeter.greet(personNamed: Swift.String) -> () + 127 at Greeter.swift:9:12, address = 0x00000001000034cf
- 按行数设置--line(-l):
(lldb) breakpoint set -l 18
Breakpoint 3: where = Greeter`main + 14 at Greeter.swift:18:15, address = 0x000000010000315e
- 按文件设置--file(-l):
(lldb) breakpoint set -f Greeter.swift -l 20
Breakpoint 6: where = Greeter`main + 34 at Greeter.swift:20:1, address = 0x0000000100003172
- 根据语言捕获异常--language-exception(-E):
(lldb) breakpoint set -E Objc
Breakpoint 7: no locations (pending).
可以通过--exception-typename(-O) 指定要捕获的异常类型:
(lldb) breakpoint set -E Swift -O EnumErrorType
Breakpoint 8: no locations (pending).
获取断点列表:
breakpoint list
(lldb) breakpoint list
Current breakpoints:
1: name = 'sayHello', locations = 0 (pending)
2: name = 'greet', locations = 1
2.1: where = Greeter`Greeter.Greeter.greet(personNamed: Swift.String) -> () + 127 at Greeter.swift:9:12, address = Greeter[0x00000001000034cf], unresolved, hit count = 0
3: file = '/Users/jackli/Desktop/Roborock/Greeter.swift', line = 18, exact_match = 0, locations = 1
3.1: where = Greeter`main + 14 at Greeter.swift:18:15, address = Greeter[0x000000010000315e], unresolved, hit count = 0
4: file = 'main.swift', line = 20, exact_match = 0, locations = 0 (pending)
5: file = 'Greet.swift', line = 20, exact_match = 0, locations = 0 (pending)
6: file = 'Greeter.swift', line = 20, exact_match = 0, locations = 1
6.1: where = Greeter`main + 34 at Greeter.swift:20:1, address = Greeter[0x0000000100003172], unresolved, hit count = 0
7: Exception breakpoint (catch: off throw: on) the correct runtime exception handler will be determined when you run
8: Swift Error breakpoint the correct runtime exception handler will be determined when you run
需要注意的是: 设置断点其实是设置了逻辑断点, 可能会对应一个或多个位置断点(location).
每个逻辑断点都有一个按照顺序从1开始分配的整型ID. 每一个位置断点又有一个自己的位置ID, 与逻辑断点的ID之间以.
分隔, 用于定位位置断点. 示例如下:
2: name = 'greet', locations = 1
2.1: where = Greeter`Greeter.Greeter.greet(personNamed: Swift.String) -> () + 127 at Greeter.swift:9:12, address = Greeter[0x00000001000034cf], unresolved, hit count = 0
逻辑断点是动态的, 如果程序载入了新的代码, 会自动载入新的位置断点.
修改断点:
breakpoint modify
使用这个命令修改逻辑断点或者位置断点, 需要传递逻辑断点或者位置断点的ID 作为参数, 具体参数可以通过help breakpoint modify
查看.
部分常用选项如下:
--condition(-c)
传入表达式参数, 只有表达式判断为true
才会执行断点.ignore-count(-i)
指定跳过断点的次数, 在该断点处跳过指定次数后, 才会执行该断点.--one-shot(-o)
执行断点一次后移除该断点.--queue-name(-q)
指定队列名称, 该断点只有在指定队列上才会执行.--thread-name(-T)
指定线程名称, 该断点只有在指定的线程上才会执行.--thread-id(-t)
指定线程ID(TID), 该断点只有在指定的线程上才会执行.--thread-index(-x)
指定线程index, 该断点只有在指定的线程上才会执行.
如下示例修改了断点ID为1的断点, 指定其在执行后,自动移除.
(lldb) breakpoint modify --one-shot 1
很多选项在breakpoint set
中就可以被指定的, 通过modify
可以重新修改选项.
在断点处执行命令
我们都知道, 当程序抵达断点处时, 程序会暂停执行, 此时可以执行lldb
命令.
我们也可以通过执行breakpoint command add
命令, 让程序每次抵达断点处时, 自动执行我们添加的命令. 如:
在位置断点1.1处添加指令, 每行可以添加一个指令, Enter
跳转至下一指令, 输入DONE
结束添加.
(lldb) breakpoint command add 1.1
Enter your debugger command(s). Type 'DONE' to end.
> thread backtrace
> DONE
可以将process continue
作为最后一个指令, 那么调试器就会在执行指令后, 自动继续执行程序, 这在记录Log的场景下使用是非常方便的.
(lldb) target create "Greeter"
Current executable set to (x86_64).
(lldb) breakpoint list
No breakpoints currently set.
(lldb) breakpoint set -n greet
Breakpoint 1: where = Greeter`Greeter.Greeter.greet(personNamed: Swift.String) -> () + 127 at Greeter.swift:9:12, address = 0x00000001000034cf
(lldb) breakpoint command add 1
Enter your debugger command(s). Type 'DONE' to end.
> frame variable
> process continue
(lldb) process launch
Process 5997 launched: (x86_64)
// 下面的frame variable 和 process continue 都是自动执行的.
(lldb) frame variable
(String) name = "Anton"
(Greeter.Greeter) self = 0x0000000100304540 {
acquaintances = 0 values {}
}
(lldb) process continue
Process 5997 resuming
Command #2 'process continue' continued the target.
Hello, Anton. Nice to meet you!
(lldb) frame variable
(String) name = "Mei"
(Greeter.Greeter) self = 0x0000000100304540 {
acquaintances = 1 value {
[0] = "Anton"
}
}
(lldb) process continue
Process 5997 resuming
Command #2 'process continue' continued the target.
Hello, Mei. Nice to meet you!
(lldb) frame variable
(String) name = "Anton"
(Greeter.Greeter) self = 0x0000000100304540 {
acquaintances = 2 values {
[0] = "Anton"
[1] = "Mei"
}
}
(lldb) process continue
Process 5997 resuming
Command #2 'process continue' continued the target.
Hello again, Anton!
Process 5997 exited with status = 0 (0x00000000)
设置断点可用状态(Diable/Enable)
禁用断点: breakpoint disable
启用断点: breakpoint enable
以上命令都需要指定断点ID参数(支持通配符).
当逻辑断点设置为diable时, 它下方的所有位置断点都将不再生效.
(lldb) breakpoint disable 1
1 breakpoints disabled.
(lldb) breakpoint disable 2.1
1 breakpoints disabled.
(lldb) breakpoint enable 1
1 breakpoints enabled.
(lldb) breakpoint enable 2.1
1 breakpoints enabled.
还可用通配符*
指定断点.
如下示例先是禁用了逻辑断点1下的所有位置断点, 而后启用了位置断点1.1
(lldb) breakpoint disable 1.*
2 breakpoint disabled*
(lldb) breakpoint enable 1.1
1 breakpoint enabled.
删除断点
(lldb) breakpoint delete 1
1 breakpoints deleted; 2 breakpoint locations disabled.
设置监视点(Watchpoint)
监视点(Watchpoint) 是一种设置在地址或者变量上的断点. 每次地址或变量被访问时就会执行.
监视点的数量收到硬件寄存器数量的显示.
可以通过watchpoint set variable
设置变量断点, 或者通过watchpoint set expression
传入返回地址的表达式参数设置地址断点.
(lldb) watchpoint set variable places
Watchpoint created: Watchpoint 1: addr = 0x100004a40 size = 8 state = enabled type = w
declare @ 'main.swift:7'
watchpoint spec = 'places'
new value: 1 value
(lldb) watchpoint set expression -- (int *)$places + 8
Watchpoint created: Watchpoint 2: addr = 0x100005f33 size = 8 state = enabled type = w
new value: 0x0000000000000000
获取监视点列表
watchpoint list
(lldb) watchpoint list
Current watchpoints:
Watchpoint 1: addr = 0x100004a50 size = 8 state = disabled type = w
declare @ 'main.swift:7'
watchpoint spec = 'places'
修改监视点
watchpoint modify
和 breakpoint modify
类似, 修改监视点的信息.
(lldb) watchpoint modify --condition !places.isEmpty
1 watchpoints modified.
在监视点处执行命令
watchpoint command add
和 breakpoint command add
类似, 在监视点出添加需要执行的命令.
(lldb) watchpoint command add 1
Enter your debugger command(s). Type 'DONE' to end.
> bt
> DONE
删除监视点
由于监视点数量受到硬件条件限制, 在不再需要它的时候将其删除是很重要的.
(lldb) watchpoint delete 1
1 watchpoints deleted.