Debugging with GDB

一:

GDB是GNU开源组织发布的一个强大的程序调试工具(UNIX WINDOWS都可以)。

一般来说,GDB主要帮助你完成下面四个方面的功能:

1,启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。

2,可以让被调试的程序在你所指定的位置的断点处停住。(断点也可以是条件表达式)

3,当程序被停住时,可以检查此时你的程序中所发生的事情。

4,动态的改变你程序的执行环境。

看一个简单的列子:

 1 #include <stdio.h>
 2 
 3 int func(int n)
 4 {
 5     int sum = 0, i;
 6     for (i = 0; i < n; i++)
 7     {
 8         sum += i;
 9     }
10     return sum;
11 }
12 
13 main()
14 {
15     int i;
16     long result = 0;
17     for (i = 1; i <= 100; i++)
18     {
19         result += 1;
20     }
21 
22     printf("result[1-100]=%d\n", result);
23     printf("result[1-500]=%d\n", func(500));
24 }

####

list(l)命令:

(gdb) list 1
1 #include <stdio.h>
2
3 int func(int n)
4 {
5 int sum = 0, i;
6 for (i = 0; i < n; i++)
7 {
8 sum += i;
9 }
10 return sum;
(gdb)
11 }
12
13 main()
14 {
15 int i;
16 long result = 0;
17 for (i = 1; i <= 100; i++)
18 {
19 result += 1;
20 }
(gdb)
21
22 printf("result[1-100]=%d\n", result);
23 printf("result[1-500]=%d\n", func(500));
24 }
(gdb)
Line number 25 out of range; tst.c has 24 lines.
(gdb)

####

和断点(break)有关的命令:

