GDB调试 Memo

GDB调试 Memo

核心概述

GDB是GNU开源调试器,与GCC配套,支持多语言(C/C++/Ada等)、多系统,为字符界面操作。核心功能:程序启停控制、断点管理、代码查看、变量监控、单步调试等。

吉祥物:射手鱼(Archer Fish),寓意“精准捕杀bug”。

一、调试准备(关键前提)

编译程序时必须添加调试选项,否则无法使用GDB调试。

- 核心选项:-g(在可执行文件中嵌入源代码关联信息,不嵌入完整源文件,调试时需保证源文件可访问)

- 推荐可选选项:

  • -O0:关闭编译器优化,避免代码执行逻辑与源码不一致
  • -Wall:开启所有警告,提前规避潜在bug

- 编译示例:

1
2
3
4
# C程序编译
gcc -g -O0 -Wall args.c -o app
# C++程序编译
g++ -g -O0 -Wall test.cpp -o test_app

注意:带-g的可执行文件体积会略大(如示例中app 9816字节 vs 无-g的app1 8608字节)。

二、GDB启停与参数设置

2.1 启动GDB

- 命令格式:gdb 可执行程序名

- 示例:

1
2
gdb app  # 启动GDB并关联app程序,此时程序未执行
(gdb) # 进入GDB交互模式,等待输入调试命令

2.2 给程序传命令行参数

适用场景:调试需要命令行参数的程序(如main(int argc, char* argv[])),需在程序启动前设置。

- 核心命令:

  • 设置参数:set args 参数1 参数2 ...
  • 查看参数:show args

- 示例:

1
2
3
(gdb) set args 11 22 33 44 55  # 给app设置命令行参数11-55
(gdb) show args # 验证参数
Argument list to give program being debugged when it is started is "11 22 33 44 55".

2.3 启动被调试程序

调试中仅能启动一次,两种启动方式:

  • run(缩写r):无断点则执行完程序;有断点则停在第一个断点
  • start:停在main函数第一行,等待后续调试命令

- 后续继续运行:continue(缩写c),从当前阻塞位置继续,直到下一个有效断点

- 示例:

1
2
(gdb) start  # 启动程序,停在main第一行
(gdb) c # 继续运行程序

2.4 退出GDB

