The NoteBook of EricKong

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks
Gdb 调试器
调试是所有程序员都会面临的问题。如何提高程序员的调试效率,更好更快地定位程序中的问题从而加快程序开发的进度,是大家共同面对的。就如读者熟知的Windows下的一些调试工具,如VC自带的如设置断点、单步跟踪等,都受到了广大用户的赞赏。那么,在Linux下有什么很好的调试工具呢?
本文所介绍的Gdb 调试器是一款GNU 开发组织并发布的UNIX/Linux 下的程序调试工具。虽然,它没有图形化的友好界面,但是它强大的功能也足以与微软的VC 工具等媲美。
下面就请跟随笔者一步步学习Gdb调试器。
3.5.1 Gdb使用流程
这里给出了一个短小的程序,由此带领读者熟悉一下Gdb 的使用流程。建议读者能够实
际动手操作。
首先,打开Linux 下的编辑器Vi或者Emacs,编辑如下代码(由于为了更好地熟悉Gdb的操作,笔者在此使用Vi 编辑,希望读者能够参见3.3 节中对Vi 的介绍,并熟练使用Vi)。
/*test.c*/
#include <stdio.h>
int sum(int m);
int main()
{
int i,n=0;
sum(50);
for(i=1; i<=50; i++)
{
n += i;
}
printf("The sum of 1-50 is %d \n", n );
}
int sum(int m)
{
int i,n=0;
for(i=1; i<=m;i++)
n += i;
printf("The sum of 1-m is %d\n", n);
}
在保存退出后首先使用Gcc对test.c进行编译,注意一定要加上选项“-g”,这样编译出的可执行代码中才包含调试信息,否则之后Gdb 无法载入该可执行文件。
[root@localhost Gdb]# gcc -g test.c -o test
虽然这段程序没有错误,但调试完全正确的程序可以更加了解Gdb 的使用流程。接下来就启动Gdb 进行调试。注意,Gdb 进行调试的是可执行文件,而不是如“.c”的源代码,因此,需要先通过Gcc编译生成可执行文件才能用Gdb进行调试。
[root@localhost Gdb]# gdb test
GNU Gdb Red Hat Linux (6.3.0.0-1.21rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db
library "/lib/libthread_db.so.1".
(gdb)
可以看出,在Gdb 的启动画面中指出了Gdb 的版本号、使用的库文件等信息,接下来就进入了由“(gdb)”开头的命令行界面了。
(1)查看文件
在 Gdb 中键入“l”(list)就可以查看所载入的文件,如下所示:
注意
在Gdb的命令中都可使用缩略形式的命令,如“l”代便“list”,“b”代表“breakpoint”,“p”代表“print”等,读者也可使用“help”命令查看帮助信息。
(Gdb) l
1 #include <stdio.h>
2 int sum(int m);
3 int main()
4 {
5 int i,n=0;
6 sum(50);
7 for(i=1; i<=50; i++)
8 {
9 n += i;
10 }
(Gdb) l
11 printf("The sum of 1~50 is %d \n", n );
12
13 }
14 int sum(int m)
15 {
16 int i,n=0;
17 for(i=1; i<=m;i++)
18 n += i;
19 printf("The sum of 1~m is = %d\n", n);
20 }
可以看出,Gdb 列出的源代码中明确地给出了对应的行号,这样就可以大大地方便代码的定位。
(2)设置断点
设置断点是调试程序中是一个非常重要的手段,它可以使程序到一定位置暂停它的运行。因此,程序员在该位置处可以方便地查看变量的值、堆栈情况等,从而找出代码的症结所在。
在 Gdb 中设置断点非常简单,只需在“b”后加入对应的行号即可(这是最常用的方式,另外还有其他方式设置断点)。如下所示:
(Gdb) b 6
Breakpoint 1 at 0x804846d: file test.c, line 6.
要注意的是,在Gdb 中利用行号设置断点是指代码运行到对应行之前将其停止,如上例中,代码运行到第5行之前暂停(并没有运行第5行)。
(3)查看断点情况
在设置完断点之后,用户可以键入“info b”来查看设置断点情况,在Gdb 中可以设置
多个断点。
(Gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804846d in main at test.c:6
(4)运行代码
接下来就可运行代码了,Gdb默认从首行开始运行代码,可键入“r”(run)即可(若想从程序中指定行开始运行,可在r 后面加上行号)。
(Gdb) r
Starting program: /root/workplace/Gdb/test
Reading symbols from shared object read from target memory...done.
Loaded system supplied DSO at 0x5fb000
Breakpoint 1, main () at test.c:6
6 sum(50);
可以看到,程序运行到断点处就停止了。
(5)查看变量值
在程序停止运行之后,程序员所要做的工作是查看断点处的相关变量值。在Gdb 中只需
键入“p”+变量值即可,如下所示:
(Gdb) p n
$1 = 0
(Gdb) p i
$2 = 134518440
在此处,为什么变量“i”的值为如此奇怪的一个数字呢?原因就在于程序是在断点设置的对应行之前停止的,那么在此时,并没有把“i”的数值赋为零,而只是一个随机的数字。但变量“n”是在第四行赋值的,故在此时已经为零。
小技巧
Gdb 在显示变量值时都会在对应值之前加上“$N”标记,它是当前变量值的引用标记,所以以后若想再次引用此变量就可以直接写作“$N”,而无需写冗长的变量名。
(6)单步运行
单步运行可以使用命令“n”(next)或“s”(step),它们之间的区别在于:若有函数调用的时候,“s”会进入该函数而“n”不会进入该函数。因此,“s”就类似于VC等工具中的
“step in”,“n”类似与VC等工具中的“step over”。它们的使用如下所示:
(Gdb) n
The sum of 1-m is 1275
7 for(i=1; i<=50; i++)
(Gdb) s
sum (m=50) at test.c:16
16 int i,n=0;
可见,使用“n”后,程序显示函数sum的运行结果并向下执行,而使用“s”后则进入到sum函数之中单步运行。
(7)恢复程序运行
在查看完所需变量及堆栈情况后,就可以使用命令“c”(continue)恢复程序的正常运行了。这时,它会把剩余还未执行的程序执行完,并显示剩余程序中的执行结果。以下是之前使用“n”命令恢复后的执行结果:
(Gdb) c
Continuing.
The sum of 1-50 is :1275
Program exited with code 031.
可以看出,程序在运行完后退出,之后程序处于“停止状态”。
小知识
在Gdb中,程序的运行状态有“运行”、“暂停”和“停止”3种,其中“暂停”状态为程序遇到了断点或观察点之类的,程序暂时停止运行,而此时函数的地址、函数参数、函数内的局部变量都会被压入“栈”(Stack)中。故在这种状态下可以查看函数的变量值等各种属性。但在函数处于“停止”状态之后,“栈”就会自动撤销,它也就无法查看各种信息了。
3.5.2 Gdb基本命令
Gdb 的命令可以通过查看help 进行查找,由于Gdb 的命令很多,因此Gdb 的help 将其分成了很多种类(class),用户可以通过进一步查看相关class找到相应命令。如下所示:
(gdb) help
List of classes of commands:
aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
Type "help" followed by a class name for a list of commands in that class.
Type "help" followed by command name for full documentation.
Command name abbreViations are allowed if unambiguous.
上述列出了Gdb 各个分类的命令,注意底部的加粗部分说明其为分类命令。接下来可以
具体查找各分类种的命令。如下所示:
(gdb) help data
Examining data.
List of commands:
call -- Call a function in the program
delete display -- Cancel some expressions to be displayed when program stops
delete mem -- Delete memory region
disable display -- Disable some expressions to be displayed when program stops
Type "help" followed by command name for full documentation.
Command name abbreViations are allowed if unambiguous.
至此,若用户想要查找call命令,就可键入“help call”。
(gdb) help call
Call a function in the program.
The argument is the function name and arguments, in the notation of the
current working language. The result is printed and saved in the value
history, if it is not void.
当然,若用户已知命令名,直接键入“help [command]”也是可以的。
Gdb 中的命令主要分为以下几类:工作环境相关命令、设置断点与恢复命令、源代码查看命令、查看运行数据相关命令及修改运行参数命令。以下就分别对这几类的命令进行讲解。
1.工作环境相关命令
Gdb中不仅可以调试所运行的程序,而且还可以对程序相关的工作环境进行相应的设定,甚至还可以使用shell 中的命令进行相关的操作,其功能极其强大。表3.10 所示为Gdb 常见工作环境相关命令。
表3.10 Gdb 工作环境相关命令
命令格式 含义
set args 运行时的参数指定运行时参数,如set args 2
show args 查看设置好的运行参数
path dir 设定程序的运行路径
show paths 查看程序的运行路径
set enVironment var [=value] 设置环境变量
show enVironment [var] 查看环境变量
cd dir 进入到dir目录,相当于shell中的cd命令
pwd 显示当前工作目录
shell command 运行shell的command命令
2.设置断点与恢复命令
Gdb 中设置断点与恢复的常见命令如表3.11 所示。
表 3.11 Gdb 设置断点与恢复相关命令
命令格式  含义
bnfo b 查看所设断点
break 行号或函数名 <条件表达式> 设置断点
tbreak 行号或函数名 <条件表达式> 设置临时断点,到达后被自动删除
delete [断点号] 删除指定断点,其断点号为“info b”中的第一栏。若缺省断点号则删除所有断点
disable [断点号]] 停止指定断点,使用“info b”仍能查看此断点。同delete一样,省断点号则停止所有断点
enable  [断点号] 激活指定断点,即激活被disable停止的断点
condition [断点号] <条件表达式> 修改对应断点的条件
ignore [断点号]<num> 在程序执行中,忽略对应断点num次
step 单步恢复程序运行,且进入函数调用
next 单步恢复程序运行,但不进入函数调用
finish 运行程序,直到当前函数完成返回
c 继续执行函数,直到函数结束或遇到新的断点
由于设置断点在Gdb 的调试中非常重要,所以在此再着重讲解一下Gdb中设置断点的方法。Gdb 中设置断点有多种方式:其一是按行设置断点,设置方法在3.5.1节已经指出,在此就不重复了。另外还可以设置函数断点和条件断点,在此结合上一小节的代码,具体介绍后两种设置断点的方法。
① 函数断点
Gdb 中按函数设置断点只需把函数名列在命令“b”之后,如下所示:
(gdb) b sum
Breakpoint 1 at 0x80484ba: file test.c, line 16.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x080484ba in sum at test.c:16
要注意的是,此时的断点实际是在函数的定义处,也就是在16 行处(注意第16 行还未
执行)。
② 条件断点
Gdb 中设置条件断点的格式为:b 行数或函数名if 表达式。具体实例如下所示:
(gdb) b 8 if i==10
Breakpoint 1 at 0x804848c: file test.c, line 8.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804848c in main at test.c:8
stop only if i == 10
(gdb) r
Starting program: /home/yul/test
The sum of 1-m is 1275
Breakpoint 1, main () at test.c:9
9 n += i;
(gdb) p i
$1 = 10
可以看到,该例中在第8 行(也就是运行完第7 行的for 循环)设置了一个“i==0”的条件断点,在程序运行之后可以看出,程序确实在i为10 时暂停运行。
3.Gdb 中源码查看相关命令
在 Gdb 中可以查看源码以方便其他操作,它的常见相关命令如表3.12 所示。
表3.12 Gdb 源码查看相关相关命令
命令格式 含义
list <行号>|<函数名> 查看指定位置代码
file [文件名] 加载指定文件
forward-search  正则表达式源代码前向搜索
reverse-search  正则表达式源代码后向搜索
dir dir 停止路径名
show directories 显示定义了的源文件搜索路径
info line 显示加载到Gdb内存中的代码
4.Gdb 中查看运行数据相关命令
Gdb 中查看运行数据是指当程序处于“运行”或“暂停”状态时,可以查看的变量及表
达式的信息,其常见命令如表3.13 所示:
表3.13 Gdb 查看运行数据相关命令
命令格式 含义
print 表达式|变量查看程序运行时对应表达式和变量的值
x <n/f/u>   查看内存变量内容。其中n为整数表示显示内存的长度,f表示显示的格式,u表示从当前地址往后请求显示的字节数
display 表达式设定在单步运行或其他情况中,自动显示的对应表达式的内容
5.Gdb 中修改运行参数相关命令
Gdb 还可以修改运行时的参数,并使该变量按照用户当前输入的值继续运行。它的设置方法为:在单步执行的过程中,键入命令“set 变量=设定值”。这样,在此之后,程序就会按照该设定的值运行了。下面,笔者结合上一节的代码将n的初始值设为4,其代码如
下所示:
(Gdb) b 7
Breakpoint 5 at 0x804847a: file test.c, line 7.
(Gdb) r
Starting program: /home/yul/test
The sum of 1-m is 1275
Breakpoint 5, main () at test.c:7
7 for(i=1; i<=50; i++)
(Gdb) set n=4
(Gdb) c
Continuing.
The sum of 1-50 is 1279
Program exited with code 031.
可以看到,最后的运行结果确实比之前的值大了4。
Gdb的使用切记点:
· 在Gcc编译选项中一定要加入“-g”。
· 只有在代码处于“运行”或“暂停”状态时才能查看变量值。
· 设置断点后程序在指定行之前停
posted on 2014-01-15 15:59 Eric_jiang 阅读(371) 评论(2)  编辑  收藏 所属分类: C 编程

Feedback

# re: Gdb 调试器 2014-01-16 15:25 puyufanyi.com
http://www.xuexi111.com/book/jisuanji/73042.html  回复  更多评论
  

# re: Gdb 调试器 2014-01-22 14:18 puyufanyi.com
http://fs.houxue.com/xuexiao-48030/#p=IMAGE78534  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: