使用GDB调试简单的用户程序

GDB是GNU Debuger的缩写,支持C/C++的代码调试,还可以用来调试Pascal和Fortran程序。今天熟悉了一下VI编辑器和GCC、GDB的使用,总结一下:
 
1.写一个带bug的程序,2次提示用户输入字符,并显示输入内容。VI的使用还不是很熟悉,代码的卖相很差。
#include <stdio.h>
int main(void)
{
int i;
char input;
for(i=0;i<2;i++)
{
printf("pleast input a character:\n");
scanf("%c",&input);
switch(input){
case 'a':
printf("you input a.\n");
case 'b':
printf("you input b.\n");
default:
printf("what you input don't belong to the judgement of the program.\n");
}
}
return 0;
}
 
2.使用gcc编译原程序。
gaolu@gaolu-desktop:~$ ls -l
total 48484
//当前路径下文件
-rw-r--r-- 1 root  root       130 2009-02-22 21:34 etcnetworkinterface
lrwxrwxrwx 1 gaolu gaolu       26 2009-02-23 03:52 Examples -> /usr/share/example-content
drwxr-xr-x 9  1005  1005     4096 2009-02-23 22:56 fcitx-3.4.2
-rw-r--r-- 1 gaolu gaolu  3155032 2009-02-23 22:40 fcitx-3.4.2.tar.bz2
drwxr-xr-x 3 gaolu gaolu     4096 2009-02-23 22:56 fcitx-install
-rwxr-xr-x 1 gaolu gaolu     9117 2009-03-01 19:48 gao.lu
-rw-r--r-- 1 gaolu gaolu      351 2009-03-01 20:40 gao.lu.c
-rw-r--r-- 1 gaolu gaolu      351 2009-03-01 20:40 gao.lu.c~
-rwxr-xr-x 1 gaolu gaolu     9771 2009-03-01 19:52 gao.lu.debug
-rwxr-xr-x 1 gaolu gaolu     9771 2009-03-01 20:15 gao.lu.debug2
drwxrwxrwx 7 root  root      4096 2005-11-21 06:35 LumaQQ
-rw-r--r-- 1 gaolu gaolu 46335159 2009-02-23 22:25 lumaqq_2005-linux_gtk2_x86_with_jre.tar.gz 
................
// 编译gao.lu.c,生成gao.lu.debug3的带调试信息的文件
gaolu@gaolu-desktop:~$ gcc -o gao.lu.debug3 -g gao.lu.c
gaolu@gaolu-desktop:~$ ls -l
total 48496
-rw-r--r-- 1 root  root       130 2009-02-22 21:34 etcnetworkinterface
lrwxrwxrwx 1 gaolu gaolu       26 2009-02-23 03:52 Examples -> /usr/share/example-content
drwxr-xr-x 9  1005  1005     4096 2009-02-23 22:56 fcitx-3.4.2
-rw-r--r-- 1 gaolu gaolu  3155032 2009-02-23 22:40 fcitx-3.4.2.tar.bz2
drwxr-xr-x 3 gaolu gaolu     4096 2009-02-23 22:56 fcitx-install
-rwxr-xr-x 1 gaolu gaolu     9117 2009-03-01 19:48 gao.lu
-rw-r--r-- 1 gaolu gaolu      351 2009-03-01 20:40 gao.lu.c  //源文件
-rw-r--r-- 1 gaolu gaolu      351 2009-03-01 20:40 gao.lu.c~
-rwxr-xr-x 1 gaolu gaolu     9771 2009-03-01 19:52 gao.lu.debug
-rwxr-xr-x 1 gaolu gaolu     9771 2009-03-01 20:15 gao.lu.debug2
-rwxr-xr-x 1 gaolu gaolu     9771 2009-03-01 21:35 gao.lu.debug3 //生成文件
drwxrwxrwx 7 root  root      4096 2005-11-21 06:35 LumaQQ
-rw-r--r-- 1 gaolu gaolu 46335159 2009-02-23 22:25 lumaqq_2005-linux_gtk2_x86_with_jre.tar.gz
drwxr-xr-x 2 gaolu gaolu     4096 2009-03-01 20:49 mnt
................
 //执行生成文件
gaolu@gaolu-desktop:~$ ./gao.lu.debug3   
pleast input a character:
af      //enter
//对于第一个输入字符a,程序没有按照预期执行。
you input a.
you input b.
what you input don't belong to the judgement of the program.
//第二个字符f不与a,b匹配,输出信息为正确。
pleast input a character:
what you input don't belong to the judgement of the program.
gaolu@gaolu-desktop:~$

 
3.进入gdb环境调试
//加载可执行程序到gdb中,也可以先执行gdb进入环境,再通过file <文件名>进行加载。
gaolu@gaolu-desktop:~$ gdb gao.lu.debug3 
//GDB版本信息
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later < [url]http://gnu.org/licenses/gpl.html[/url]>
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 "i486-linux-gnu"...
 
//run命令执行可执行程序
(gdb) run    
Starting program: /home/gaolu/gao.lu.debug3
pleast input a character:
af
you input a.
you input b.
what you input don't belong to the judgement of the program.
pleast input a character:
what you input don't belong to the judgement of the program.
Program exited normally.
 
