1. 调试准备
-g 将调试信息写入到可执行程序中
gcc -g args.c -o app
项目程序如果是为了进行调试而编译时, 必须要打开调试选项(-g)。另外还有一些可选项:
在尽量不影响程序行为的情况下关掉编译器的优化选项(-O0),
-Wall选项打开所有 warning,
也可以发现许多问题,避免一些不必要的 bug。
2. 设置参数
gdb 可执行程序文件名
set args ...
show args
start 向下执行一行(从main开始)
c 继续
run/r 执行到断点或者执行完毕
q/quit 退出
3. 查看代码
3.1 当前文件
# 使用 list 和使用 l 都可以
# 从第一行开始显示
(gdb) list
# 列值这行号对应的上下文代码, 默认情况下只显示10行内容
(gdb) list 行号
# 显示这个函数的上下文内容, 默认显示10行
(gdb) list 函数名
3.2 切换文件
# 切换到指定的文件,并列出这行号对应的上下文代码, 默认情况下只显示10行内容
(gdb) l 文件名:行号
# 切换到指定的文件,并显示这个函数的上下文内容, 默认显示10行
(gdb) l 文件名:函数名
3.3 设置显示的行数
# 以下两个命令中的 listsize 都可以写成 list
(gdb) set listsize 行数
# 查看当前list一次显示的行数
(gdb) show listsize
4. 断点操作
4.1 设置断点
# 设置普通断点到当前文件
# 在当前文件的某一行上设置断点
# break == b
(gdb) b 行号
(gdb) b 函数名 # 停止在函数的第一行
# 设置普通断点到某个非当前文件上
# 在非当前文件的某一行上设置断点
(gdb) b 文件名:行号
(gdb) b 文件名:函数名 # 停止在函数的第一行
# 设置条件断点
# 必须要满足某个条件, 程序才会停在这个断点的位置上
# 通常情况下, 在循环中条件断点用的比较多
(gdb) b 行数 if 变量名==某个值
4.2 查看断点
# info == i
# 查看设置的断点信息
(gdb) i b #info break
# 举例
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400cb5 in main() at test.cpp:12
2 breakpoint keep y 0x0000000000400cbd in main() at test.cpp:13
3 breakpoint keep y 0x0000000000400cec in main() at test.cpp:18
4 breakpoint keep y 0x00000000004009a5 in insertionSort(int*, int)
at insert.cpp:8
5 breakpoint keep y 0x0000000000400cdd in main() at test.cpp:16
6 breakpoint keep y 0x00000000004009e5 in insertionSort(int*, int)
at insert.cpp:16
在显示的断点信息中有一些属性需要在其他操作中被使用, 下面介绍一下:
Num: 断点的编号, 删除断点或者设置断点状态的时候都需要使用
Enb: 当前断点的状态, y表示断点可用, n表示断点不可用
What: 描述断点被设置在了哪个文件的哪一行或者哪个函数上
4.3 删除断点
# delete == del == d
# 需要 info b 查看断点的信息, 第一列就是编号
(gdb) d 断点的编号1 [断点编号2 ...]
# 举例:
(gdb) d 1 # 删除第1个断点
(gdb) d 2 4 6 # 删除第2,4,6个断点
# 删除一个范围, 断点编号 num1 - numN 是一个连续区间
(gdb) d num1-numN
# 举例, 删除第1到第5个断点
(gdb) d 1-5
4.4 设置断点状态
# 设置断点无效
# 让断点失效之后, gdb调试过程中程序是不会停在这个位置的
# disable == dis
# 设置某一个或者某几个断点无效
(gdb) dis 断点1的编号 [断点2的编号 ...]
# 设置某个区间断点无效
(gdb) dis 断点1编号-断点n编号
# 让无效的断点生效
# enable == ena
# 设置某一个或者某几个断点有效
(gdb) ena 断点1的编号 [断点2的编号 ...]
# 设置某个区间断点有效
(gdb) ena 断点1编号-断点n编号
5. 调试命令
5.1 继续运行gdb
# continue == c
(gdb) continue
5.2 手动打印信息
5.2.1 打印变量值
| 格式化字符(fmt) |
说明 |
| %x |
以十六进制的形式打印出整数。 |
| %d |
以有符号、十进制的形式打印出整数。 |
| %u |
以无符号、十进制的形式打印出整数。 |
| %o |
以八进制的形式打印出整数。 |
| %t |
以二进制的形式打印出整数。 |
| %f |
以浮点数的形式打印变量或表达式的值。 |
| %c |
以字符形式打印变量或表达式的值。 |
# print == p
(gdb) p 变量名
# 如果变量是一个整形, 默认对应的值是以10进制格式输出, 其他格式请参考上表
(gdb) p/fmt 变量名
# 举例
(gdb) p i # 10进制
$5 = 3
(gdb) p/x i # 16进制
$6 = 0x3
(gdb) p/o i # 8进制
$7 = 03
5.2.2 打印变量类型
# 查看某个变量的类型
# 语法格式
(gdb) ptype 变量名
5.3 自动打印信息
5.3.1 设置变量名自动显示
# 每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动帮我们打印出来
# 在变量的有效取值范围内, 自动打印变量的值(设置一次, 以后就会自动显示)
(gdb) display 变量名
# 以指定的整形格式打印变量的值, 关于 fmt 的取值, 请参考 print 命令
(gdb) display/fmt 变量名
5.3.2 查看自动显示列表
# info == i
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1: y i
2: y array[i]
3: y /x array[i]
在展示出的信息中, 每个列的含义如下:
Num : 变量或表达式的编号,GDB 调试器为每个变量或表达式都分配有唯一的编号
Enb : 表示当前变量(表达式)是处于激活状态还是禁用状态,如果处于激活状态(用 y 表示),则每次程序停止执行,该变量的值都会被打印出来;反之,如果处于禁用状态(用 n 表示),则该变量(表达式)的值不会被打印。
Expression :被自动打印值的变量或表达式的名字。
5.3.3 取消自动显示
# 删除自动显示列表中的变量或表达式
# 命令中的 num 是通过 info display 得到的编号, 编号可以是一个或者多个
(gdb) undisplay num [num1 ...]
# num1 - numN 表示一个范围
(gdb) undisplay num1-numN
(gdb) delete display num [num1 ...]
(gdb) delete display num1-numN
# 如果不想删除自动显示的变量, 也可以禁用自动显示列表中处于激活状态下的变量或表达式
# 命令中的 num 是通过 info display 得到的编号, 编号可以是一个或者多个
(gdb) disable display num [num1 ...]
# num1 - numN 表示一个范围
(gdb) disable display num1-numN
# 当需要启用自动显示列表中被禁用的变量或表达式时, 可以使用下边的命令
# 命令中的 num 是通过 info display 得到的编号, 编号可以是一个或者多个
(gdb) enable display num [num1 ...]
# num1 - numN 表示一个范围
(gdb) disable display num1-numN
5.4 单步调试
5.4.1 step
# 从当前代码行位置, 一次调试当前行下的每一行代码
# step == s
# 如果这一行是函数调用, 执行这个命令, 就可以进入到函数体的内部
(gdb) step
5.4.2 finish
# 如果通过 s 单步调试进入到函数内部, 想要跳出这个函数体,如果想要跳出函数体必须要保证函数体内不能有有效断点,否则无法跳出
(gdb) finish
5.4.3 next
# next == n
# 如果这一行是函数调用, 执行这个命令, 不会进入到函数体的内部
(gdb) next
5.4.4 until
通过 until 命令可以直接跳出某个循环体,这样就能提高调试效率了。如果想直接从循环体中跳出, 必须要满足以下的条件,否则命令不会生效:
要跳出的循环体内部不能有有效的断点
必须要在循环体的开始/结束行执行该命令
(gdb) until
5.5 设置变量值
# 可以在循环中使用, 直接设置循环因子的值
# 假设某个变量的值在程序中==90的概率是5%, 这时候可以直接通过命令将这个变量值设置为90
(gdb) set var 变量名=值