- 命令:quit(缩写q

- 示例:(gdb) q # 终止GDB进程,退出调试

三、代码查看命令(list/l)

无可视化界面时,通过命令查看源码,辅助定位断点位置。命令:list(缩写l),默认一次显示10行。

3.1 查看当前文件(默认main函数所在文件)

1
2
3
4
(gdb) l          # 从第一行开始显示
(gdb) l 15 # 显示第15行附近的代码
(gdb) l main # 显示main函数附近的代码
# 回车:重复上一次list命令,查看后续内容

3.2 切换并查看其他文件

- 命令格式:l 文件名:行号l 文件名:函数名

- 示例:

1
2
(gdb) l insert.cpp:8    # 切换到insert.cpp,显示第8行附近代码
(gdb) l test.cpp:sort # 切换到test.cpp,显示sort函数附近代码

3.3 调整显示行数

1
2
3
(gdb) set listsize 20  # 设置一次显示20行
(gdb) show listsize # 查看当前显示行数设置
listsize is 20.

四、断点操作(核心调试功能)

断点命令:break(缩写b),用于让程序在指定位置阻塞,便于观察状态。

4.1 设置断点

  • 普通断点(当前文件):
1
2
(gdb) b 12        # 在当前文件第12行设断点
(gdb) b main # 在main函数第一行设断点
  • 普通断点(非当前文件):
1
2
(gdb) b test.cpp:16    # 在test.cpp第16行设断点
(gdb) b insert.cpp:insertionSort # 在insert.cpp的insertionSort函数设断点
  • 条件断点(仅满足条件时阻塞,常用于循环):
1
(gdb) b 20 if i==10  # 第20行设断点,仅当变量i等于10时生效

4.2 查看断点信息

- 命令:info break(缩写i b

- 示例及字段说明:

1
2
3
4
5
6
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400cb5 in main() at test.cpp:12
# Num:断点编号(操作断点的关键标识)
# Enb:状态(y=可用,n=不可用)
# What:断点位置(文件+行号/函数)

4.3 删除断点

- 命令:delete(缩写del/d)+ 断点编号/区间

- 示例:

1
2
3
(gdb) d 1          # 删除编号1的断点
(gdb) d 2 4 6 # 删除编号2、4、6的断点
(gdb) d 1-5 # 删除编号1到5的连续断点

4.4 切换断点状态(启用/禁用)

临时不用的断点无需删除,可设置为禁用状态。

  • 禁用断点:disable(缩写dis)+ 编号/区间
  • 启用断点:enable(缩写ena)+ 编号/区间

- 示例:

1
2
3
(gdb) dis 2 4      # 禁用编号2、4的断点
(gdb) ena 2-5 # 启用编号2到5的断点
(gdb) i b # 验证状态(Enb列变为y/n)

五、核心调试命令(程序阻塞后使用)

5.1 变量查看与打印

5.1.1 手动打印变量值(print/p)

- 命令:print(缩写p),支持格式化输出。

- 格式化字符表:

格式化字符(/fmt) 说明
/x 十六进制(整数)
/d 有符号十进制(整数)
/u 无符号十进制(整数)
/o 八进制(整数)
/t 二进制(整数)
/f 浮点数格式
/c 字符格式

- 示例:

1
2
3
4
5
6
(gdb) p i          # 十进制打印变量i
$5 = 3
(gdb) p/x i # 十六进制打印变量i
$6 = 0x3
(gdb) p/o i # 八进制打印变量i
$7 = 03

5.1.2 查看变量类型(ptype)

- 命令:ptype 变量名

- 示例:

1
2
3
4
(gdb) ptype i       # 查看变量i的类型
type = int
(gdb) ptype array # 查看数组array的类型
type = int [12]

5.1.3 自动打印变量(display)

区别于print:程序每次暂停(如单步、断点)时自动打印,适合跟踪变量变化。

  • 设置自动打印:display 变量名display/fmt 变量名
  • 查看自动打印列表:info display(缩写i display
  • 取消自动打印:undisplay 编号delete display 编号
  • 禁用/启用自动打印:disable display 编号 / enable display 编号

- 示例:

1
2
3
4
5
6
7
8
(gdb) display i        # 自动打印变量i
(gdb) display/x array[i] # 十六进制自动打印array[i]
(gdb) i display # 查看列表
Auto-display expressions now in effect:
Num Enb Expression
1: y i
2: y /x array[i]
(gdb) undisplay 1 # 取消编号1的自动打印

5.2 单步调试

程序阻塞后,逐行/逐函数调试,观察执行流程。

  • step(缩写s):逐行执行,会进入函数体内部
  • next(缩写n):逐行执行,不进入函数体内部(函数整体执行)
  • finish:从当前函数体内部跳出(需确保函数内无有效断点)
  • until:直接跳出循环体(条件:循环内无有效断点,需在循环开始/结束行执行)

- 示例:

1
2
3
4
(gdb) s          # 单步执行,进入函数
(gdb) finish # 跳出当前函数
(gdb) n # 单步执行,不进入函数
(gdb) until # 跳出循环

5.3 手动设置变量值

适用场景:快速让变量达到目标值(如循环因子、特殊条件值),提高调试效率。

- 命令:set var 变量名=目标值

- 示例:

1
2
(gdb) set var i=90  # 直接将变量i设为90
(gdb) set var count=0 # 将循环因子count设为0,重新执行循环

六、高频命令速查表

功能 完整命令 缩写 核心用法
启动GDB gdb 可执行程序 - gdb app
启动程序 run r r(停在第一个断点)
启动停main函数 start - start
继续运行 continue c c(到下一个断点)
设断点 break b b 12、b main、b test.cpp:8
查看断点 info break i b i b(查编号、状态)
删除断点 delete d d 1、d 2-5
单步(进函数) step s s
单步(不进函数) next n n
打印变量 print p p i、p/x i
查看代码 list l l、l 15、l test.cpp:main
退出GDB quit q q