LLDB 快速入门

如果调试是删除 bug 的过程,那么编程就是引入 bug 的过程。

—— Edsger W. Dijkstra


LLDB 是什么?

LLDB( Low level Debug )是 MacOS 默认进行调试 C/C++ 程序的调试工具,能帮开发者进行更加丰富地流程控制和栈帧数据监测。

简言之,LLDB 是一个有着 REPL 的特性和 C++ 、Python 插件的开源调试器。

在此,我们以几个简单的程序为例子,对 LLDB 进行快速入门。

目录

  • 启动 LLDB

  • 断点操作

    • 设置断点
    • 查看断点
    • 删除断点
  • 分步调试

    • 启动调试
    • 进入,跳过和继续
    • 跳出当前函数
  • 查看变量

  • 结束调试

启动 LLDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// demo.cpp
#include <iostream>

using namespace std;

int fact(int n) {
if (n == 0) {
return 1;
}
else {
return n * fact(n - 1);
}
}


int main() {

int x = 2;
int y = 3;
int z = x + y;

cout << fact(z) << endl;


return 0;
}

编译 C/C++ 程序时使其可以被 LLDB 调试工具设置断点,需要添加 -g ,以 C++ 文件 demo.cpp 为例:

1
2
3
clang++ -g demo.cpp

lldb a.out

断点操作

设置断点
1
2
br s -f [文件名] -l [行号]			# 在文件的某一行设置断点
br s -n [函数名] # 给函数设置断点
查看断点
1
br list					# 显示所有断点和其序号
删除断点
1
2
br del [断点序号]
br del # 删除所有断点

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(lldb) br s -f demo.cpp -l 17
Breakpoint 1: where = a.out`main + 28 at demo.cpp:17:9, address = 0x0000000100003d80
(lldb) br s -f demo.cpp -l 21
Breakpoint 2: where = a.out`main + 56 at demo.cpp:21:18, address = 0x0000000100003d9c
(lldb) br s -n fact
Breakpoint 3: where = a.out`fact(int) + 16 at demo.cpp:6:9, address = 0x0000000100003d18
(lldb) br list
Current breakpoints:
1: file = 'demo.cpp', line = 17, exact_match = 0, locations = 1
1.1: where = a.out`main + 28 at demo.cpp:17:9, address = a.out[0x0000000100003d80], unresolved, hit count = 0

2: file = 'demo.cpp', line = 21, exact_match = 0, locations = 1
2.1: where = a.out`main + 56 at demo.cpp:21:18, address = a.out[0x0000000100003d9c], unresolved, hit count = 0

3: name = 'fact', locations = 1
3.1: where = a.out`fact(int) + 16 at demo.cpp:6:9, address = a.out[0x0000000100003d18], unresolved, hit count = 0

(lldb) br del 3
1 breakpoints deleted; 0 breakpoint locations disabled.
(lldb) br list
Current breakpoints:
1: file = 'demo.cpp', line = 17, exact_match = 0, locations = 1
1.1: where = a.out`main + 28 at demo.cpp:17:9, address = a.out[0x0000000100003d80], unresolved, hit count = 0

2: file = 'demo.cpp', line = 21, exact_match = 0, locations = 1
2.1: where = a.out`main + 56 at demo.cpp:21:18, address = a.out[0x0000000100003d9c], unresolved, hit count = 0

分步调试

启动调试
1
r

输入 run 或者 r 后程序便会开始启动调试

进入,跳过和继续
1
2
3
4
5
6
7
8
# 进入	单步执行,中间如果有函数调用会跳转到目标函数
s

# 跳过 单步执行,中间的函数执行过程会跳过
n

# 继续 跳转到下一个断点
c
跳出当前函数
1
finish

查看变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 查看某个变量:
p [变量名]


# 查看当前栈帧所有变量
fr v


# 切换栈帧
fr s [栈帧序号]


# 打印当前线程的栈帧信息
bt


# 打印所有线程的栈帧信息
bt all

综合案例:在 demo.cpp 的 17 行和 21 行设置断点,使用 r 开始调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100003d80 a.out`main at demo.cpp:17:9
14
15 int main() {
16
-> 17 int x = 2;
18 int y = 3;
19 int z = x + y;
20
Target 0: (a.out) stopped.
(lldb) s
Process 31435 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100003d88 a.out`main at demo.cpp:18:9
15 int main() {
16
17 int x = 2;
-> 18 int y = 3;
19 int z = x + y;
20
21 cout << fact(z) << endl;
Target 0: (a.out) stopped.
(lldb) s
Process 31435 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100003d8c a.out`main at demo.cpp:19:13
16
17 int x = 2;
18 int y = 3;
-> 19 int z = x + y;
20
21 cout << fact(z) << endl;
22
Target 0: (a.out) stopped.
(lldb) s
Process 31435 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
frame #0: 0x0000000100003d9c a.out`main at demo.cpp:21:18
18 int y = 3;
19 int z = x + y;
20
-> 21 cout << fact(z) << endl;
22
23 return 0;
24 }
Target 0: (a.out) stopped.
(lldb) fr v
(int) x = 2
(int) y = 3
(int) z = 5
(lldb) s
Process 31435 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100003d18 a.out`fact(n=5) at demo.cpp:6:9
3 using namespace std;
4
5 int fact(int n) {
-> 6 if (n == 0) {
7 return 1;
8 }
9 else {
Target 0: (a.out) stopped.
(lldb) finish
Process 31435 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step out
Return value: (int) $0 = 120

frame #0: 0x0000000100003da4 a.out`main at demo.cpp:21:13
18 int y = 3;
19 int z = x + y;
20
-> 21 cout << fact(z) << endl;
22
23 return 0;
24 }
Target 0: (a.out) stopped.
(lldb) c
Process 31435 resuming
120
Process 31435 exited with status = 0 (0x00000000)

结束调试

1
q

输入 quit 或者 q 结束 LLDB 调试

以上就是对 LLDB 的一个简单介绍了,如果想了解更多 LLDB 指令,可以查看官网的 LLDB command map


LLDB 快速入门
https://goer17.github.io/2023/02/22/LLDB 快速入门/
作者
Captain_Lee
发布于
2023年2月22日
许可协议