分类:
2010-01-04 14:46:02
摘自 华清远见《嵌入式linux应用程序开发详解》第三章
这里给出了一个短小的程序,由此带领读者熟悉一下 Gdb 的使用流程。建议读者能够实际动手操作。首先,打开 Linux 下的编辑器 Vi 或者 Emacs,编辑如下代码:
|
在保存退出后首先使用 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 列出的源代码中明确地给出了对应的行号,这样就可以大大地方便代码的定位。
(2)设置断点
设置断点是调试程序中是一个非常重要的手段,它可以使程序到一定位置暂停它的运行。因此,程序员在该位置处可以方便地查看变量的值、堆栈情况等,从而找出代码的症结所在。在 Gdb 中设置断点非常简单,只需在“b”后加入对应的行号即可(这是最常用的方式,另外还有其他方式设置断点) 。如下所示:
(Gdb) b 6
Breakpoint 1 at 0×804846d: file test.c, line 6.
要注意的是,在 Gdb 中利用行号设置断点是指代码运行到对应行之前将其停止,如上例中,代码运行到第 6 行之前暂停(并没有运行第 6 行)。
(3)查看断点情况
在设置完断点之后,用户可以键入“info b”来查看设置断点情况,在 Gdb 中可以设置多个断点。
(Gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0×0804846d 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 0×5fb000
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)中。故在这种状态下可以查看函数的变量值等各种属性。但在函数处于“停止”状态之后, “栈”就会自动撤销,它也就无法查看各种信息了。
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 中的命令进行相关的操作,其功能极其强大。
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 中设置断点与恢复的常见命令: info b 查看所设断点 break 行号或函数名 <条件表达式> 设置断点 tbreak 行号或函数名 <条件表达式> 设置临时断点,到达后被自动删除 delete [断点号] 删除指定断点,其断点号为“info b”中的第一栏。若缺省断点号则删除所有断点 disable [断点号]] 停止指定断点,使用“info b”仍能查看此断点。同 delete 一样,省断点号则停止所有断点 enable [断点号] 激活指定断点,即激活被 disable 停止的断点 condition [断点号] <条件表达式> 修改对应断点的条件 ignore [断点号] 在程序执行中,忽略对应断点 num 次 step 单步恢复程序运行,且进入函数调用 next 单步恢复程序运行,但不进入函数调用 finish 运行程序,直到当前函数完成返回 c 继续执行函数,直到函数结束或遇到新的断点
由于设置断点在 Gdb 的调试中非常重要,所以在此再着重讲解一下 Gdb 中设置断点的方法。
Gdb 中设置断点有多种方式:其一是按行设置断点,设置方法在 上面已经指出,在此就不重复了。另外还可以设置函数断点和条件断点,在此结合上面的代码,具体介绍后两种设置断点的方法。
函数断点
Gdb 中按函数设置断点只需把函数名列在命令“b”之后,如下所示:
(gdb) b sum
Breakpoint 1 at 0×80484ba: file test.c, line 16.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0×080484ba in sum at test.c:16
要注意的是,此时的断点实际是在函数的定义处,也就是在 16 行处(注意第 16 行还未执行)。
条件断点
Gdb 中设置条件断点的格式为:b 行数或函数名 if 表达式。具体实例如下所示:
(gdb) b 8 if i==10
Breakpoint 1 at 0×804848c: file test.c, line 8.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0×0804848c 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==10”的条件断点,在程序运行之后可以看出,程序确实在 i 为 10 时暂停运行。
3.Gdb 中源码查看相关命令
在 Gdb 中可以查看源码以方便其他操作,它的常见相关命令:
list <行号>|<函数名> 查看指定位置代码 file [文件名] 加载指定文件 forward-search 正则表达式 源代码前向搜索 reverse-search 正则表达式 源代码后向搜索 dir dir 停止路径名 show directories 显示定义了的源文件搜索路径 info line 显示加载到 Gdb 内存中的代码
4.Gdb 中查看运行数据相关命令
Gdb 中查看运行数据是指当程序处于“运行”或“暂停”状态时,可以查看的变量及表达式的信息,其常见命令:
print 表达式|变量 查看程序运行时对应表达式和变量的值 x查看内存变量内容。其中 n 为整数表示显示内存的长度,f 表示显示的格式,u 表示从当前地址往后请求显示的字节数 display 表达式 设定在单步运行或其他情况中,自动显示的对应表达式的内容
5.Gdb 中修改运行参数相关命令
Gdb 还可以修改运行时的参数,并使该变量按照用户当前输入的值继续运行。它的设置方法为:在单步执行的过程中,键入命令“set 变量=设定值”。这样,在此之后,程序就会按照该设定的值运行了。下面,笔者结合上面的代码将 n 的初始值设为 4,其代码如下所示:
(Gdb) b 7
Breakpoint 5 at 0×804847a: 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 的使用切记点: