GDB简单教程

来源:互联网 发布:句子迷 知乎 编辑:程序博客网 时间:2024/04/27 10:09

本文的内容基本来自http://www.cs.cmu.edu/~gilpin/tutorial/这篇教程,我在使用里面的示例程序时遇到了”<iostream.h> is not a file or directory” 的错误,因此修改了一下原来到源程序。

源代码:

为了使读者更快地学习gdb,本文提供了一个带有bug的示例程序,以及一个简单的makefile,我把他们打包上传到这里,不需积分即可下载。在学习本文到过程中,读者可以通过调试这个示例程序来获得更好的体验。
这个示例程序很简单,包含两个类:Node和LinkedList。为了方便调试,我们将这两个类放到一个文件中。

前期准备

环境设置

首先检查是否安装gdb。如果您的系统中有g++,那么gdb就已经安装了。可以通过在命令行中输入gdb -v来检查是否安装gdb。

Debugging Symbols

gdb只能使用g++产生的symbol进行调试。如果读者使用Sun Cc编译器,那么可以使用一个和gdb很类似到调试工具:dbx
在调试带有debugging symbol的程序时,gdb才能如鱼得水。使用g++的-g选项,即可编译出带有gdb的debugging symbol的程序。除-g选项外,还可以使用-ggdb选项,本文的makefile里面即使用了-ggdb选项。

使用GDB调试

编译程序

首先,切换到含有前面下载的两个文件的目录,然后使用make命令进行编译。
make -f makefile
编译完成后,会生成一个名为main的可执行文件。

加载程序

使用gdb main命令即可将main可执行文件加载到gdb中。在我的终端,使用这个命令的结果如下:
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 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 "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/jubin/Downloads/gdb_sample/main...done.
(gdb)
(注:在emacs中,您可以使用M-x gdb来在emacs中使用gdb。Emacs将分成两个窗口,第二个窗口将显示代码,并有个箭头指向正在执行的指令所在的代码行。)

gdb启动后,此时正在等待用户输入下一个指令。因为需要查看程序错在哪里,所以首先需要运行这个程序,输入run命令:
(gdb) run
Starting program: /home/jubin/Downloads/gdb_sample/main
Creating Node, 1 are in existence right now
Creating Node, 2 are in existence right now
Creating Node, 3 are in existence right now
Creating Node, 4 are in existence right now
The fully created list is:
4
3
2
1
Now removing elements:
Creating Node, 5 are in existence right now
Destroying Node, 4 are in existence right now
4
3
2
1
Program received signal SIGSEGV, Segmentation fault.
0x08048cb4 in Node<int>::next (this=0x0) at main.cc:30
30Node<T>* next () const { return next_; }
(gdb)
显然,这段程序出错了,下面我们来分析下错误出在什么地方。

检查出错信息

从上面的出错信息可以看出在main.cc的第30行,this指针指向了0。但同时我们还想知道谁调用了第30行,以及调用程序的当时状态。在gdb提示符中输入:backtrace
(gdb) backtrace
#0  0x08048cb4 in Node<int>::next (this=0x0) at main.cc:30
#1  0x08048bea in LinkedList<int>::remove (this=0x804c008, item_to_remove=@0xbffff2c4) at main.cc:79
#2  0x080488d6 in main (argc=1, argv=0xbffff3a4) at main.cc:122
(gdb)
从上面的信息不仅可以看到出错的方法和局部变量,还可以找到调用第30行的程序以及调用时使用的参数item_to_remove的存储地址。x命令可以使我们根据item_to_remove的地址获得item_to_remove的值:
(gdb) x 0xbffff2c4
0xbffff2c4:0x00000001
(gdb)

从上面的信息可以看出,当使用参数“1”调用LinkedList<int>::remove时,程序出错。

条件断点

现在我们知道哪里出错了,下一步要做的是查看在出错前程序的状态。一种方法是步进,直到快出错的那个位置,另一种就是设置断点,在gdb中这样实现:

(gdb) break LinkedList<int>::remove

Breakpoint 1 at 0x8048ab3: file main.cc, line 54.

(gdb)

这样位于 LinkedList<int>::remove的断点“1”就设置好了。如果我们只想查看item_to_remove == 1时的状态,那么需要使用条件断点,在gdb中输入:


(gdb) condition 1 item_to_remove == 1
(gdb)
这个命令的意思是只有在“item_to_remove == 1”的情况下,断点“1”才会生效。

步进

gdb中步进的命令是step。gdb有一个很好的特性,当用户只输入回车时默认执行上一个命令,因此步进时只需在第一步输入step,后面直接敲击回车就可以了。
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/jubin/Downloads/gdb_sample/main
Creating Node, 1 are in existence right now
Creating Node, 2 are in existence right now
Creating Node, 3 are in existence right now
Creating Node, 4 are in existence right now
The fully created list is:
4
3
2
1

Now removing elements:
Creating Node, 5 are in existence right now
Destroying Node, 4 are in existence right now
4
3
2
1


Breakpoint 1, LinkedList<int>::remove (this=0x804c008, item_to_remove=@0xbffff2f4)
   at main.cc:54
54   Node<T> *marker = head_;
(gdb) step
55   Node<T> *temp = 0;  // temp points to one behind as we iterate
(gdb)
57   while (marker != 0) {
(gdb)
58     if (marker->value() == item_to_remove) {
(gdb)
Node<int>::value (this=0x804c058) at main.cc:32
32 const T& value () const { return value_; }
(gdb)
LinkedList<int>::remove (this=0x804c008, item_to_remove=@0xbffff2f4) at main.cc:77
77     marker = 0;  // reset the marker
(gdb)
78     temp = marker;
(gdb)
79     marker = marker->next();
(gdb)
Node<int>::next (this=0x0) at main.cc:30
30 Node<T>* next () const { return next_; }
(gdb)
Program received signal SIGSEGV, Segmentation fault.
0x08048cb4 in Node<int>::next (this=0x0) at main.cc:30
30 Node<T>* next () const { return next_; }
(gdb)
离开gdb的命令:q或quit

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
通过上面的内容,相信您已经可以充满自信地使用gdb了,下面将补充一些常用的gdb命令:
continue or c (continue的简写) :程序中断后继续运行
next:程序中断后不进入函数,与step对应
info break:查看断点
disable break <断点号>,如disable break 1:使<断点号>号断点失效
delete break <断点号>:删除<断点号>号断点
list:列出代码行,一般是10行
clear <断点句>:与break对应,后面的内容就是创建断点时break后面的内容,清楚某断点
breakpoint or b:创建断点,有两种用法。
b <函数名>:设置函数断点
b <文件名:行号>:在某文件的某行设置断点