网站搜索

GNU 调试器或 GDB:强大的 Linux 程序源代码调试工具


调试器在任何软件开发系统中都起着至关重要的作用。没有人可以一次性编写出没有错误的代码。在开发过程中,不断出现错误,需要解决以进一步增强。没有调试器的开发系统是不完整的。考虑到开源开发者社区,GNU Debugger 是他们的最佳选择。它还用于 UNIX 类型平台上的商业软件开发。

GNU 调试器,也称为gdb,允许我们在代码执行时或程序崩溃前尝试执行的操作中潜入。 GDB 基本上帮助我们做四件主要的事情来捕获源代码中的缺陷。

  1. 启动程序,指定可能影响一般行为的参数。
  2. 在指定条件下停止程序。
  3. 检查崩溃或程序何时停止。
  4. 更改代码并立即尝试修改后的代码。

我们可以使用 gdb 来调试用 C 和 C++ 编写的程序,而不需要付出太多的努力。截至目前,对其他编程语言(如 DModula-2Fortran)的支持是部分的。

GNU 调试器或 GDB 入门

GDB 使用 gdb 命令调用。在发出 gdb 时,它会显示一些有关平台的信息,并将您带入 (gdb) 提示符,如下所示。

[root@fedora20 ~]# gdb
样本输出
GNU gdb (GDB) Fedora 7.6.50.20130731-19.fc20 
Copyright (C) 2013 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law.  Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "x86_64-redhat-linux-gnu". 
Type "show configuration" for configuration details. 
For bug reporting instructions, please see: 
<http://www.gnu.org/software/gdb/bugs/>. 
Find the GDB manual and other documentation resources online at: 
<http://www.gnu.org/software/gdb/documentation/>. 
For help, type "help". 
Type "apropos word" to search for commands related to "word". 
(gdb)

输入 help list 列出 gdb 中可用的不同类别的命令。键入 help ,后跟类名称以获取该类中的命令列表。输入 help all 以获取所有命令的列表。如果命令名称缩写明确,则允许使用缩写。例如,您可以键入 n,而不是键入 nextc 表示继续,依此类推。

最常用的 GDB 命令

下表列出了常用的gdb命令。这些命令可以从 gdb 命令提示符 (gdb) 中使用。

Command

说明

run

开始执行程序

quit

退出 gdb

print expr

打印表达式,其中expr也可以是变量名称

next

转到下一行

step

进入下一行

continue

从当前行继续直到程序结束或下一个断点

请注意 stepnext 这两个命令之间的区别。如果下一行是函数调用,则 next 命令不会进入函数内部。而 step 命令可以进入函数内部并查看那里发生了什么。

与 GDB 的示例会话

考虑以下源代码。


// sum.c
#include <stdio.h> 

int sum (int a, int b) { 
	int c; 
	c = a + b; 
	return c; 
} 

int main() { 
	int x, y, z; 
	printf("\nEnter the first number: "); 
	scanf("%d", &x); 
	printf("Enter the second number: "); 
	scanf("%d", &y); 
	z = sum (x, y); 
	printf("The sum is %d\n\n", z); 
	return 0; 
}

为了调试输出文件,我们需要使用 -g 选项将其编译为 gcc,如下所示。

gcc -g sum.c -o sum

输出文件 sum 可以通过以下两种方式之一附加到 gdb:

1. 通过指定输出文件作为 gdb 的参数。

gdb sum

2. 使用 file 命令在 gdb 内运行输出文件。

gdb
(gdb) file sum

list 命令列出源代码文件中的行并移动指针。因此,第一个列表将显示前 10 行,下一个列表将显示接下来的 10 行,依此类推。

(gdb) list
1	#include <stdio.h>   
2	 
3	int sum (int a, int b) { 
4		int c; 
5		c = a + b; 
6		return c; 
7	} 
8	 
9	int main() { 
10		int x, y, z;

要开始执行,请发出run 命令。现在程序可以正常执行了。但是我们忘记在源代码中放置一些断点来调试,对吗?可以为函数或指定行指定这些断点。

(gdb) b main

注意:我使用了缩写b来表示break

在main函数中设置断点后,重新运行程序会停在第11行。如果事先知道行号,也可以实现同样的效果。

(gdb) b sum.c:11

现在使用 next n 命令逐步执行代码行。需要注意的是,next 命令不会进入函数代码内部,除非在函数上设置了断点。现在让我们尝试一下 print 命令。在函数 sum 上设置断点,如下所示。

(gdb) b sum 
Breakpoint 1 at 0x4005aa: file sum.c, line 5. 
(gdb) r 
Starting program: /root/sum 

Enter the first number: 2 
Enter the second number: 3 

Breakpoint 1, sum (a=2, b=3) at sum.c:5 
5		c = a + b; 
(gdb) p a 
$1 = 2 
(gdb) p b 
$2 = 3
(gdb) c 
Continuing. 
The sum is 5 

[Inferior 1 (process 3444) exited normally]

如果正在运行的程序需要命令行参数,则提供相同的参数以及 run 命令。

(gdb) run   . . .

与当前正在运行的程序关联的共享库文件可以列出为。

(gdb) info share 
From                To                  Syms Read   Shared Object Library 
0x00000035a6000b10  0x00000035a6019c70  Yes         /lib64/ld-linux-x86-64.so.2 
0x00000035a641f560  0x00000035a6560bb4  Yes         /lib64/libc.so.6

修改变量

GDB还能够在程序执行过程中修改变量。让我们试试这个。如上所述,在第 16 行设置断点并运行程序。

(gdb) r 
Starting program: /root/sum 

Enter the first number: 1 
Enter the second number: 2 

Breakpoint 1, main ( ) at sum.c:16 
16		printf("The sum is %d\n\n", z); 
(gdb) set z=4 
(gdb) c 
Continuing. 
The sum is 4

现在a=1b=2,结果应为z=3。但这里我们在main函数中将最终结果改为 z=4。通过这种方式,使用 gdb 可以使调试变得更加容易。

启用/禁用断点

要获取所有断点的列表,请输入 info Breakpoints

(gdb) info breakpoints 
Num     Type           Disp Enb Address            What 
1       breakpoint     keep y   0x00000000004005c2 in main at sum.c:11

这里只有一个断点,就是To。启用禁用断点指定断点编号以及禁用命令。要稍后启用,请使用enable命令。

(gdb) disable 1 
(gdb) info breakpoints 
Num     Type           Disp Enb Address            What 
1       breakpoint     keep n   0x00000000004005c2 in main at sum.c:11

您还可以使用delete命令删除断点。

调试正在运行的进程

GNU/Linux 系统中有许多进程在后台运行。要调试正在运行的进程,首先我们需要找到该特定进程的进程 ID。 pidof 命令为您提供进程的 pid。

pidof <process_name>

现在我们需要将此 pid 附加到 gdb。有两种方法。

1. 通过指定 pid 和 gdb。

gdb -p <pid>

2. 使用 gdb 中的 attach 命令。

(gdb) attach <pid>

目前为止就这样了。这些只是 gdb 调试源代码的良好开端的基础知识,它比上面解释的内容要多得多。例如,我们可以使用堆栈信息、环境变量等进行调试。尝试玩弄所有这些东西......