调试工具总览:GDB、LLDB、strace、ltrace
做系统调试这么多年,我发现自己手头最趁手的家伙,其实就是这四个工具:GDB、LLDB、strace、ltrace。说白了,它们分两大阵营——动态调试器和系统跟踪工具。今天咱们就挨个捋一遍,哪些场景用哪个,怎么用得顺手。
一、动态调试器:GDB 与 LLDB
这两个是给进程“做手术”的。GDB 我用了十年,LLDB 是后来因为 macOS 项目才开始接触。它们都能让你在程序运行时随时停下来,看变量、看堆栈、改内存。
GDB(GNU Debugger)
Linux 下调试 C/C++ 的首选。我个人习惯直接把核心命令记牢:run、break、next、step、backtrace、info locals。说到 backtrace,我记得有一次线上服务半夜崩溃,直接看 crash dump 里的栈帧,就靠 bt 找到了那个空指针。
# 启动调试
gdb ./myapp
(gdb) run
(gdb) bt
(gdb) info registers
避坑指南:我曾经在调试多线程程序时忘了 set follow-fork-mode child,结果子进程一跑就抓不住。嗯,这个选项你得记着。
LLDB(LLVM Debugger)
macOS / iOS 下的调试利器。命令风格和 GDB 很像,但有些名字不一样,比如 thread backtrace 对应 GDB 的 bt。它原生支持 Swift 和 Objective-C,如果你做苹果平台开发,基本离不开它。
lldb ./MyApp
(lldb) run
(lldb) thread backtrace -e true
(lldb) frame variable
你想想看,如果只是要快速看一个 iOS app 的崩溃栈,我一般直接用 lldb attach 到进程,然后 bt 搞定,效率比 Xcode 的 GUI 快不少。
二、系统跟踪工具:strace 与 ltrace
这两个说白了是“偷窥”程序跟操作系统和库的交互。程序死锁、文件打不开、内存越界?先用 strace 看一眼系统调用,再用 ltrace 看库函数,定位速度直接翻倍。
strace(系统调用跟踪)
它跟踪程序发起的每一个系统调用——open、read、write、mmap……我当年排查一个“启动慢”的问题,用 strace 发现程序反复打开同一个配置文件三次,后来一查是初始化顺序写错了。
strace -o trace.log ./myapp
strace -p 12345 -f # 跟踪子进程
⚠️ 注意:strace 输出量极大,我建议先用 -c 做个统计,再针对高频调用加 -e 过滤。
strace -c ./myapp # 打印系统调用计数
strace -e trace=open,read ./myapp # 只看 open 和 read
避坑指南:我曾经用 strace 跟踪一个守护进程,没加 -f,结果子进程创建后一路没被跟踪,白忙活半小时。记住:多进程程序一定要 -f。
ltrace(库调用跟踪)
它跟踪的是动态库函数调用,像 malloc、printf、strlen 这些。如果 strace 没发现系统调用异常,那问题很可能发生在用户态库函数里。
ltrace -o lib.log ./myapp
ltrace -e malloc+free ./myapp # 只看内存分配相关
举个例子:程序跑着跑着内存暴涨,用 strace 看 brk 并不频繁,但 ltrace 里的 malloc 次数却飙升。嗯,那肯定是调用层的问题,比如忘记释放了。
三、工具对比速查表
| 工具 | 领域 | 典型场景 | 调试语言 |
|---|---|---|---|
| GDB | 动态调试 | 断点、堆栈、寄存器 | C/C++、Fortran |
| LLDB | 动态调试 | macOS/iOS 崩溃分析 | C/C++、Swift、ObjC |
| strace | 系统调用 | 文件 I/O、网络、进程创建 | 所有用户态程序 |
| ltrace | 库函数调用 | 内存泄漏、库调用顺序 | 动态链接的程序 |
实战口诀:先 strace 查系统调用,再 ltrace 查库函数,最后 GDB / LLDB 下断点打桩。三层下来,90% 的崩溃都能定位。
小技巧:GDB 的 catch syscall 可以像 strace 一样抓系统调用,但调试功能更强。LLDB 里对应的命令是 breakpoint set -n start -s libsystem_kernel.dylib。
四、工具选择决策流程
我平时遇到问题,先问自己:
- 程序崩了,但不知道在哪? → 直接 GDB/LLDB 加载 core dump,bt 看栈。
- 卡住不动,怀疑死锁? → strace 看进程卡在哪个系统调用上(比如
futex等锁)。 - 内存越来越大,怀疑泄漏? → ltrace 盯
malloc/free次数差异。 - 启动巨慢,想优化? → strace -c 统计系统调用耗时。
记住一个原则:能用 strace / ltrace 的场合,不要急着上 GDB。因为跟踪工具不会打断程序运行,适合线上应急。但需要修 bug 时,GDB 的断点调试无可替代。
这张结构图帮你快速定位:遇到崩溃问题,先判断是用户态逻辑问题(上动态调试器)还是系统交互问题(上系统跟踪工具)。两个阵营配合使用,效率最高。