3. 启动与退出GDB:gdb命令的多种启动方式、core文件调试、attach到运行进程、quit与exit

说实话,很多初学者觉得GDB启动就是敲个gdb ./a.out完事。但我在实际项目中踩过不少坑,发现启动方式选对了,调试效率能翻倍。今天咱们就把GDB的启动和退出聊透。

3.1 最基础的启动方式

先看最常用的几种启动命令:

# 方式1:直接调试可执行文件
gdb ./my_program

# 方式2:调试时带参数
gdb --args ./my_program arg1 arg2

# 方式3:先启动GDB,再加载文件
gdb
(gdb) file ./my_program
(gdb) run arg1 arg2

我个人习惯用方式2,因为参数写在命令行里一目了然。但要注意,--args后面的所有内容都会被当作参数传给程序,包括路径中的空格——我曾经因为这个特性,在调试一个带空格路径的程序时折腾了半小时。

小技巧:如果程序需要大量参数,可以写个脚本把参数存成变量,然后用gdb -x script.gdb的方式批量执行GDB命令。

3.2 Core文件调试——救命稻草

程序崩溃了,但现场没了?这时候core文件就是你的救命稻草。说白了,core文件就是程序挂掉那一刻的内存快照。

先确保系统允许生成core文件:

# 查看当前限制
ulimit -c

# 设置为无限制(临时生效)
ulimit -c unlimited

# 永久生效(写入bashrc)
echo "ulimit -c unlimited" >> ~/.bashrc

然后让程序崩溃一次,生成core文件:

# 运行程序,让它崩溃
./my_program
Segmentation fault (core dumped)

# 用GDB加载core文件
gdb ./my_program core

我曾经在一个线上服务崩溃后,靠core文件定位到了一个指针越界问题。当时程序跑了三天才挂,如果没有core文件,根本复现不了。用bt命令看调用栈,发现是某个函数里对数组的访问越界了——索引值比数组长度大了1。

注意:core文件可能包含敏感数据(密码、密钥等),生产环境记得配置core文件路径和权限。我见过有人把core文件直接丢在/tmp下,结果被其他用户读走了内存中的私钥。

3.3 Attach到运行中的进程

有时候程序已经跑起来了,你不能停掉它(比如线上服务)。这时候就需要attach方式:

# 先找到进程PID
ps aux | grep my_program

# 假设PID是12345
gdb -p 12345

# 或者先启动GDB再attach
gdb
(gdb) attach 12345

attach上去后,程序会暂停。你可以设置断点、查看变量、修改内存。完事后用detach让程序继续跑:

(gdb) detach
(gdb) quit

这里有个坑:如果你attach到一个多线程程序,GDB默认只暂停当前线程。其他线程还在跑!我曾经调试一个死锁问题,attach上去后发现所有线程都在等锁,但GDB只显示了当前线程的栈——差点误判。后来用info threads才看清全貌。

核心要点:attach调试时,记得用set follow-fork-mode child或set detach-on-fork off来控制子进程的行为。特别是调试fork出来的子进程时,这个设置能救命。

3.4 退出GDB的正确姿势

退出GDB很简单,但不同场景有不同讲究:

# 正常退出
(gdb) quit
# 或
(gdb) exit

# 强制退出(不询问)
(gdb) quit -y

# 如果调试的进程还在运行,GDB会问你是否要杀掉它
(gdb) quit
The program is running. Exit anyway? (y or n) y

我个人建议:如果只是临时退出,用quit就好。但如果调试的是线上服务,记得先detach再退出,否则GDB会帮你把进程杀了——别问我怎么知道的。

3.5 知识体系总览

下面这张图总结了GDB启动与退出的核心逻辑:

GDB启动与退出知识体系 启动方式 退出方式 直接调试 带参数启动 Core文件调试 Attach进程 quit / exit 强制退出 -y 先detach再退出 核心流程:启动 → 调试 → 退出 ⚠️ 注意事项 • Core文件调试前需确认 ulimit -c 已开启 • Attach到多线程程序时,记得用 info threads 查看所有线程

3.6 实战避坑指南

最后分享几个我踩过的坑:

  • core文件太大?用ulimit -c 102400限制大小,单位是KB。我一般设100MB,够用又不占磁盘。
  • attach后程序卡死?检查是不是有SIGSTOP信号。用signal SIGCONT让程序继续跑。
  • 退出时GDB问要不要杀进程?如果你只是调试,选n。如果调试完要重启,选y。我习惯先detach再quit,这样永远不会误杀。
  • 多进程调试?用set follow-fork-mode child让GDB跟踪子进程。或者用set detach-on-fork off同时调试父子进程。
我的经验:调试线上服务时,我通常先用gdb -p PID attach上去,然后set scheduler-locking on锁定线程调度,再慢慢看问题。完事后detach,服务继续跑,用户无感知。

嗯,启动和退出这部分就这些。记住一点:启动方式选对了,调试就成功了一半。Core文件调试和Attach调试是线上问题排查的两大利器,建议多练练。

可可精品资料库