(gdb) break 16
Breakpoint 1 at 0x4004ce: file tst.c, line 16.
(gdb) list 16
11 }
12
13 main()
14 {
15 int i;
16 long result = 0;
17 for (i = 1; i <= 100; i++)
18 {
19 result += 1;
20 }
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004004ce in main at tst.c:16
(gdb) break func
Breakpoint 2 at 0x40049f: file tst.c, line 5.
(gdb) list func
1 #include <stdio.h>
2
3 int func(int n)
4 {
5 int sum = 0, i;
6 for (i = 0; i < n; i++)
7 {
8 sum += i;
9 }
10 return sum;
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004004ce in main at tst.c:16
2 breakpoint keep y 0x000000000040049f in func at tst.c:5

####

常用的最基础的gdb调试命令:

run:运行程序(运行到断点或者程序结束)

next:单条语句执行

continue:继续运行程序(必须先有run才能有continue,继续运行,运行到下一个断点或者是程序结束)

print:打印信息

bt:查看堆栈信息

finish:退出当前函数

quit:退出gdb

二:

一般来说GDB主要是调试c/c++的程序,要调试c/c++的程序,首先在编译的时候,我们必须把调试的信息加到可执行文件中。使用编译器(cc/gcc/g++)的-g参数可以做到这一点。如:

cc -g hello.c -o hello

g++ -g hello.c -o hello

gcc -g hello.c -o hello

如果没有-g,你将看不见程序的函数名、变量名、所替代的全是运行是的内存地址。让你用-g把调试信息加入之后,并成功编译目标代码以后,就可以用GDB来调试他了。

启动GDB的方法有以下几种:

1,gdb [program]

program一般是当前的可可行文件,一般在当前目录下。

2,gdb [program] core

用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。

3,gdb [program] [PID]

如果你的程序是一个服务程序,那么你就可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试他。progr应该在PATH环境变量中搜索的到。

 

在GDB环境中,你可以执行UNIX的shell的命令,使用GDB的shell命令来完成:

shell [command string]

调用UNIX的shell来执行command string,环境变量shell中定义的UNIX的shell将会被用来执行command string,如果shell还没有定义,那就是用UNIX的标准shell:/bin/sh (在Windows中使用Commad.com或者cmd.exe)

还有一个GDB命令是make:

make [make-argv]

可以在GDB中执行make命令来重新build自己的程序,这个命令等价于"shell make [make-argv]"

 

在GDB中运行程序:

当以gdb [program] 方式启动gdb后,gdb会在PATH路径和当前目录中搜索[program]的源文件。如果要确认gdb是否读到源文件,可以使用l或者list命令,看看gdb是否能列出源代码。

 

调试已经运行的程序:

两种方法:

1,在UNIX下线用ps查看正在运行的程序的PID,然后用gdb [program] PID格式挂载正在运行的程序。

2,先用gdb [program]关联上源代码,并进行gdb,在gdb中用attach来挂接住进程的PID,并用detach来取消挂载的进程。

在调试程序中,暂停程序运行是必须的,GDB可以方便地暂停程序的运行。你可以设置程序在哪行停住,在什么条件下停住,在收到什么信号的时候停住等等。以便于你查看运行时的变量,已经运行时的流程。

当进程被gdb停住时,你可以使用info program来查看程序是否在运行,进程号,被暂停的原因。

在gdb中,我们可以有以下几种暂停方式:断点(breakp)、观测点(watchpoint)、捕捉点(catchpoint)、信号(signals)、线程停止(Thread Stops)。如果要回复程序的运行,可以使用continue命令。

一,设置断点breakpoint

我们用break命令来设置断点,有几个设置断点的方法:

break [function]

在进入指定函数时停住。

break [linenum]

在指定行号停住。

break +offset

break -offset

在当前行号的前面或者后面的offset行停住,offset为自然数。

break filename:linenum

在源文件filename的linenum行停住

break filename:function

在源文件filename的function函数的入口处停住。

break *address

在程序运行的内存地址处停住。

break

break命令没有参数时,表示在下一条指令处停住。

break ... if condition

...可以是上述的参数,condition表示条件,在条件成立时停住。比如在循环中,可以设置break if i==100,表示当i为100时停住程序。

查看断点时,可以使用info命令,如下所示:(n表示断点号)

info breakpoints [n]

info break [n]

二,设置观察点(watchpoint)

观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,马上停住程序。有下面几种方法来设置观察点:

watch [expr]

为表达式(变量)expr设置一个观测点,一旦表达式值有变化时,马上停住程序。

rwatch [expr]

当表达式(变量)expr被读时,停住程序。

awatch  [expr]

当表达式(变量)的值被读或者被写时,停住程序。

info watchpoints

列出当前所设置了的所有观察点。

三,设置捕捉点(catchpoint)

你可以设置捕捉点来捕捉程序运行时的一些事件。如:载入共享库(动态链接库)或者c++的异常。设置捕捉点的格式为:

catch [event]

当event发生时,停住程序。evnet可以是下面的内容:

1,throw一个c++抛出的异常 (throw为关键字)

2,catch一个c++捕捉到的一场 (catch为关键字)

3,exec调用系统调用exec时(exec为关键字,目前此功能只在hp-ux下有用)

4,fork调用系统调用fork时。(fork为关键字,目前此功能只在hp-ux下有用)

5,load或者load [libname]载入共享库(动态链接库)时。(load为关键字,目前此功能只在hp-ux下有用)

6,unload或unload [libname]卸载共享库(动态链接库)时。(unload为关键字,目前此功能只在hp-ux下有用)

四、维护停止点

上面说了如何设置程序的停止点,GDB中的停止点也就是上述的三类。在GDB中,如果你觉得已经定义好的停止点没有用了,你可以使用delete clear disable enable这几个命令来进行维护。

clear

清除所有的已经定义的停止点。

clear [function]

clear [filename:function]

清除在所有设置在函数上的停止点。

clear [linenum]

clear [filename:linenum]

清除所有设置在指定行上的停止点。

delete [breakpoints] [range...]

删除指定的断点,breakpoins为断点号,如果不指定断点号,则表示删除所有的断点。range表示断点号的范围(如3-7)。其简写命令为d。

比删除更好的一种方法是disable停止点,disable了的停止点,GDB不会删除,当你还需要时,enable即可,就好象回收站一样。

五,信号signals

信号是一种软中断,是一种处理异步事件的方法。一般来说,操作系统都支持许多信号。尤其是UNIX,比较重要应用程序一般都会处理信号。UNIX定义了许多信号,比如SIGINT表示中断字符信号,也就是Ctrl+C的信号,SIGBUS表示硬件故障的信号;SIGCHLD表示子进程状态改变信号;SIGKILL表示终止程序运行的信号,等等。信号量编程是UNIX下非常重要的一种技术。

GDB有能力在你调试程序的时候处理任何一种信号,你可以告诉GDB需要处理哪一种信号。你可以要求GDB收到你所指定的信号时,马上停住正在运行的程序,以供你进行调试,你可以使用GDB的handle命令来完成这一功能。

handle [signal] [keywords...]

在GDB中定义一个信号处理,信号[signal]可以以SIG开头或不以SIG开头,可以用定义一个要处理信号的范围(如:SIGIO-SIGKILL,表示处理从SIGIO到SIGKILL的信号,其中包括SIGIO,SIGIOT,SIHKILL三个信号),也可以使用关键字all来表明要处理的所有的信号。一旦被调试的程序接收到信号,运行程序马上会被GDB住,以供调试。

六,线程(Thread Stops)

如果你程序是多线程的话,你可以定义你的断点是否在所有的线上上,或是在某个特定的线程。GDB很容易帮你完成这一工作。

break [linespec] thread [threadno]

break [linespec] thread [threadno] if...

linespec指定了断点设置在的源程序的行号。threadno指定了线程的id,注意,这个id是GDB分配的,你可以通过”info threads“命令来查看正在运行程序中的线程信息。如果你不指定thread [threadno]则表示你的断点设在所有的线程上面。

七:查看

posted @ 2013-09-09 10:46  jiezhao  阅读(711)  评论(0编辑  收藏  举报