跳转到内容

使用 gdb 调试本地程序

使用调试信息编译程序,以便在 gdb 中获得有意义的调试内容:

Terminal window
gcc -g -O0 -o myprog myprog.c

解释:

  • -g 会在可执行文件中嵌入调试符号(函数名、行号、局部变量类型)。
  • -O0 关闭优化,避免编译器把变量移除或重排,便于调试时观察程序状态。

用参数启动 gdb:

Terminal window
gdb --args ./myprog arg1 arg2

一个典型的交互流程:

  • break main — 在 main 处设置断点。
  • run — 启动程序。
  • 程序停止时使用 bt 查看调用栈,frame 2 切换帧,print var 检查变量。
  • next 跳过函数调用,step 进入函数内部。

常用命令一览:

  • run — 启动程序
  • break <function|file:line> — 设置断点
  • delete — 删除断点
  • info breakpoints — 列出断点
  • next / step — 单步(跳过 / 进入)
  • continue — 继续执行
  • bt / backtrace — 打印调用栈
  • frame <n> — 切换到指定帧
  • print <expression> — 打印变量或求值表达式
  • set variable x=42 — 修改程序状态中变量的值

若程序崩溃,先确保生成 core 文件或在 gdb 中运行:

Terminal window
ulimit -c unlimited
./myprog
# 崩溃并生成 core 后:
gdb ./myprog core
# 或者在 gdb 中直接运行:
gdb --args ./myprog
run

运行 bt 会显示崩溃堆栈,例如:

#0 0x00007ffff7a3341a in strcpy () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x4006f4 in unsafe_copy (src=0x602010 "...", dest=0x7fffffffe2c0 "...") at buffer.c:12
#2 0x400710 in main () at hello.c:24

使用 frame 1,然后 print srcprint dest 查看该帧内变量。用 list 显示崩溃附近的源码。

  • 条件断点:break foo if x==0 — 仅当条件满足时停下。
  • 观察点(watchpoint):watch myvar — 当 myvar 的值发生变化时停下(硬件观察点数量受限)。
  • 信号处理:handle SIGSEGV print pass 用于配置 gdb 如何显示与传递信号。

对于 C++ 的 STL 容器,启用 pretty-printers(通常随 libstdc++ 调试助手一起提供)。如果未启用,可安装并配置 gdb 的 Python pretty-printers,然后 print std::vector_var 会以人类可读形式显示内容。

在目标机(或容器/虚拟机)上运行 gdbserver,在主机上连接并调试:

目标机:

Terminal window
gdbserver :1234 ./myprog arg1

主机:

Terminal window
gdb ./myprog
target remote target-ip:1234
continue

这样可以在主机上使用完整的源代码与 gdb,同时程序在目标机上运行。

在 CI 中非交互地收集回溯信息:

Terminal window
gdb --batch -ex 'run' -ex 'bt full' --args ./myprog

或当已有 core 文件时:

Terminal window
gdb --batch -ex 'bt full' ./myprog core > core-backtrace.txt
  • addr2line -e ./myprog 0x4006f4:把地址转换为文件:行号。
  • 在脚本中使用 set print pretty onset pagination off 可获得更简洁的输出。
  • 对 Python 扩展或使用 GDB Python 脚本时,可在 gdb 中使用 python 块自动化任务。

当 bug 难以重现或与性能相关时,用 perf record / perf report 找出热点,再在热点附近使用 gdb 调试和检查运行时状态。

若 gdb 报告缺少符号,确认使用了 -g 编译且可执行文件未被 strip。用 filereadelf -S ./myprog 检查符号表与段信息。

  1. 交互式调试使用 -g -O0;发布构建可用 -g -O2 保留部分符号信息。
  2. 在 CI 中使用 gdb --batch -ex 'run' -ex 'bt' --args ./myprog 捕获失败测试的回溯。
  3. 重现崩溃时设 ulimit -c unlimited 保存 core dump 以便事后分析。