用 gdb 调试 GCC 程序.docx
《用 gdb 调试 GCC 程序.docx》由会员分享,可在线阅读,更多相关《用 gdb 调试 GCC 程序.docx(10页珍藏版)》请在冰豆网上搜索。
用gdb调试GCC程序
用gdb调试GCC程序
Linux中包含有一个很有用的调试工具--gdb(GNUDebuger),它可以用来调试C和C++程序,功能不亚于Windows下的许多图形界面的调试工具。
和所有常用的调试工具一样,gdb提供了以下功能:
#监视程序中变量的值
#在程序中设置断点
#程序的单步执行
在使用gdb前,必须先载入可执行文件,因为要进行调试,文件中就必须包含调试信息,所以在用gcc或cc编译时就需要用-g参数来打开程序的调试选项。
调试开始时,必须先载入要进行调试的程序,可以用以下两种方式:
*在启动gdb后执行以下命令:
file可执行文件路径
*在gdb启动时就载入程序:
gdb可执行文件路径
载入程序后,接下来就是要进行断点的设置,要监视的变量的添加等工作,下面对在这个过程中常会用到的命令逐一进行介绍:
基本gdb命令.
file装入想要调试的可执行文件.
kill终止正在调试的程序.
list列出产生执行文件的源代码的一部分.
next执行一行源代码但不进入函数内部.
step执行一行源代码而且进入函数内部.
run执行当前被调试的程序
quit终止gdb
watch使你能监视一个变量的值而不管它何时被改变.
break在代码里设置断点,这将使程序执行到这里时被挂起.
make使你能不退出gdb就可以重新产生可执行文件.
shell使你能不离开gdb就执行UNIXshell命令.
命令详解
*list:
显示程序中的代码,常用使用格式有:
list
输出从上次调用list命令开始往后的10行程序代码。
list-
输出从上次调用list命令开始往前的10行程序代码。
listn
输出第n行附近的10行程序代码。
listfunction
输出函数function前后的10行程序代码。
*forward/search:
从当前行向后查找匹配某个字符串的程序行。
使用格式:
forward/search字符串
查找到的行号将保存在$_变量中,可以用print$_命令来查看。
*reverse-search:
和forward/search相反,向前查找字符串。
使用格式同上。
*break:
在程序中设置断点,当程序运行到指定行上时,会暂停执行。
使用格式:
break要设置断点的行号
*tbreak:
设置临时断点,在设置之后只起作用一次。
使用格式:
tbreak要设置临时断点的行号
*clear:
和break相反,clear用于清除断点。
使用格式:
clear要清除的断点所在的行号
*run:
启动程序,在run后面带上参数可以传递给正在调试的程序。
*awatch:
用来增加一个观察点(addwatch),使用格式:
awatch变量或表达式
当表达式的值发生改变或表达式的值被读取时,程序就会停止运行。
*watch:
与awatch类似用来设置观察点,但程序只有当表达式的值发生改变时才会停止运行。
使用格式:
watch变量或表达式
需要注意的是,awatch和watch都必须在程序运行的过程中设置观察点,即可运行run之后才能设置。
*commands:
设置在遇到断点后执行特定的指令。
使用格式有:
commands
设置遇到最后一个遇到的断点时要执行的命令
commandsn
设置遇到断点号n时要执行的命令
注意,commands后面跟的是断点号,而不是断点所在的行号。
在输入命令后,就可以输入遇到断点后要执行的命令,每行一条命令,在输入最后一条命令后输入end就可以结束输入。
*delete:
清除断点或自动显示的表达式。
使用格式:
delete断点号
*disable:
让指定断点失效。
使用格式:
disable断点号列表
断点号之间用空格间隔开。
*enable:
和disable相反,恢复失效的断点。
使用格式:
enable断点编号列表
*ignore:
忽略断点。
使用格式:
ignore断点号忽略次数
*condition:
设置断点在一定条件下才能生效。
使用格式:
condition断点号条件表达式
*cont/continue:
使程序在暂停在断点之后继续运行。
使用格式:
cont
跳过当前断点继续运行。
contn
跳过n次断点,继续运行。
当n为1时,cont1即为cont。
*jump:
让程序跳到指定行开始调试。
使用格式:
jump行号
*next:
继续执行语句,但是跳过子程序的调用。
使用格式:
next
执行一条语句
nextn
执行n条语句
*nexti:
单步执行语句,但和next不同的是,它会跟踪到子程序的内部,但不打印出子程序内部的语句。
使用格式同上。
*step:
与next类似,但是它会跟踪到子程序的内部,而且会显示子程序内部的执行情况。
使用格式同上。
*stepi:
与step类似,但是比step更详细,是nexti和step的结合。
使用格式同上。
*whatis:
显示某个变量或表达式的数据类型。
使用格式:
whatis变量或表达式
*ptype:
和whatis类似,用于显示数据类型,但是它还可以显示typedef定义的类型等。
使用格式:
ptype变量或表达式
*set:
设置程序中变量的值。
使用格式:
set变量=表达式
set变量:
=表达式
*display:
增加要显示值的表达式。
使用格式:
display表达式
*infodisplay:
显示当前所有的要显示值的表达式。
*deletedisplay/undisplay:
删除要显示值的表达式。
使用格式:
deletedisplay/undisplay表达式编号
*disabledisplay:
暂时不显示一个要表达式的值。
使用格式:
disabledisplay表达式编号
*enabledisplay:
与disabledisplay相反,使用表达式恢复显示。
使用格式:
enabledisplay表达式编号
*print:
打印变量或表达式的值。
使用格式:
print变量或表达式
表达式中有两个符号有特殊含义:
$和$$。
$表示给定序号的前一个序号,$$表示给定序号的前两个序号。
如果$和$$后面不带数字,则给定序号为当前序号。
*backtrace:
打印指定个数的栈帧(stackframe)。
使用格式:
backtrace栈帧个数
*frame:
打印栈帧。
使用格式:
frame栈帧号
*infoframe:
显示当前栈帧的详细信息。
*select-frame:
选择栈帧,选择后可以用infoframe来显示栈帧信息。
使用格式:
select-frame栈帧号
*kill:
结束当前程序的调试。
*quit:
退出gdb。
gdb应用举例
本节用一个实例教你一步步的用gdb调试程序.被调试的程序相当的简单,但它展示了gdb的典型应用.
下面列出了将被调试的程序.这个程序被称为greeting,它显示一个简单的问候,再用反序将它列出.
#include
main()
{
charmy_string[]="hellothere";
my_print(my_string);
my_print2(my_string);
}
voidmy_print(char*string)
{
printf("Thestringis%s",string);
}
voidmy_print2(char*string)
{
char*string2;
intsize,i;
size=strlen(string);
string2=(char*)malloc(size+1);
for(i=0;istring2[size-i]=string[i];
string2[size+1]=`';
printf("Thestringprintedbackwardis%s",string2);
}
用下面的命令编译它:
gcc–gtest.c-otest
这个程序执行时显示如下结果:
Thestringishellothere
Thestringprintedbackwardis
输出的第一行是正确的,但第二行打印出的东西并不是我们所期望的.我们所设想的输出应该是:
Thestringprintedbackwardiserehtolleh
由于某些原因,my_print2函数没有正常工作.让我们用gdb看看问题究竟出在哪儿,先键入如下命令:
gdbgreeting
--------------------------------------------------------------------------------
注意:
记得在编译greeting程序时把调试选项打开.
--------------------------------------------------------------------------------
如果你在输入命令时忘了把要调试的程序作为参数传给gdb,你可以在gdb提示符下用file命令来载入它:
(gdb)filegreeting
这个命令将载入greeting可执行文件就象你在gdb命令行里装入它一样.
这时你能用gdb的run命令来运行greeting了.当它在gdb里被运行后结果大约会象这样:
(gdb)run
Startingprogram:
/root/greeting
Thestringishellothere
Thestringprintedbackwardis
Programexitedwithcode041
这个输出和在gdb外面运行的结果一样.问题是,为什么反序打印没有工作?
为了找出症结所在,我们可以在my_print2函数的for语句后设一个断点,具体的做法是在gdb提示符下键入list命令三次,列出源代码:
(gdb)list
(gdb)list
(gdb)list
--------------------------------------------------------------------------------
技巧:
在gdb提示符下按回车健将重复上一个命令.
--------------------------------------------------------------------------------
第一次键入list命令的输出如下:
1#include
2
3main()
4{
5charmy_string[]="hellothere";
6
7my_print(my_string);
8my_print2(my_string);
9}
10
如果按下回车,gdb将再执行一次list命令,给出下列输出:
11my_print(char*string)
12{
13printf("Thestringis%s",string);
14}
15
16my_print2(char*string)
17{
18char*string2;
19intsize,i;
20
再按一次回车将列出greeting程序的剩余部分:
21size=strlen(string);
22string2=(char*)malloc(size+1);
23for(i=0;i24string2[size-i]=string[i];
25string2[size+1]=`';
26printf("Thestringprintedbackwardis%s",string2);
27}
根据列出的源程序,你能看到要设断点的地方在第24行,在gdb命令行提示符下键入如下命令设置断点:
(gdb)break24
gdb将作出如下的响应:
Breakpoint1at0x139:
filegreeting.c,line24
(gdb)
现在再键入run命令,将产生如下的输出:
Startingprogram:
/root/greeting
Thestringishellothere
Breakpoint1,my_print2(string=0xbfffdc4"hellothere")atgreeting.c:
24
24string2[size-i]=string[i]
你能通过设置一个观察string2[size-i]变量的值的观察点来看出错误是怎样产生的,做法是键入:
(gdb)watchstring2[size-i]
gdb将作出如下回应:
Watchpoint2:
string2[size-i]
现在可以用next命令来一步步的执行for循环了:
(gdb)next
经过第一次循环后,gdb告诉我们string2[size-i]的值是`h`.gdb用如下的显示来告诉你这个信息:
Watchpoint2,string2[size-i]
Oldvalue=0`00'
Newvalue=104`h'
my_print2(string=0xbfffdc4"hellothere")atgreeting.c:
23
23for(i=0;i这个值正是期望的.后来的数次循环的结果都是正确的.当i=10时,表达式string2[size-i]的值等于`e`,size-i的值等于1,最后一个字符已经拷到新串里了.
如果你再把循环执行下去,你会看到已经没有值分配给string2[0]了,而它是新串的第一个字符,因为malloc函数在分配内存时把它们初始化为空(null)字符.所以string2的第一个字符是空字符.这解释了为什么在打印string2时没有任何输出了.
现在找出了问题出在哪里,修正这个错误是很容易的.你得把代码里写入string2的第一个字符的的偏移量改为size-1而不是size.这是因为string2的大小为12,但起始偏移量是0,串内的字符从偏移量0到偏移量10,偏移量11为空字符保留.
为了使代码正常工作有很多种修改办法.一种是另设一个比串的实际大小小1的变量.这是这种解决办法的代码:
#include
main()
{
charmy_string[]="hellothere";
my_print(my_string);
my_print2(my_string);
}
my_print(char*string)
{
printf("Thestringis%s",string);
}
my_print2(char*string)
{
char*string2;
intsize,size2,i;
size=strlen(string);
size2=size-1;
string2=(char*)malloc(size+1);
for(i=0;istring2[size2-i]=string[i];
string2[size]=`';
printf("Thestringprintedbackwardis%s",string2);
}
本文来自CSDN博客,转载请标明出处:
file:
///D:
/2009Linux实习/2009%20Linux%20实习/Gbd调试器/Linux%20下的%20gbd调试%20-%20tianhappy(城市旅行者)%20-%20CSDN博客.htm