文章目录
- 简介
- GDB 的介绍
- GDB 的使用
- GDB 常用命令及示例
- 查看相关操作
- 断点相关操作
- 运行相关操作
- 变量相关操作
- 分隔窗口操作
简介
GDB 的介绍
GDB 是 GNU 调试程序,是用来调试 C 和 C++ 程序的调试器。它可以让程序开发者在程序运行时观察程序的内部结构和内存的使用情况。它是一个非图形化界面的纯命令行调试器,提供了强大的功能和灵活的选项,使得开发者能够更轻松地诊断和解决程序中的问题。
GDB 的使用非常依赖于命令行参数和选项,因此需要熟悉 GDB 的命令行语法和各种选项,GDB 调试程序通常有以下几种方式:
-
启动 GDB 时同时加载待调试程序。使用命令
gdb file_name
来启动,并同时加载待调试程序。 -
先启动 GDB,再加载、运行待调试程序。使用命令
gdb
来启动 GDB,然后使用命令load file_name
来加载待调试程序,并使用命令run
来运行程序。 -
使用 GDB 开启源码界面、界面布局设置。在 GDB 命令行界面输入命令
source file_name
可以开启源码界面,使用命令layout all
来设置界面布局。
除了以上常用的命令外,GDB 还提供了很多其他的命令和功能,可以使用命令 gdb help
或 man gdb
来查看完整的命令列表和帮助文档。
GDB 的使用
在 Linux 系统中,通常默认发布的版本为 Release 版本,这个版本的程序在编译时会被优化,以提高程序的执行效率。但是,这样做会导致程序中的调试信息被删除,使得我们无法直接使用 GDB 进行调试。
因此,如果需要使用 GDB 调试程序,就需要以 Debug 版本发布程序,要将 Release 版本的程序发布为 Debug 版本,可以使用 GCC 编译器的原文件选项 -o
指定可执行文件的名称,再使用 -g
参数来加入调试信息。其中,参数 -g
的作用是在生成的可执行文件中加入 调试信息 ,这样就可以使用 GDB 进行调试了。
举个例子,如果我们有一个 Release 版本名为 gdb_test.c
的程序,想要将它发布为 Debug 版本,可以使用以下命令。
gcc -g gdb_test.c -o test
显然,Release 版本比 Debug 版本多占一些空间,即调试信息所占的空间,如下图所示。
然后,使用命令 gdb test
启动 GDB 对 test 程序进行调试。
GDB 常用命令及示例
假设 test.c
文件是一个通过递归调用来计算 3 的阶乘的程序,该程序的具体代码如下所示。
#include <stdio.h>
int cal(int n)
{
if (n == 1) {
return 1;
} else {
return n * cal(n - 1);
}
}
int main()
{
int n = 3;
int s;
s = cal(n);
printf("%d! = %d\n", n, s);
return 0;
}
在 Linux 系统终端下执行命令 gcc -g test.c -o test
对其进行编译,其中,参数 g
的作用是把调试信息加入生成的 test 可执行文件中,否则 GDB 就无法对 test 进行调试。
接下来,使用命令 gdb test
启动 GDB 对 test 进行调试了,如下图所示。
可以看到,GDB 首先显示了版本信息和库信息,随后 GDB 停留在符号 (gdb)
处等待用户输入调试命令。GDB 提供了大量的命令来实现各种调试功能,下面仅对一些常用的命令进行介绍。
查看相关操作
在调试程序时,GCC 会给出产生警告或错误的代码行数,但在普通的文本环境中是无法直接获得语句的行数。
(1) list/l
:在 GDB 中,可以通过命令 l
( list
的缩写)可以查看程序代码,如下图所示。
(2) list/l 行号
:从某行开始显示源代码,不加行号默认从第一行开始显示,连续 l
接着上次的位置往下列(可以直接回车默认输入上次的指令),每次列 10 行,如下图所示。
(3) list/l 函数名
:表示列出某个函数的源代码,即从某个函数开始显示 10 行代码,也可以继续向下显示,如下图所示。
(4)info/i locals
:查看当前堆栈页的所有变量,如下图所示。
可以看出,该命令可以显示出该堆栈的所有变量的值。
(5)where/backtrace/bt
:显示当前调用的堆栈列表信息,如下图所示。
断点相关操作
在 GDB 中,断点是调试程序的重要方法。通过在程序的关键位置设置断点,可以让程序在执行到这些位置时停下来,从而让我们可以观察程序每一步的执行状况(例如,当前变量的值、函数是否调用、堆栈使用情况等)。
在 GDB 中,可以使用命令 b
( breakpoints
的缩写)来设置断点,通过命令 info/i beark/b
查看断点的情况及位置信息。
(1)break/b 行号
:在某一行设置断点,设置断点后,通过命令 i b
查看各个断点情况,如下图所示。
(2)break/b 函数名
:在某个函数开头设置断点,设置后断点的行数为函数的第一行代码,如下图所示。
可以看到,命令 break/b
在程序的指定位置处设置了断点,并显示了该断点在内存中的物理地址。
(3) delete/d 断点号 n
:删除序号为 n 的断点,如下图所示。
(4) delete breakpoints/d
:删除所有的断点,如下图所示。
(5) disable 序号 n
:禁用序号为 n 的断点,如下图所示。
注意:断点在禁用后,断点会继续保留,但是在运行时并不会在该断点处停止。
(6) disable breakpoints/b
:禁用所有的断点,如下图所示。
(7) enable 断点号 n
:启用序号为 n 的断点,如下图所示。
(8) enable breakpoints/b
:启用所有的断点,如下图所示。
运行相关操作
(1) run/r
:在 GDB 中,通过命令 r
( run
的缩写)运行程序,如下图所示。
可以看出,GDB 默认从代码的首行开始运行(也可以通过 r 行数
的方式让程序从指定行数开始运行),如果程序中有断点,则程序会在断点行数的前一行暂停运行。
(2) continue/c
:从当前位置开始连续执行程序,遇到断点会停止运行,如下图所示。
(3) next/n
:不进入函数,逐过程执行。在执行时会显示当前执行的语句和返回值,如下图所示。
(4) step/s
:进入函数,逐语句执行。在执行时会显示当前执行的语句和返回值,如下图所示。
(5) finish
:运行程序直到当前函数完成返回,并打印函数返回时的堆栈地址、返回值和参数值等信息,如下图所示。
变量相关操作
(1) print/p 变量名
:查看当前变量的值,如下图所示。
可以看出,GDB 通过 $N
($1
、$2
)来显示变量的值,这样在下次查看变量值时,就可以用 $N
代替变量名了。
(2)set var 变量名 = value
:修改变量的值,如下图所示。
(3)display 变量名
:跟踪查看一个变量,每次停下来都显示它的值,跟踪显示变量时是有序号的,如下图所示。
分隔窗口操作
分隔窗口方便一边查看代码,一边进行测试。
(1)layout src
:显示代码窗口,效果如下图所示。
(2)layout asm
:显示反汇编窗口,效果如下图所示。
(3)layout regs
:显示源代码/反汇编和 CPU 寄存器窗口,效果如下图所示。
(4)layout split
:显示源代码和反汇编窗口,效果如下图所示。
-
参考链接: GDB 官网
-
参考书籍:《高质量嵌入式 Linux C编程(梁庚 著)