在GDB中加载可执行程序的目的不是执行,而是进行调试。非常有用的2个概念就是断点和观察点。断点的设置是“break 行号”,要知道具体的行号,可以用list命令显示可执行文件中的带行号代码信息。
(gdb)
(gdb)
(gdb) list
1 #include <stdio.h>

3 int main(void)
4 {

6 int i = 0;
7 char input;

9 for(i=0;i<2;i++)
10 {        
(gdb)
11 printf("pleast input a character:\n");
12 scanf("%c",&input);
13 
14 switch(input){
15 case 'a':
16 printf("you input a.\n");
17 case 'b':
18 printf("you input b.\n");
19 default:
20 printf("what you input don't belong to the judgement of the program.\n");
(gdb)
21 }
22 }
23 return 0;
24 } 
25  
26 
27 
28 
29 
30 
(gdb) break 12
Breakpoint 1 at 0x8048421: file gao.lu.c, line 12.
(gdb) break 16
Breakpoint 2 at 0x804844c: file gao.lu.c, line 16.
//info break可以查看当前设置的断点信息
(gdb) info break
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048421 in main at gao.lu.c:12
2       breakpoint     keep y   0x0804844c in main at gao.lu.c:16
//禁用断点2
(gdb) disable break 2
(gdb) info break
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048421 in main at gao.lu.c:12
2       breakpoint     keep   0x0804844c in main at gao.lu.c:16
//允许断点2
(gdb) enable break 2
(gdb) info break
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048421 in main at gao.lu.c:12
2       breakpoint     keep   0x0804844c in main at gao.lu.c:16
//执行带断点的程序
(gdb) run
//gdb提示开始执行/home/gaolu/下面的gao.lu.debug3 可执行程序
Starting program: /home/gaolu/gao.lu.debug3
pleast input a character:
//gdb提示遇到第一个断点以及断点信息
Breakpoint 1, main () at gao.lu.c:12
12 scanf("%c",&input);
//这个命令用来设置观察点,用于在程序运行过程中,变量取值变化时给出提示
(gdb) watch input
//gdb提示观察点设置成功
Hardware watchpoint 3: input
//next表示单步执行,如果执行到下一个断点使用continue
(gdb) next
//输入参数字符a回车
a
//gdb提示参数a发生变化,
Hardware watchpoint 3: input
Old value = -72 '?'
New value = 97 'a'
//gdb提示程序进入了库函数
0xb7f40cdc in _IO_vfscanf () from /lib/tls/i686/cmov/libc.so.6
(gdb) next
//gdb提示程序退出库函数,调用了函数库中的scanf
Single stepping until exit from function _IO_vfscanf,
which has no line number information.
0xb7f4a698 in scanf () from /lib/tls/i686/cmov/libc.so.6
(gdb) next
Single stepping until exit from function scanf,
which has no line number information.
Hardware watchpoint 3 deleted because the program has left the block
in which its expression is valid.
//进入switch case判断
main () at gao.lu.c:14
14 switch(input){
(gdb) next
//遇到第二个断点,当input=a时,执行所有的分支情况
Breakpoint 2, main () at gao.lu.c:16
16 printf("you input a.\n");
(gdb) next
you input a.
18 printf("you input b.\n");
(gdb) next
you input b.
20 printf("what you input don't belong to the judgement of the program.\n");
(gdb) next
what you input don't belong to the judgement of the program.
//开始第二轮循环
9 for(i=0;i<2;i++)
(gdb) next
11 printf("pleast input a character:\n");
(gdb) next
pleast input a character:
Breakpoint 1, main () at gao.lu.c:12
12 scanf("%c",&input);
(gdb) next
//直接回车,相当于把\n赋值给input
14 switch(input){
(gdb) next
//不与a.b匹配打印信息正确
20 printf("what you input don't belong to the judgement of the program.\n");
(gdb) next
what you input don't belong to the judgement of the program.
//程序判断是否还要执行for循环
9 for(i=0;i<2;i++)
(gdb) next
//程序返回0值
23 return 0;
(gdb) next
24 } 
(gdb) next
//退出main函数,程序执行结束
0xb7f04685 in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
(gdb) next
Single stepping until exit from function __libc_start_main,
which has no line number information.
Program exited normally.
(gdb) info break
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048421 in main at gao.lu.c:12
 breakpoint already hit 2 times
2       breakpoint     keep y   0x0804844c in main at gao.lu.c:16
 breakpoint already hit 1 time
(gdb)
 
 以上代码流程说明输入字符与第一个case匹配的时候,则会执行后面所有情况的printf语句;而满足最后一种情况的输入时,则只会打印最后一个printf信息。因此switch...case结构没有问题,主要问题在于满足某个case时,执行完语句没有及时跳出结构。每个printf 后面增加break即可。
 
值得一提的是GDB支持shell命令,比如(gdb)shell ls -l,也支持shell的自动补全,通过TAB键。 
其他几个命令:
delete break n    //删除第n个断点
print             //遇到断点时,可以使用print input打印变量input的值
whatis            //遇到断点时,可以使用whatis input打印变量input的类型
Quit              //退出GDB调试环境。

你可能感兴趣的:(linux,gcc,学习,vi编辑器,GDB调试)