众所周知, 笔者的操作系统课烂得无法让人忍受, 并且笔者使用的是M1芯片的MacOS, 如果没有 LLDB, 笔者将难以进行这类底层代码的debug. 是时候学习一些 LLDB 的操作了.
1. Clang
Clang 是一个C、C++、Objective-C和Objective-C++编程语言的编译器前端。它采用了LLVM作为其后端,由LLVM2.6开始,一起发布新版本。它的目标是提供一个GCC (GNU Compiler Collection) 的替代品,支持了GNU编译器大多数的编译设置以及非官方语言的扩展。作者是Chris Lattner,在苹果公司的赞助支持下进行开发,而源代码许可是使用类BSD的伊利诺伊大学厄巴纳-香槟分校开源码许可.
Clang 项目包括 Clang 前端和 Clang 静态分析器等.
在Mac上, 编译运行 C 语言的指令是
1 | clang <NAME>.c # 默认得到a.out文件 |
在这样的情况下生成的 a.out 文件, lldb a.out
也会正常启动,但是无法顺利断点. 执行lldb a.out
并顺利打断点需要使用clang
的-g
flag
1 | clang -g main.c |
此时会生成一个名为a.out.dSYM
,此后就能顺利执行lldb a.out
(注意不是 lldb a.out.dSYM
)了
2. Run
在输入 lldb a.out
之后, 会进入lldb的调试界面. 如下:
此时输入 r
或者 run
, 程序可以开始运行 (直到遇到错误或者断点处停下).
2.1. 设置断点
1 | (lldb) breakpoint set -f <NAME>.c -l <LINE_NUM> |
这里 <NAME>.c
表示 C 文件的名字(注意不是 a.out
), <LINE_NUM>
表示想要将断点设在 C 文件的第几行
如果编译时没有加上 -g
flag, 此时将遇到这样的报错
2.2. 删除断点
1 | (lldb) br list #这条指令将会按照顺序展示所有的断点 |
3. Control Flow
只有三种平凡的用法
1 | (lldb) s(tep) # 单步执行, 如果遇到函数则会进入函数体 |
4. Variables
打印出某个变量的值
1 | (lldb) p <VAR_NAME> |
考虑到作用域, 在一个 C 项目中很可能出现同名的变量, 这个时候需要选择好帧栈.
1 | (lldb) bt # 展示所有的栈 |
1 | (lldb) frame select <FRAME_NAME> #选择特定的帧栈 |
1 | (lldb) frame variable # 展示当前帧栈内所有的变量 |
5. Watch Point
watchpoint 与breakpoint有类似之处但是也有区别, watchpoint 是当监视的变量被修改时, 则停止运行. breakpoint 是当程序运行到特定的位置时, 则停止运行.
当开始 run 之后, 进行如下的输入.
1 | (lldb)watchpoint set variable <GLOBAL_VAR> |
此时 continue, 可以继续执行.
1 | (lldb)watchpoint list |
这样的指令可以监视所有的watchpoint
6. Kill
直接输入 kill 会杀死当前的进程 (每个 run 对应一个进程).