《gdb调试之基础篇》

来源:互联网 发布:淘宝 买家秀图 编辑:程序博客网 时间:2024/05/21 22:43

        这篇文章通过一个简单的实例描述了gdb的基本用法,并对gdb支持的语言极其基本选项进行了介绍。对于有一定经验的建议看下一篇文章:《gdb调试之实用技巧篇》

1. gdb介绍

        gdbGNU发布的一款功能强大的程序调试工具,它可以让我们深入洞悉一个程序是怎么运行的,也可以帮我们记录一个程序在崩溃的时候所执行的操作。具体一点它可以帮我们完成下面四件事情

  • 启动我们的程序,并指定任何可以影响程序执行的条件。
  • 设置断点,让我们的程序停止在某处,然后查看堆栈是否正常。
  • 追踪程序出错时执行的代码。
  • 在程序运行中,调整参数,以测试潜在的bug

       就具体调试方法而言,根据使用场景不同,gdb调试可分为三种类型

  • 调试一个可执行文件
  • 调试一个coredump文件
  • 调试一个正在运行的进程

2. 一个简单的实例

       实际应用的时候,遇到的情况可能是千差万别的,也远比下面所要举的例子更加复杂和困难。这里先针对gdb三种调试类型的前两种举一个简单的实例,以期带你走进gdb的调试世界。下面的测试代码,先从终端输入两个字符串,然后再将其输出到终端。

编译执行

      编译上面的代码并执行,结果发现程序的输出结果不对,输入给b的内容本来是”01234”,但是输出的时候却变成了”ghijk”,而且发生了core dump(这里省略了glibc输出的memory map信息)。如下所示:

调试可执行文件

       可执行文件的调试参考附录A,从中我们知道字符串a的赋值后,b也被改变了。因为给a赋值的时候超过了给a开辟的空间长度。

调试coredump文件

       调试core文件的命令格式为:gdbPROGRAM CORE。根据gdb调试core文件的信息,可以知道发生core dump时程序正在执行的操作为test.c中的第18行代码,即free操作。

       综合上述信息,可知道b的输出错误是因为a赋值越界引起的,而产生coredump的原因是free出错。至于为什么free出错,其实也是因为a的赋值越界,导致glibc开辟给btrunk的头部信息被覆盖导致的。关于内存的错误可以参考附录B中的文档。

3. gdb支持的语言

       gdb能支持很多语言,可以在启动gdb之后执行”set language”来查看当前版本gdb所支持的语言。一般默认为C语言,可以用”show language”命令来查看,需要修改的话还是用”set language ***”,但请务必加上要设置的目标语言。


4. gdb的启动选项

       除了最简洁的启动办法(直接运行”gdb”就可以启动gdb,退出的话”ctrl+d”或者”quit”),gdb还支持很多命令行选项和参数,用于在启动gdb时就设置需要调试的内容以及调试方式。这些选项可以在gdbhelp文件中查找到,下表列出其中最为常用的一些选项:



5. gdb的内部命令

        gdb的内部命令,可用来设置gdb的调试环境并调试可执行文件。和shell一样,gdb环境下也支持tab命令补全特性。下表列出了常见的内部命令:



       除了上述内部命令的使用之外, gdb环境下也可直接执行shell命令,一般格式为”shell COMMAND”。这有一个例外,那就是make命令。


附录A------gdb调试可执行文件实例

[root@HPC-NQS share]# gdb test        >>>>>>>>>>>>>>>启动gdb时直接指定可执行文件

GNU gdb (GDB) Red Hat Enterprise Linux  (7.0.1-32.el5)

Copyright (C) 2009 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  "x86_64-redhat-linux-gnu".

For bug reporting instructions, please  see:

<http://www.gnu.org/software/gdb/bugs/>...

Reading symbols from  /data/yinsy/share/test...done.

(gdb) l               >>>>>>>>>>>>>>>显示(默认10行)源代码

1        #include<stdio.h>

2        #include<stdlib.h>

3        #include <string.h>

4

5        int main()

6        {

7           char* a=malloc(3);

8           char* b=malloc(5);

9

10          printf("please enter a string  for b:");

(gdb)                >>>>>>>>>>>>>>>直接按enter,重复上一条子命令

11          scanf("%s",b);

12          printf("please enter a string  for a:");

13           scanf("%s",a);

14          printf("address:  a=%p,b=%p\n",a,b);

15          printf("strlen :  a=%d,b=%d\n",strlen(a),strlen(b));

16          printf("content:  a=%s,b=%s\n",a,b);

17

18          free(a);

19          free(b);

20       }

(gdb) b 9            >>>>>>>>>>>>>>>在第9行设置断点

Breakpoint 1 at 0x40058c: file test.c,  line 9.

(gdb) b 17            >>>>>>>>>>>>>>>在第17行设置断点

Breakpoint 2 at 0x400657: file test.c,  line 17.

(gdb) i b              >>>>>>>>>>>>>>>显示已经设置的断点信息

Num      Type           Disp Enb  Address            What

1        breakpoint     keep y   0x000000000040058c in main at test.c:9

2        breakpoint     keep y   0x0000000000400657 in main at test.c:17

(gdb) r               >>>>>>>>>>>>>>>开始运行可执行文件

Starting program: /data/yinsy/share/test

 

Breakpoint 1, main () at test.c:10         >>>>>>>>>>>>>>>在第一个断点出停下来,等待命令

10          printf("please enter a string  for b:");

