1.简介
在编译程序生成可执行文件之后,就进入了程序的调试环节。在程序中可能会有很多错 误需要进行调试。Linux 系统中包含了 GNU 调试程序 GDB(GNU DeBugger),它是一个用 来调试 C 和 C++ 程序的调试器。GDB 的高级特性会使得搜索错误更加高效。可以使程序 开发者在程序运行时观察程序的内部结构和内存的使用情况。使用 GDB 的优点还在于 GDB 支持嵌入式软件的交叉编译开发模式。当运行 GDB 的 Linux 平台通过串行端口连接到目标 板时,GDB 可以对运行在目标板上的应用程序进行调试
2.功能
- 启动程序,设置所有能影响程序运行的参数和环境。
- 能够让程序在指定断点处停止。
- 能够在程序停止时检查所有参数的情况。
- 能够根据指定条件改变程序的运行。
- 动态监视程序中的变量的值。
- 可以单步执行代码,观察程序的运行状态.
3.相关指令
需要注意的是,GDB 调试的是可执行文件,而不是源程序。如果想让 GDB 调试编译后 生成可执行文件,则在使用 GDB 工具调试程序之前必须使用带有-g 或-GDB 编译选项的 GCC 命令来编译源程序。下面是 GDB 的一些基本命令。
- file:装入想要调试的可执行文件。
- kill :终止正在调试的程序。
- list :列出产生执行文件的源代码的一部分。
- next :执行一行源代码,但不进入函数内部。
- step :执行一行源代码,而且进入函数内部。
- run :执行当前被调试的程序。
- quit :终止。
- gdbwatch:监视一个变量的值,而不管它何时被改变。
- break :在代码里设置断点, 这将使程序执行到这里时被挂起。
- make:不退出 GDB 就可以重新产生可执行文件。
- Shell :不离开 GDB 就执行 UNIX Shell 命令。
GDB 可以运行在许多模式下,这些模式是 GDB 运行时在命令行作为选项指定的。下面 是对这些模式的详细介绍。
- -nx 或-n:不执行任何初始化文件中的命令。一般情况下,在这个文件中的命令会将 所有的命令行参数传给 GDB 后执行。
- -quiet 或-q:安静模式。不输出介绍和版本信息。
- -batch:批处理模式。当批处理命令文件中的所有命令都被执行后,GDB 将返回状态 0。如果执行过程出错,将返回非 0。
- -cd DIRECTORY:把 DIRECTORY 作为 GDB 的工作目录,这时工作目录不再是当 前目录。
- -b BIT/S:为远程调试设置串口波特率。
- tty 设备名:使用其他设备作为程序的标准输入输出。
4.GDB使用实例
4.1.创建一个代码
vim test.c
4.2.添加代码到test.c中
#include <stdio.h>
#define S 10
int main() {
int a[S], i, max, min;
printf("Enter 10 integers:\n");
for (i = 0; i < S; i++) {
if (scanf("%d", &a[i]) != 1) {
printf("Invalid input. Please enter an integer.\n");
while (getchar() != '\n'); // 清除输入缓冲区直到遇到换行符
return 1;
}
}
max = min = a[0];
for (i = 1; i < S; i++) {
if (max < a[i]) max = a[i];
if (min > a[i]) min = a[i];
}
printf("Maximum value is %d\n", max);
printf("Minimum value is %d\n", min);
return 0;
}
4.3.编译
gcc -g test.c -o test
4.4.程序调试
4.4.1.进入 GDB
终端输入gdb
gdb
可以看出,在 GDB 的启动画面中指出了 GDB 的版本号和使用的库文件等信息。接着 就进入由“(gdb) ”开头的命令行界面。
4.4.2.加载程序
使用file
命令是用来加载一个可执行文件或者一个核心转储文件以便进行调试
file test
4.4.3.查看文件
在 GDB 中键入‘l’(list )就可以查看所载入的文件
在一般情况下,源代码中的行号与用户书写程序中的行号是一致的,但有时由于用户的某 些编译选项会导致行号不一致的情况,因此,要查看在 GDB 中的行号。
4.4.4.设置断点
设置断点可以使程序到一定位置暂停它的运行。程序员在该位置处可以方便地查看变量 的值和堆栈情况等,从而找出代码的问题所在。在 GDB 中设置断点非常简单,只需要在 “b”后加入对应的行号即可(这是最常用的方式,另外还有其他设置断点的方式)
需要注意的是,在 GDB 中利用行号设置断点是指代码在运行到对应行之前暂停。
4.4.5.查看断点处的情况
在设置完断点之后,用户可以键入“info b”来查看设置断点的情况。在 GDB 中可以 设置多个断点
4.4.6.运行代码
接下来就可以运行代码了。GDB 默认从首行开始运行代码,键入“r” (run)即可,在 “r”后面加上行号即可从程序中指定行开始运行
4.4.7.单步调试
输入“step”命令,程序运行一步
4.4.8.查看变量值。
在程序停止运行之后,程序员需要查看断点处的相关变量值。在 GDB 中只需键入“p+ 变量值”即可
GDB 在显示变量值时都会在对应值之前加上“$N”标记,它是当前变量值的引用标记, 所以若想再次引用此变量,就可以直接写作“$N”,而无需写冗长的变量名。
4.4.9.观察变量
在某一循环处,程序员往往希望能够观察一个变量的变化情况,这时就可以键入命令 watch 来观察变量的变化情况
在此处必须键入完整的命令“watch”,因为在 GDB 中有不少以‘w’开头的命令,如 “where”和“while”等。
4.4.10.退出 GDB
退出 GDB 只需使用指令“q” (quit )即可
4.5.GDB的帮助
在 GDB 输入“help”命令,显示的帮助信息
在“help”命令后面加上一个命令名称,可以显示这个命令的帮助信息。例如,输入 “help list”
4.6.设置/删除断点
GDB 中丰富的断点设置和删除命令,可以满足用户各个方面的需求。表 5-6 列出了 GDB 中常见的断点设置及删除命令
命 令 格 式 | 作 用 |
Info b | 查看所设的断点 |
break+设置断点的行号或函数名 | 用于在程序中的对应行设置断点 |
tbreak+行号或函数名 | 设置临时断点,到达后被自动删除 |
break+filename+行号 | 用于在指定文件的对应行设置断点 |
break+if+条件 | 在条件成立时停止 |
clear+要清除断点的行号 | 用于清除对应行的断点 |
delete+断点号 | 删除指定断点,其断点号为“info b”中的第一栏。若缺省断点号,则删除所有断点 |
disable+断点号 | 让所设断点暂时停止。如果要让多个编号处的断点停止,可将编号之间用空格隔开 |
awatch+表达式(变量) | 为表达式(变量)设置一个观察点,当表达式值有变化时停止程序 |
rwatch+表达式(变量) | 设置一个观察点,当表达式(变量)被程序读时,程序被暂停 |
watch+表达式(变量) | 同 awatch |
enable+断点号 | 激活被 disable 停止的断点 |
condition+断点号<条件表达式> | 修改对应断点的条件 |
ignore+断点号<n> | 在程序执行中忽略对应断点 n 次 |
step | 单步恢复程序运行,且进入函数调用 |
next | 单步恢复程序运行,但不进入函数调用 |
finish | 运行程序,直到当前函数完成返回 |
c | 继续执行函数,直到函数结束或遇到新的断点 |
如果程序是多线程的话,可以定义断点是否在所有的线程上,或是在某个特定的线程上。 当程序被 GDB 停住时,所有的运行线程都会被停住。这样可方便用户查看运行程序的总 体情况。而在恢复程序运行时,所有的线程也会被恢复运行。
4.7.各种相关命令
4.7.1.数据相关命令
GDB 中有丰富的数据相关命令,可以使用户以各种形式显示所要查看的数据。GDB 中运行数据相关命令见表
命 令 格 式 | 作 用 |
display+表达式 | 用于显示表达式的值。使用该命令后,每当程序运行到断点处都会显示表达式的值 |
info display | 查看 display 设置的自动显示的信息 |
delete+display 编号 | 用于删除一个要显示值的表达式 |
disable+display 编号 | 使一个要显示的表达式暂时无效 |
enable+display 编号 | 恢复要显示的表达式 |
undisplay+display 编号 | 用于结束某个表达式值的显示 |
whatis+变量 | 显示某个变量的数据类型 |
print(p)+变量或表达式 | 用来打印变量或表达式的值 |
set+变量=变量值 | 用来给变量赋值 |
x/<n/f/u> <addr> | 查看内存地址中的值。n、f、u 是可选参数。 n 是一个正整数,表示显示内存的长度;f 表示显示的格式;u 表示从当前地址往后请求 的字节数,如果不指定的话,GDB 默认是 4 个 Bytes |
一般地,GDB 会根据变量的类型输出变量的值。但也可以自定义 GDB 的输出的格式。 其命令格式为:print/变量名+格式,其中格式有以下几种方式。
- x:按十六进制格式显示变量。
- d:按十进制格式显示变量。
- u:按十六进制格式显示无符号整型。
- o:按八进制格式显示变量。
- t:按二进制格式显示变量。
- a:按十六进制格式显示变量。
- c:按字符格式显示变量。
- f :按浮点数格式显示变量
4.7.2.调试运行环境相关命令
在 GDB 中控制程序的运行也是非常方便的。用户可以自行设定变量值和调用函数等, 其具体命令见表
命 令 格 式 | 作 用 |
set args | 设置运行参数 |
show args | 查看运行参数 |
set width+数目 | 设置GDB的行宽 |
cd dir | 进入dir目录 |
run | 程序开始执行 |
return<返回值> | 改变程序流程,直接结束当前函数,并将指定值返回 |
call+函数 | 在当前位置执行所要运行的函数 |
4.7.3.堆栈相关命令
GDB 中也提供了多种堆栈相关命令,可以查看堆栈的情况和寄存器的情况等,其具体命令见表
命 令 格 式 | 作 用 |
backtrace 或 bt | 显示函数调用的所有栈框架的踪迹和当前函数的参数值 |
frame | 打印栈帧会打印出这些信息: 栈的层编号, 当前的函数名, 函数参数值, 函数所在文件及行号, 函数执行到的语句 |
info reg | 查看寄存器状态 |
info stack | 查看堆栈信息 |
up | 在堆栈中上移 |
down | 在堆栈中下移 |