版本控制器 Git 和调试器 gdb/cgdb,这两样东西听起来像老派命令行工具,但说句实话,它们才是开发者的基本功。刚工作那会儿我习惯把所有代码版本手动备份,文件夹名字从“最终版”一直排到“最终版_改改改_再也不改”,直到有一次同事把我最新的“最终版V3_真最终”直接覆盖了,我才彻底老老实实学 Git。调 bug 也是,以前就靠 printf 满天飞,编进去、跑了、删掉,再编再跑,后来被一个隐蔽的指针越界折磨了整整两天,才开始认真啃 gdb。
这篇东西不是教科书式的命令罗列,而是把我实际用 Git、gdb、cgdb 一路踩过的坑、验证过好用的命令、以及嵌入式调试时遇到的那些“服务器连不上”的疑难杂症,全部整理成一篇可以照着操作的文章。无论你是刚接触命令行工具链的新人,还是已经会用 git add/commit 但碰到复杂场景就发懵的老手,或者正被 gdb 调试崩溃程序搞得焦头烂额,这篇文章都适合你。我会从为什么需要这两套工具讲起,到 Git 安装配置、日常提交规范、SSH 免密,再到 gdb 断点、调用栈、内存分析,最后把 cgdb 安装配置和高频报错排查一起覆盖掉。
1. 工具定位:为什么版本控制器Git和调试器gdb/cgdb是开发者的基本功
1.1 从存档说起:Git到底在你电脑里做了什么
先介绍一个生活化类比。Git 就像游戏里无限数量的存档位:你随时可以存一个档(commit),随时可以读档(checkout/reset),甚至可以开一条平行剧情线(branch)去实验新玩法,实验失败不影响主线。说得再正式一点,Git 是一个分布式版本控制系统,每次提交都会完整记录当前仓库的快照,并保留历史提交链。和早期的集中式版本控制工具(比如 SVN)相比,最大的区别在于 Git 把完整历史仓库复制到了每个开发者本地。
这意味着什么?意味着你断网的时候也能提交代码,也能看历史,也能开分支、合并分支。只有推送到远程服务器(GitHub、GitLab、Gitea 或者公司内网仓库)的时候才需要联网。我遇到过不少现场运维场景,客户机房网络政策严格,外网完全不通,靠着 Git 本地仓库照样完成了代码回滚和版本对比。
Git 真正解决的核心问题有三个:
- 可回溯性:每一行代码改动都能追溯到是谁、在什么时候、为什么改的。
- 并行开发:多个人可以在不同分支上同时开发互不干扰,最后合并。
- 代码审查:通过 Pull Request / Merge Request 把改动集中起来评审,很多规范团队把这条当成质量门禁。
所以 Git 不是“记笔记的工具”,而是项目管理的基础设施。你代码写得好不好是一回事,能不能把团队协作版本管理得井井有条是另一回事。
1.2 gdb与cgdb:同一引擎,两种操作界面
gdb 是 GNU 项目的调试器,支持 C、C++、Rust、Go 等多种编译语言,也是 Linux 平台最通用的程序调试工具。它能做的事情非常直接:让程序在你指定的位置停下来,然后你逐行执行、查看变量的值、修改内存、查看函数调用栈,甚至附加到一个正在运行的进程上,看它到底卡在哪个函数里。
cgdb 是 gdb 的一个文本交互前端。它保留了 gdb 完整的命令体系,额外把窗口分成了上下两块:上面是源码窗口,下面是 gdb 命令窗口。你不需要在 IDE 里点击鼠标,就能在纯命令行环境下同时看到源码和调试输出。很多嵌入式开发、服务器维护、容器开发场景没有图形界面,cgdb 就是最接近 IDE 体验的调试方案。
为什么不用 Visual Studio Code 或者 CLion 自带的调试器?首先,VSCode 里的调试本质上也是调用 gdb/lldb,只不过帮你做了图形化封装。但在某些远程服务器、开发板、容器内部,没有条件装图形界面,这时候掌握 gdb 就是唯一可行的调试路径。另外,嵌入式交叉编译环境下,调试器要针对目标架构(ARM、RISC-V)工作,命令行 gdb 的适配和灵活性远高于图形 IDE。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Git从安装到日常提交:完整链路与高频命令详解
2.1 不同系统下的Git安装与环境配置
安装 Git 这一步看起来简单,其实不少新人在 Windows 上就卡住了。最常见的报错是 PowerShell 里输入 git 后提示“无法将‘git’项识别为 cmdlet、函数、脚本文件或可运行程序的名称”,这基本就是安装时没有把 Git 加入系统 PATH,或者安装完没有重新打开终端。
Windows 上推荐从 git-scm.com 下载官方安装包,安装过程中有一步专门让你选择 PATH 环境变量,建议选“Git from the command line and also from 3rd-party software”,这样 Git 的命令行工具会被加入系统 PATH。安装完成后重新打开 PowerShell 或者 CMD,输入:
bash复制git --version
如果能看到版本号,说明安装成功。
macOS 上最简单的方式是安装 Xcode Command Line Tools,系统会自带 Git;或者用 Homebrew:
bash复制brew install git
Linux 上根据发行版不同:
bash复制# Debian/Ubuntu
sudo apt install git
# CentOS/RHEL
sudo yum install git
# Fedora
sudo dnf install git
安装完别忘了确认版本,Git 版本太老的话,部分新特性(比如更智能的合并策略、哈希算法 SHA-256 仓库)无法使用。建议至少使用 2.30 以上的版本。
2.2 第一次提交前的三件事:身份、换行符、默认编辑器
如果你直接 git commit,很可能遇到一个弹出来的 Vim 编辑器,新人不熟悉 Vim 操作会直接卡死在里面。所以第一步建议先把默认编辑器改掉:
bash复制git config --global core.editor "code --wait"
这是把默认编辑器改成 VSCode,等你关闭编辑器窗口后,提交信息才被 Git 读取。如果你不想用 VSCode,也可以改成 nano 或者 notepad。
第二步是配置用户信息。这步很多人觉得无所谓,实际影响很大。提交记录里的作者姓名和邮箱就来自这里,代码审查时这个信息是追溯责任人的关键:
bash复制git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
注意,这跟你之后配置 SSH 免密无关,身份信息只影响提交记录,不影响鉴权。
第三步是处理换行符。Windows 和 Linux/macOS 对换行符的编码不同(Windows 是 CRLF,Unix 是 LF),不同系统协作时很容易出现“整文件被标记为改动”的情况——其实只是换行符不一致。建议在 Windows 上设置:
bash复制git config --global core.autocrlf true
这个设置会在提交时把 CRLF 自动转成 LF,检出时再转回 CRLF。在 Linux/macOS 上建议:
bash复制git config --global core.autocrlf input
另外还有一个高频配置,解决中文文件名显示成八进制转义的问题:
bash复制git config --global core.quotepath false
配置完成后,用这个命令可以检查所有生效的配置以及它的来源:
bash复制git config --list --show-origin
2.3 SSH免密配置:一次配置,永久省力
用 HTTPS 方式 clone 和 push 时,每次都要求输入账号密码是很多人的痛点。SSH 免密配置是所有 Git 使用者的必经之路。
先生成密钥对:
bash复制ssh-keygen -t ed25519 -C "your_email@example.com"
一路回车即可,默认保存在 ~/.ssh/id_ed25519。如果提示 ssh-keygen 不存在,说明系统缺少 OpenSSH 客户端。
然后把公钥内容复制到代码托管平台。不同平台位置不同:GitHub 在 Settings -> SSH and GPG keys,GitLab 在 Preferences -> SSH Keys,Gitea 在设置 -> SSH 密钥。公钥文件是 .pub 后缀的那个,可以用 cat 或者直接打开文本编辑器复制。
bash复制cat ~/.ssh/id_ed25519.pub
添加完成后测试连接:
bash复制ssh -T git@github.com
首次连接会询问是否信任主机指纹,输入 yes 回车,看到类似“Hi username! You've successfully authenticated”的输出就说明配置成功。
如果你有多个 Git 托管平台的账号,比如一个 GitHub 一个 GitLab,密钥会冲突。解决方法是编辑 ~/.ssh/config 文件,为不同的 Host 指定不同的密钥文件:
bash复制Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github
Host gitlab.com
HostName gitlab.com
User git
IdentityFile ~/.ssh/id_ed25519_gitlab
这样 Git 会根据目标域名自动选择对应密钥,不用反复切换。
2.4 日常操作链路:clone、branch、commit、push、pull
下面这一套是每天最频繁的 Git 操作链路。假设你已经有了一个远程仓库,第一次拉取代码:
bash复制git clone git@github.com:user/repo.git
进入项目目录后,新建一个功能分支开始开发:
bash复制git checkout -b feature/login
这个命令会同时完成“创建分支”和“切换分支”两步。为什么不直接在主分支上开发?因为主分支通常是保护分支,直接往上面提交容易造成冲突,也绕过了代码评审。规范的做法是每个功能一个分支,开发完合并后删除。
改完代码后先看看状态和差异:
bash复制git status
git diff
这会让你清楚哪些文件改过、改了哪些行。确认无误后,把文件加入暂存区:
bash复制git add .
git add . 会把当前目录下所有改动加入暂存区。如果想单独提交某个文件,用 git add 文件名。提交:
bash复制git commit -m "feat: 添加登录页面"
这里我建议写规范提交信息,下一小节详细讲。提交完成后推送到远程分支:
bash复制git push origin HEAD
HEAD 表示当前分支。推送成功后去远程仓库应该能看到你的新分支。
日常开发还有一个高频操作:同步远程。同事可能合并了代码到主分支,你需要拉取最新代码。这里强烈建议用:
bash复制git pull --rebase
而不是直接 git pull。区别在于:git pull 默认会合并远程分支到本地生成一个多余的合并节点,历史看起来很乱;--rebase 则把你的本地提交“搬”到远程最新提交的后面,历史是线性的,更干净。注意只有本地有未推送的提交时才需要关心这个,如果没有本地提交,两者效果一样。
2.5 提交信息怎么写最规范:Conventional Commits 实践
“git提交规范”是工作中很容易被轻视但实际影响很大的点。规范的提交信息配合代码审查,能大幅提升协作效率。目前业界最通用的规范是 Conventional Commits,格式如下:
text复制<type>(<scope>): <description>
[optional body]
[optional footer]
type 是提交类型:
- feat:新功能
- fix:修复 Bug
- docs:文档变更
- refactor:重构代码,不改变行为
- perf:性能优化
- test:增加测试
- chore:构建工具、依赖、辅助工具变更
scope 是影响范围,比如 feat(auth): 增加登录页。description 是简短描述,用祈使句,不超过 50 个字符。
举个例子:
text复制feat(cart): 增加购物车商品批量删除功能
- 前端新增多选删除按钮
- 后端新增 batch_delete 接口
- 补充批量删除的单元测试
为什么要这么写?第一,历史记录里搜“fix: xxx”一眼就能看到哪些提交是修 Bug;第二,后续可以用工具根据提交类型自动生成 changelog;第三,代码审查时 reviewer 能快速判断改动意图。我见过不少团队用 commitlint 配合 husky 在提交时强制校验格式,格式不对直接拒绝提交,这属于工程效率的长期投资。
3. gdb调试实战:从断点到内存,把程序看个通透
3.1 编译参数是调试的第一道门槛
很多新手抱怨“gdb 看不到行号,只能看到地址”,这不是 gdb 的问题,而是编译时没有加调试符号。调试符号是程序和你写的源代码之间的映射表,gdb 根据它才能把机器指令对应回具体的源文件行号。编译时务必加 -g 参数:
bash复制gcc -g -o app main.c
加了 -g 之后,生成的二进制文件里会包含调试信息,文件体积变大,这是正常的。发布到生产环境的版本出于体积和逆向保护考虑通常不加 -g,但即便如此,我建议 release 编译时也可以考虑加上 -g 然后 strip,这样线上出问题还能用 core 文件分析。
补充一个常见问题:如果你在 64 位 Linux 上调试 32 位程序,或者做嵌入式交叉编译调试,需要安装 multiarch 支持。比如在 Ubuntu 上调试其他架构的程序,可以安装 gdb-multiarch:
bash复制sudo apt install gdb-multiarch
gdb-multiarch ./target_arm_elf
这样 gdb 就能识别不同架构的二进制文件,不至于一开始就报“file format not recognized”。
3.2 启动 gdb 的三种姿势
第一种,调试一个新程序:
bash复制gdb ./myapp
进入 gdb 交互界面后,可以先用 break main 在入口函数下断点,再输入 run 启动程序。
第二种,调试需要传参的程序。有两种方式:要么在 gdb 里面用 set args 设置,要么启动时直接带上:
bash复制gdb --args ./myapp --port 8080 --config /etc/myapp.conf
进入 gdb 后直接 run,程序就会带上这些参数启动。用 show args 可以查看当前设置的参数。
第三种,调试正在运行的进程。有时候程序已经跑起来了,但你想看看它卡在哪,可以附加:
bash复制gdb -p PID
PID 是进程号,可以用 ps 或者 pidof 查询。附加成功后,程序会暂停,你可以用 bt 查看当前调用栈。注意,Linux 上附加他人进程或受保护进程可能被 ptrace 权限限制,系统提示 Operation not permitted 时,需要检查 /proc/sys/kernel/yama/ptrace_scope 的值,或者用 sudo 以 root 权限附加。
如果是程序崩溃,Linux 会生成 core dump 文件,调试崩溃现场:
bash复制gdb ./myapp core
但前提是系统开启了 core dump 生成。可以用 ulimit -c unlimited 临时开启,长期生效需要写进 shell 配置文件。
3.3 高频命令串讲:断点、单步、查看变量、调用栈
进入 gdb 后,我实际使用频率最高的命令就下面这些:
break 是下断点的核心命令。可以按函数名、文件名加行号、条件几种方式:
gdb复制break main
break src/server.c:102
break foo if x == 5
第三种条件断点非常省事。比如你确认循环第 100 次才出问题,直接 break 循环行 if i == 100,程序会一直运行到条件成立才停,不需要手动循环 next 一百次。
run 启动程序。程序启动后会正常执行,遇到断点停下。
单步执行有三个命令:
- next(或 n):执行当前行,遇到函数调用会整个跳过。
- step(或 s):进入函数内部执行。
- finish:一直运行到当前函数返回,配合 step 进入函数后快速跳出。
continue(或 c):程序继续运行,直到下一个断点或结束。
查看变量是 print(或 p)。除了直接打印变量名,还能按格式打印:
gdb复制p x
p/x x # 十六进制
p/d x # 十进制
p/s str # 字符串
p/x &arr[0] # 地址
如果只想关注某个变量在运行过程中什么时候被改变,可以用 watch:
gdb复制watch x
程序运行到 x 的值发生变化的瞬间就会停下,非常适合找“谁偷偷改了我的变量”。
排查崩溃问题时最常用的命令是 bt(backtrace),打印当前的函数调用栈。不管程序是崩溃还是主动断下,先 bt 一下,基本能定位到问题出在哪个调用链条上。再用 frame 切换到对应栈帧,比如 frame 2,然后 info locals 查看该层函数的所有局部变量。
3.4 一个越界写崩溃的完整调试案例
下面用一个经典到不能再经典的 C 语言崩溃案例完整演示一遍调试思路。
写一个明显有问题的程序:
c复制#include <stdio.h>
int main() {
int arr[5];
for (int i = 0; i <= 5; i++) {
arr[i] = i * 10;
}
printf("done\n");
return 0;
}
这个程序有一个越界写:i 从 0 到 5,但 arr 只有 5 个元素,arr[5] 越界写入了栈上的相邻内存,可能破坏 main 的栈帧,导致返回地址错误,程序异常退出。
编译并启动调试:
bash复制gcc -g -o bug bug.c
gdb ./bug
在 gdb 里直接 run:
gdb复制(gdb) run
程序会崩溃,gdb 会提示收到了 SIGSEGV 信号,并且定位到发生异常的位置。输入 bt:
gdb复制(gdb) bt
#0 main () at bug.c:6
看到崩溃点在第 6 行,也就是 arr[i] = i * 10 这一行。用 p i 打印循环变量:
gdb复制(gdb) p i
$1 = 5
问题清晰地暴露了:i 等于 5,正好越界。修复方案很简单,循环条件改成 i < 5。
但现实比这个复杂得多,越界写不会每次都会立即崩溃,可能只是悄悄破坏邻近变量。更恶劣的情况是运行时正常,程序结果却诡异。这时候用 watch 去监控某个变量就能救命。比如怀疑某个全局变量被莫名改掉,你可以在 gdb 里:
gdb复制watch my_global_var
只要这个变量被写入,程序马上停下。这类问题靠 printf 是几乎不可能定位的。
3.5 多线程调试与附加运行中进程
多线程调试比单线程要小心一些。gdb 默认在所有线程并行运行,断点命中某个线程后,其他线程可能还在跑。查看当前线程:
gdb复制info threads
切换线程:
gdb复制thread 2
切换后 bt 看这个线程的栈。当多线程程序死锁时,最有效的命令是:
gdb复制thread apply all bt
这会把所有线程的调用栈一下子打出来。看到两个线程各自持有锁在等对方释放锁,死锁原因立刻清楚。
单线程步进时,如果不希望其他线程继续运行,设置:
gdb复制set scheduler-locking on
这样 next、step 只会在当前线程执行,其他线程冻结,方便排查共享数据竞争问题。
附加到运行中的服务进程时,要稍等片刻让 gdb 加载符号表,然后用 bt 就能看到服务当前卡在哪个调用点。注意,附加调试会暂停目标进程,线上环境操作前一定要向团队确认。
4. cgdb:让命令行调试效率翻倍的交互式前端
4.1 cgdb解决了什么问题
gdb 的原生命令行体验确实存在短板:在文本模式下,你输入 next 回车,gdb 打印下一行源码,但你看不到整个函数上下文,只有一条一行。需要随时 list 来刷新源码,操作繁琐。
cgdb 解决了这个痛点。它把终端分成两个区域:上部是源码窗口,清晰显示当前执行到哪一行、哪些行有断点;下部是 gdb 命令行窗口。源码窗口能实时高亮当前行,支持方向键浏览上下文,直接回车就能在光标所在行设置或取消断点。
很多人不知道的是,cgdb 内部仍是 gdb,只是把 gdb 的输出重新渲染成了界面。也就是说,gdb 的所有命令在 cgdb 里都照常可用,不需要学习一套新的调试语言。
4.2 cgdb安装与基本操作
Debian/Ubuntu 上一行命令安装:
bash复制sudo apt install cgdb
macOS:
bash复制brew install cgdb
如果发行版仓库里没有,可以源码编译,依赖 ncurses 和 gdb:
bash复制./configure --prefix=/usr/local
make && sudo make install
启动方式:
bash复制cgdb ./myapp
进入界面后,键盘操作是重点:
- 按空格:在源码窗口和命令窗口之间切换焦点。
- 在源码窗口时,按 i 或者回车进入命令输入模式,直接输入 gdb 命令。
- 用上下方向键可以上下浏览源码,回车会在当前选中行设置断点。
- 按 o 可以在源码窗口和汇编窗口之间切换。
- 按 Esc 可以退出当前输入模式。
这个交互模式对熟悉 Vim 的朋友非常友好,按键风格类似。
4.3 cgdbrc配置心得
cgdb 的配置文件在 ~/.cgdb/cgdbrc,可以设置一些个性化选项。我常用的配置:
bash复制set ignorecase
set tabstop=4
set autosourcerefresh
ignorecase 让搜索忽略大小写,tabstop 控制 tab 宽度,autosourcerefresh 让源码窗口自动跟随当前执行位置刷新。cgdb 还支持在源码窗口用鼠标点击设置断点,前提是终端支持鼠标事件,启用方式:
bash复制set mouse
这些配置写进 cgdbrc 后重启 cgdb 生效。有了一屏源码加命令行的展示,调试体验基本接近 IDE,但运行环境要求低得多。
5. 高频故障排查实录:Git与调试器的疑难杂症速查
5.1 Git常见报错与解决方法
第一个高频报错是“git 无法将项识别为 cmdlet”。这个前面提过,属于 PATH 环境变量问题。Windows 上解决思路是:重新运行 Git 安装包选择“修改”,在调整 PATH 那一步改为推荐选项;或者手动在系统环境变量里把 Git 的 bin 目录和 cmd 目录加进去。改完环境变量后必须新开终端才能生效。
第二个是 HTTPS 克隆时报证书错误:
text复制error setting certificate file: d:/git/mingw64/etc/ssl/certs/ca-bundle.crt
这个报错常见于 Windows 上 Git 的 SSL 证书路径配置错误。排查思路是,确认 Git 安装目录下 mingw64/etc/ssl/certs/ca-bundle.crt 是否存在,如果路径不对,用以下命令修正:
bash复制git config --global http.sslCAInfo "C:/Program Files/Git/mingw64/etc/ssl/certs/ca-bundle.crt"
注意证书路径要用正斜杠。不要一碰到证书错误就 http.sslVerify false,那样等于关闭了 SSL 证书校验,会有中间人攻击风险。
还有一个常见的证书相关报错:
text复制unable to access '...': SSL certificate problem
这种情况可能是系统时间不对,证书校验会因为时间不在有效期内而失败;也可能是公司防火墙做了中间人替换证书。排查顺序:先检查系统时间,再用浏览器访问一下仓库地址看证书是否正常,最后再考虑是不是环境变量 HTTP_PROXY / HTTPS_PROXY 导致 Git 意外走了代理。
第三个问题是把包含 .git 目录的项目部署到 Web 服务器后,源码被泄露。这类问题属于安全事故,防范意识比补救更重要。部署时务必排除 .git 目录,Nginx 里可以配置禁止访问点开头路径,或者更稳妥的做法是 CI/CD 打包时直接用 tar/rsync 排除,坚决不把仓库原封不动推到线上。
第四个小技巧很多人不知道:提交信息写错了怎么办?不需要 reset 重来:
bash复制git commit --amend -m "正确的提交信息"
这会把上次提交替换成新提交。注意只有还没推送到远程的情况下才能安全使用,已经推送了再去 amend 会造成历史分叉,需要强推,很危险。
5.2 gdb连接类报错排查:以嵌入式场景为例
嵌入式开发时,gdb 经常作为调试服务器和开发板之间的桥梁,很容易遇到连接类报错。最常见的两个:
第一个是 J-Link GDB Server 的:
text复制J-Link GDB Server failed: could not connect to target.
遇到这个报错,先别慌,按照以下几个方面排查:
- 开发板是否上电并且复位正常?很多开发板需要单独供电,只连了调试器是不够就绪的。
- SWD/JTAG 接线是否正确?SWDIO、SWCLK、GND 三条线至少不能错;线材过长或接触不良也会导致连接失败。
- 目标芯片是否被锁死?芯片读保护开启后 J-Link 无法正常连接,可能需要做全片擦除。
- J-Link 速率是否太高?把速率从 4MHz 降到 1MHz 甚至 400kHz,很多不稳定连接问题会消失。
排查时可以先用 J-Link Commander 单独连接目标板:
bash复制JLink.exe -device STM32F103C8 -if SWD -speed 4000
如果这个都连不上,问题基本在硬件层面,跟 gdb 没关系。
第二个是 OpenOCD 的:
text复制openocd: gdb server quit unexpectedly. see gdb-server output in terminal tab for more details.
OpenOCD 启动时会同时起一个 GDB Server(默认端口 3333)和一个 telnet 端口(4444),这个报错通常意味着 GDB Server 异常退出。先打印 OpenOCD 自身的日志,重点看有没有 Board/Device 初始化错误、引脚冲突、供电问题。另外如果 3333 端口被别的进程占用,openocd 起不来也会报类似错误。排查:
bash复制lsof -i :3333
netstat -anp | grep 3333
发现占用先杀掉,或者改 OpenOCD 配置里的 gdb_port。
嵌入式环境下如果同时调试多种架构,建议直接用 gdb-multiarch,避免“架构不匹配识别不了 ELF 文件”的尴尬。
5.3 几条实战中的独家经验
第一个经验:把调试命令整理成自己的速查表。工具命令再怎么记,总有想不起来的时候。我在家目录放了一个 cheat.sh 脚本,把 git log、gdb bt、cgdb 快捷键这类内容集中写在里面,需要时快速翻。这比百度搜索快得多,而且内容是自己整理的,命中率高。
第二个经验:新手不要拿生产项目练手。Git 和 gdb 都有学习成本,拿公司项目练手可能把历史搞乱或者误操作。给自己建一个小练习仓库,写几个故意崩溃的 C 小程序,反复练习断点、打印、watch、core dump 这一套。熟练之后再用到真实项目上,心理压力完全不同。
第三个经验:gdb 命令可以写成脚本。如果每次调试都要重复输入十几个命令,太浪费时间。把命令写进文件,比如 debug_cmd.txt 里面:
text复制break main
run
bt
info locals
启动时加载:
bash复制gdb -x debug_cmd.txt ./myapp
更进一步,可以把自动化调试脚本和 Git 的二分查找组合起来。遇到“最近哪次提交引入了这个 Bug”的时候,用 git bisect 标记好与坏提交,让 Git 自动二分切换版本,每次切换后跑一遍自动化测试,很快就能锁定出问题的提交。这个组合是我现在排查疑难 Bug 的标配流程,效率极高。
第四个经验是 cgdb 和 gdb 的选择问题。纯粹的快速看一个堆栈、挂载一下进程,我直接用 gdb 就够了;但需要连续深入源码定位、频繁打断点看流程的时候,cgdb 的分屏视图会明显降低疲劳感。两个工具不是对立关系,而是同一套底层能力的不同交互形态,都值得掌握。