(gdb) p a             >>>>>>>>>>>>>>>打印指针a的值,以及其指向地址的内容,当前为空

$1 = 0x601010 ""

(gdb) p b            >>>>>>>>>>>>>>>打印指针b的值,以及其指向地址的内容,当前为空

$2 = 0x601030 ""

(gdb) s              >>>>>>>>>>>>>>>单步执行

11          scanf("%s",b);

(gdb)               >>>>>>>>>>>>>>>继续单步执行,给b赋值“01234”

please enter a string for b:01234

12          printf("please enter a string  for a:");

(gdb)

13          scanf("%s",a);

(gdb) p b           >>>>>>>>>>>>>>>给a赋值前,打印b指针及其指向地址的内容,仍为“01234”

$3 = 0x601030 "01234"

(gdb) s

please enter a string for  a:abcdefghijklmnopqrstuvwxyzabcdefghijk

14          printf("address:  a=%p,b=%p\n",a,b);

(gdb) p a

$4 = 0x601010 "abcdefghijklmnopqrstuvwxyzabcdefghijk"

(gdb) p b           >>>>>>>>>>>>>>>给a赋值后,b指针指向地址的内容也发生变化,变为“ghijk”

$5 = 0x601030 "ghijk"

(gdb) c             >>>>>>>>>>>>>>>继续运行程序,直到遇到第二个断点暂停

Continuing.

address: a=0x601010,b=0x601030

strlen : a=37,b=5

content: a=abcdefghijklmnopqrstuvwxyzabcdefghijk,b=ghijk

 

Breakpoint 2, main () at test.c:18

18          free(a);

(gdb) s             >>>>>>>>>>>>>>>继续单步执行free(a)操作,程序出现错误,glibc提示invalid next size

*** glibc detected ***  /data/yinsy/share/test: free(): invalid next size (fast): 0x0000000000601010  ***

======= Backtrace: =========

/lib64/libc.so.6[0x3e13c7245f]

/lib64/libc.so.6(cfree+0x4b)[0x3e13c728bb]

/data/yinsy/share/test[0x400660]

/lib64/libc.so.6(__libc_start_main+0xf4)[0x3e13c1d994]

/data/yinsy/share/test[0x4004b9]

======= Memory map: ========

00400000-00401000 r-xp 00000000 08:06  674109                              /data/yinsy/share/test

00600000-00601000 rw-p 00000000 08:06  674109                              /data/yinsy/share/test

00601000-00622000 rw-p 00601000 00:00  0                                   [heap]

3893600000-389360d000 r-xp 00000000 08:05 278756                          /lib64/libgcc_s-4.1.2-20080825.so.1

389360d000-389380d000 ---p 0000d000 08:05 278756                          /lib64/libgcc_s-4.1.2-20080825.so.1

389380d000-389380e000 rw-p 0000d000 08:05 278756                          /lib64/libgcc_s-4.1.2-20080825.so.1

3e13800000-3e1381c000 r-xp 00000000 08:05  278556                          /lib64/ld-2.5.so

3e13a1b000-3e13a1c000 r--p 0001b000 08:05  278556                         /lib64/ld-2.5.so

3e13a1c000-3e13a1d000 rw-p 0001c000 08:05  278556                          /lib64/ld-2.5.so

3e13c00000-3e13d4e000 r-xp 00000000 08:05  283255                          /lib64/libc-2.5.so

3e13d4e000-3e13f4e000 ---p 0014e000 08:05  283255                          /lib64/libc-2.5.so

3e13f4e000-3e13f52000 r--p 0014e000 08:05  283255                          /lib64/libc-2.5.so

3e13f52000-3e13f53000 rw-p 00152000 08:05  283255                          /lib64/libc-2.5.so

3e13f53000-3e13f58000 rw-p 3e13f53000  00:00 0

2aaaaaaab000-2aaaaaaaf000 r-xp  2aaaaaaab000 00:00 0                       [vdso]

2aaaaaaaf000-2aaaaaab3000 rw-p  2aaaaaaaf000 00:00 0

2aaaaaade000-2aaaaaadf000 rw-p  2aaaaaade000 00:00 0

7ffffffea000-7ffffffff000 rw-p 7ffffffe9000  00:00 0                      [stack]

ffffffffff600000-ffffffffffe00000 ---p  00000000 00:00 0                   [vsyscall]

 

Program received signal SIGABRT, Aborted.

0x0000003e13c30265 in raise () from  /lib64/libc.so.6

(gdb) s

Single stepping until exit from function  raise,

which has no line number information.

 

Program terminated with signal SIGABRT,  Aborted.

The program no longer exists.

(gdb) q             >>>>>>>>>>>>>>>退出gdb调试

附录B------深入理解glibc的内存管理

相关资料无法插入本文档,以下链接供参考。

1)http://gee.cs.oswego.edu/dl/html/malloc.html

2)https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=1120d4df8487b78a9f1ceb5394968d6ab651986e;hb=439bda3209b768c349b98b8ceecf0fa8d94600e9

3) http://blog.csdn.net/phenics/article/details/777053

4)http://stackoverflow.com/questions/10943907/linux-allocator-does-not-release-small-chunks-of-memory

5) http://www.cnblogs.com/sunyubo/archive/2010/05/05/2282170.html

6) http://www.ibm.com/developerworks/cn/linux/l-memory/

7)http://www.cnblogs.com/sunyubo/archive/2010/05/05/2282170.html

0 0
原创粉丝点击