众所周知, 笔者的操作系统课烂得无法让人忍受, 并且笔者使用的是M1芯片的MacOS, 如果没有 LLDB, 笔者将难以进行这类底层代码的debug. 是时候学习一些 LLDB 的操作了.
1. Clang
Clang 是一个C
Clang 项目包括 Clang 前端和 Clang 静态分析器等.
在Mac上, 编译运行 C 语言的指令是
$ clang <NAME>.c # 默认得到a.out文件
$ ./a.out
在这样的情况下生成的 a.out 文件, lldb a.out
也会正常启动lldb a.out
并顺利打断点需要使用clang
的-g
flag
clang -g main.c
此时会生成一个名为a.out.dSYM
lldb a.out
(注意不是 lldb a.out.dSYM
)了
2. Run
在输入 lldb a.out
之后, 会进入lldb的调试界面. 如下:
![](https://naturalifica.oss-cn-nanjing.aliyuncs.com/~/Users/wuchentian/SoloLearning/Blog/source/imgs/image-20230420002257288.png)
此时输入 r
或者 run
, 程序可以开始运行 (直到遇到错误或者断点处停下).
2.1. 设置断点
(lldb) breakpoint set -f <NAME>.c -l <LINE_NUM>
# 或者是
(lldb) br s -f <NAME>.c -l <LINE_NUM>
# 或者是
(lldb) b <NAME>.c: <LINE_NUM>
# 或者是
(lldb) b <NAME>.c: <LINE_NUM>
## 或者是
(lldb) br <FUNC_NAME> # 这一指令会将断点设在函数体内第一行.
这里 <NAME>.c
表示 C 文件的名字(注意不是 a.out
), <LINE_NUM>
表示想要将断点设在 C 文件的第几行
如果编译时没有加上 -g
flag, 此时将遇到这样的报错
![](https://naturalifica.oss-cn-nanjing.aliyuncs.com/~/Users/wuchentian/SoloLearning/Blog/source/imgs/image-20230420004450029.png)
2.2. 删除断点
(lldb) br list #这条指令将会按照顺序展示所有的断点
(lldb) br del <BREAKPOINT_NUM> #这条指令将会删去第 <BREAKPOINT_NUM> 条断点
3. Control Flow
只有三种平凡的用法
(lldb) s(tep) # 单步执行, 如果遇到函数则会进入函数体
(lldb) n(ext) # 下一步, 如果遇到函数则跳过, 不会进入函数体内
(lldb) c(ontinue) # 直接运行到下一个断点处
4. Variables
打印出某个变量的值
(lldb) p <VAR_NAME>
考虑到作用域, 在一个 C 项目中很可能出现同名的变量, 这个时候需要选择好帧栈.
(lldb) bt # 展示所有的栈
(lldb) frame select <FRAME_NAME> #选择特定的帧栈
# 或者是
(lldb) fr s <FRAME_NAME> #选择特定的帧栈
(lldb) frame variable # 展示当前帧栈内所有的变量
# 或者是
(lldb) fr variable
5. Watch Point
watchpoint 与breakpoint有类似之处但是也有区别, watchpoint 是当监视的变量被修改时, 则停止运行. breakpoint 是当程序运行到特定的位置时, 则停止运行.
当开始 run 之后, 进行如下的输入.
(lldb)watchpoint set variable <GLOBAL_VAR>
# 或者是
(lldb)w s v <GLOBAL_VAR>
此时 continue, 可以继续执行.
(lldb)watchpoint list
# 或者是
(lldb)w list
这样的指令可以监视所有的watchpoint
6. Kill
直接输入 kill 会杀死当前的进程 (每个 run 对应一个进程).