GDB使用简介

需要调试的program必须含有调试信息,编译时加上-g选项

启动 gdb 三种方法:

(1)gdb <program>

调试可执行程序program

(2)gdb <program> core

同时调试运行程序和core文件,core记录了程序出错时的一些内存环境和出错信息。

(3)gdb <program> <PID>

attach一个正在运行的程序,调试。

break func

break 23   在23行设置断点

info break  查看断点

run (r) 运行

next ( n ) 单条语句执行

continue (c)继续运行程序

print  var  (p) 打印变量

backtrace (bt)查看函数堆栈

bt n  最内n层帧

bt -n 最外n层帧

finish 退出函数

frame n  选择第n帧

info local 打印所有局部变量

#include "stdio.h"
#include "stdlib.h"
void func1()
{
    int a = 1;
    func2(a);
}
void func2(int t)
{
    //int b = t/0;
    char *buf;
    buf = malloc(1<<31);
    //free(b);
    fgets(buf,123,stdin);
}
int main()
{
    func1();
    return 0;
}
ron@ubuntu:~/文档/chenxuyuan$ cc -g core_test.c -o core_test
core_test.c:8: warning: conflicting types for ‘func2’
core_test.c:6: note: previous implicit declaration of ‘func2’ was here
ron@ubuntu:~/文档/chenxuyuan$ ./core_test 
hello
Segmentation fault
ron@ubuntu:~/文档/chenxuyuan$ ulimit -c unlimited
ron@ubuntu:~/文档/chenxuyuan$ ./core_test 
hello
Segmentation fault (core dumped)
ron@ubuntu:~/文档/chenxuyuan$ gdb core_test core

 

Core was generated by `./core_test'.
Program terminated with signal 11, Segmentation fault.
#0  0x0043ce73 in _IO_getline_info () from /lib/tls/i686/cmov/libc.so.6
(gdb) bt
#0  0x0043ce73 in _IO_getline_info () from /lib/tls/i686/cmov/libc.so.6
#1  0x0043cda1 in _IO_getline () from /lib/tls/i686/cmov/libc.so.6
#2  0x0043bdea in fgets () from /lib/tls/i686/cmov/libc.so.6
#3  0x0804848f in func2 (t=1) at core_test.c:14
#4  0x0804845c in func1 () at core_test.c:6
#5  0x0804849c in main () at core_test.c:18
(gdb) frame 3
#3  0x0804848f in func2 (t=1) at core_test.c:14
14      fgets(buf,123,stdin);
(gdb) info local
buf = 0x0
(gdb) kill
Kill the program being debugged? (y or n) y
You can't do that without a process to debug.
(gdb) b 12
Breakpoint 1 at 0x8048464: file core_test.c, line 12.
(gdb) r
Starting program: /home/ron/文档/chenxuyuan/core_test 
                       
Breakpoint 1, func2 (t=1) at core_test.c:12
12      buf = malloc(1<<31);
(gdb) p buf
$1 = 0x1449d5 "\213\006\205\300u\365[^]ÐU\211\345VS\350%"
(gdb) n
14      fgets(buf,123,stdin);
(gdb) p buf
$2 = 0x0
(gdb)

 

Core was generated by `./core_test'.
Program terminated with signal 11, Segmentation fault.
#0  0x0053be73 in _IO_getline_info () from /lib/tls/i686/cmov/libc.so.6
(gdb) bt
#0  0x0053be73 in _IO_getline_info () from /lib/tls/i686/cmov/libc.so.6
#1  0x0053bda1 in _IO_getline () from /lib/tls/i686/cmov/libc.so.6
#2  0x0053adea in fgets () from /lib/tls/i686/cmov/libc.so.6
#3  0x0804848f in func2 (t=1) at core_test.c:14
#4  0x0804845c in func1 () at core_test.c:6
#5  0x0804849c in main () at core_test.c:18
(gdb) bt -4
#2  0x0053adea in fgets () from /lib/tls/i686/cmov/libc.so.6
#3  0x0804848f in func2 (t=1) at core_test.c:14
#4  0x0804845c in func1 () at core_test.c:6
#5  0x0804849c in main () at core_test.c:18
(gdb) bt full
#0  0x0053be73 in _IO_getline_info () from /lib/tls/i686/cmov/libc.so.6
No symbol table info available.
#1  0x0053bda1 in _IO_getline () from /lib/tls/i686/cmov/libc.so.6
No symbol table info available.
#2  0x0053adea in fgets () from /lib/tls/i686/cmov/libc.so.6
No symbol table info available.
#3  0x0804848f in func2 (t=1) at core_test.c:14
        buf = 0x0
#4  0x0804845c in func1 () at core_test.c:6
        a = 1
#5  0x0804849c in main () at core_test.c:18
No locals.
(gdb)
 

1、GDB 是什么?
 GDB(GNU symbolic debugger)简单地说就是一个调试工具。
许可证即GPL保护的自由软件。
2、GDB特性
  象所有的调试器一样,GDB可以让你调试一个程序,包括让程序在你希望的地方
停下,此时你可以查看变量,寄存器,内存及堆栈。更进一步你可以修改变量及内存
值。GDB是一个功能很强大的调试器,它可以调试多种语言。在此我们仅涉及C和C++
的调试,而不包括其它语言。还有一点要说明的是,GDB是一个调试器,而不象VC一
样是一个集成环境。你可以使用一些前端工具如XXGDB,DDD等。他们都有图形化界面
,因此使用更方便,但它们仅是GDB的一层外壳。因此,你仍应熟悉GDB命令。事实上
,当你使用这些图形化界面时间较长时,你才会发现熟悉GDB命令的重要性。下面我
们将结合简单的例子,来介绍GDB的一些重要的常用命令。在你调试你的程序之前,
当你编译你的源程序时,不要忘了-g选项或其它相应的选项,才能将调试信息加到你
要调试的程序中
。例如:gcc -g -o hello hello.c 。
3、GDB常用命令简介
  GDB的命令很多,本文不会全部介绍,仅会介绍一些最常用的。在介绍之前,先
介绍GDB中的一个非常有用的功能:补齐功能。它就如同Linux下SHELL中的命令补齐
一样。当你输入一个命令的前几个字符,然后输入TAB键,如果没有其它命令的前几
个字符与此相同,SHELL将补齐此命令。如果有其它命令的前几个字符与此相同,你
会听到一声警告声,再输入TAB键,SHELL将所有前几个字符与此相同的命令全部列出
。而GDB中的补齐功能不仅能补齐GDB命令,而且能补齐参数。
  本文将先介绍常用的命令,然后结合一个具体的例子来演示如何实际使用这些命
令。下面的所有命令除了第一条启动GDB命令是在SHELL下输入的,其余都是GDB内的
命令。大部分GDB内的命令都可以仅输入前几个字符,只要不与其它指令冲突。如qu
it可以简写为q,因为以q打头的命令只有quit。List可以简写为l,等等
3.1 启动GDB
  你可以输入GDB来启动GDB程序。GDB程序有许多参数,在此没有必要详细介绍,
但一个最为常用的还是要介绍的:如果你已经编译好一个程序,我们假设文件名为h
ello,你想用GDB调试它,可以输入gdb hello来启动GDB并载入你的程序。如果你仅
仅启动了GDB,你必须在启动后,在GDB中再载入你的程序。
3.2 载入程序 === file
  在GDB内,载入程序很简单,使用file命令。如file hello。当然,程序的路径
名要正确。
  退出GDB === quit
  在GDB的命令方式下,输入quit,你就可以退出GDB。你也可以输入'C-d'来退出
GDB。
3.3 运行程序 === run
  当你在GDB中已将要调试的程序载入后,你可以用run命令来执行。如果你的程序
需要参数,你可以在run指令后接着输入参数,就象你在SHELL下执行一个需要参数的
命令一样。
3.4 查看程序信息 === info
  info指令用来查看程序的信息,当你用help info查看帮助的话,info指令的参
数足足占了两个屏幕,它的参数非常多,但大部分不常用。我用info指令最多的是用
它来查看断点信息。
3.4.1 查看断点信息
info br
br是断点break的缩写,记得GDB的补齐功能吧。用这条指令,你可以得到你所设置的
所有断点的详细信息。包括断点号,类型,状态,内存地址,断点在源程序中的位置
等。
3.4.2 查看当前源程序
info source

3.4.3 查看堆栈信息
info stack

用这条指令你可以看清楚程序的调用层次关系。
3.4.4 查看当前的参数
info args

3.5 列出源一段源程序 === list
3.5.1 列出某个函数
list FUNCTION
3.5.2 以当前源文件的某行为中间显示一段源程序
list LINENUM
3.5.3 接着前一次继续显示
list
3.5.4 显示前一次之前的源程序
list -
3.5.5 显示另一个文件的一段程序
list FILENAME:FUNCTION 或 list FILENAME:LINENUM
3.6 设置断点 === break
  现在我们将要介绍的也许是最常用和最重要的命令:设置断点。无论何时,只要
你的程序已被载入,并且当前没有正在运行,你就能设置,修改,删除断点。设置断
点的命令是break。有许多种设置断点的方法。如下:
3.6.1 在函数入口设置断点
break FUNCTION

3.6.2 在当前源文件的某一行上设置断点
break LINENUM
3.6.3 在另一个源文件的某一行上设置断点
break FILENAME:LINENUM
3.6.4 在某个地址上设置断点,当你调试的程序没有源程序是,这很有用
break *ADDRESS
  除此之外,设置一个断点,让它只有在某些特定的条件成立时程序才会停下,我
们可以称其为条件断点。这个功能很有用,尤其是当你要在一个程序会很多次执行到
的地方设置断点时。如果没有这个功能,你必须有极大的耐心,加上大量的时间,一
次一次让程序断下,检查一些值,接着再让程序继续执行。事实上,大部分的断下并
不是我们所希望的,我们只希望在某些条件下让程序断下。这时,条件断点就可以大
大提高你的效率,节省你的时间。条件断点的命令如下,在后面的例子中会有示例。
3.6.5 条件断点
break ...if COND

  COND是一个布尔条件表达式,语法与C语言中的一样。条件断点与一般的断点不
同之处是每当程序执行到断点处,都要计算条件表达式,如果为真,程序才会断下,
否则程序会一直执行下去。
3.7 其它断点操作
  GDB给每个断点赋上一个整数数字,这个数字在操作断点时起到重要作用,它实
际上就代表相应的断点。GDB中的断点有四种状态:
  有效(Enabled)
  禁止(Disabled)
  一次有效(Enabled once)
  有效后删除(Enabled for deletion)

  在上面的四个状态有效和禁止都很好理解,禁止就是让断点暂时失效。一次有效
就是当程序在此断点断下后,断点状态自动变为禁止状态。有效后删除就是当程序在
此断点断下后,断点被删除。实际上,后两种状态一般不会碰到。
  当你设置一个断点后,它的确省状态是有效。你可以用enable和disable指令来
设置断点的状态为有效或禁止。例如,如果你想禁止2号断点,可以用下面的指令:
disable 2
相应的,如果想删除2号断点,可以有下面的指令:
delete 2
3.8 设置监视点 === watch
  当你调试一个很大的程序,并且在跟踪一个关键的变量时,发现这个变量不知在
哪儿被改动过,如何才能找到改动它的地方。这时你可以使用watch命令。简单地说
,监视点可以让你监视某个表达式或变量,当它被读或被写时让程序断下。watch命
令的用法如下:
   watch EXPRESSION
  watch指令是监视被写的,当你想监视某个表达式或变量被读的话,需要使用rw
atch指令
,具体用法是一样的。要注意的是,监视点有硬件和软件两种方式,如果可
能Linux尽可能用硬件方式,因为硬件方式在速度上要大大快于软件方式。软件方式
由于要在每次执行一条指令后都要检查所要监视的值是否被改变,因此它的执行速度
会大大降低。同时它也无法设置成被读时让程序断下,因为读操作不会改变值,所以
GDB无法检测到读操作。幸运的是,目前的PC机基本都支持硬件方式。如果你想确认
一下你的机器是否支持硬件,你可以在调试程序时用watch设置一个监视点,如果GD
B向你显示:
   Hardware watchpoint NUM: EXPR
  那么你可以放心了,你的机器支持硬件方式。
3.9 检查数据
  最常用的检查数据的方法是使用print命令。
   print exp

  print指令打印exp表达式的值。却省情况下,表达式的值的打印格式依赖于它的
数据类型。但你可以用一个参数/F来选择输出的打印格式。F是一个代表某种格式的
字母,详细可参考输出格式一节。表达式可以是常量,变量,函数调用,条件表达式
等。但不能打印宏定义的值。表达式exp中的变量必须是全局变量或当前堆栈区可见
的变量。否则GDB会显示象下面的一条信息:
   No symbol "varible" in current context
3.10 修改变量值
  在调试程序时,你可能想改变一个变量的值,看看在这种情况下会发生什么。用
set指令可以修改变量的值:
   set varible=value
  例如你想将一个变量tmp的值赋为10,
set tmp=10
3.11 检查内存值
检查内存值的指令是x,x是examine的意思。用法如下:
x /NFU ADDR
其中N代表重复数,F代表输出格式(见2.13),U代表每个数据单位的大小。U可以取如
下值:
b :字节(byte)
h :双字节数值
w :四字节数值
g :八字节数值

  因此,上面的指令可以这样解释:从ADDR地址开始,以F格式显示N个U数值。例
如:
   x/4ub 0x4000
  会以无符号十进制整数格式(u)显示四个字节(b),0x4000,0x4001,0x4002,0
x4003。
3.12 输出格式
  缺省情况下,输出格式依赖于它的数据类型。但你可以改变输出格式。当你使用
print命令时,可以用一个参数/F来选择输出的打印格式。F可以是以下的一些值:
  'x' 16进制整数格式
  'd' 有符号十进制整数格式
  'u' 无符号十进制整数格式
  'f' 浮点数格式
3.13 单步执行指令
  单步执行指令有两个step和next。Step可以让你跟踪进入一个函数,而next指令
则不会进入函数。
3.14 继续执行指令
  当程序被断下后,你查看了所需的信息后,你会希望程序执行下去,输入 cont
inue, 程序会继续执行下去。
3.15 帮助指令help
  在GDB中,如果想知道一条指令的用法,最方便的方法是使用help。使用方法很
简单,在help后跟上指令名。例如,想知道list指令用法,输入
help list
4.一个简单的例子
  上面仅是GDB常用指令的简单介绍。本节将结合一个简单的例子,向大家演示这
些常用指令的具体应用。这是一个冒泡排序算法的程序,这个例子的目的仅仅是演示
,并不是实际调试。将下面的源程序存为bubble.c文件,并编译好。
#include 
#define MAX_RECORD_NUMBER 10
int record[MAX_RECORD_NUMBER] =
{12,76,48,62,94,17,37,52,69,32};
swap(int * x , int * y )
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int main()
{
int i,j;
for( i = 0 ; i  i; j--)
if( record[j] : 12 76 48 62
上面的指令查看4个4字节数,以整数方式显示。可以看到这与reocrd值是相附的。
(gdb) x/4bb record
0x8049580 : 12 0 0 0
显示4个单字节数,以字节当时显示。上面的4个字节值正好是record数组第一个整数
值,因为整数是4字节,而且intel机器的数值是低字节在前。
改变变量值也很简单,如果想将reocrd数组第一个值该为1,
(gdb) set record[0]=1
看一下值是否改变了。
(gdb) p record
$10 = {1, 76, 48, 62, 94, 17, 32, 37, 52, 69}
第一个值以改成了1。

 

部分内容来自:http://linux.chinaunix.net/techdoc/develop/2006/03/05/928469.shtml

posted @ 2013-02-19 23:30  wongzawing  阅读(1101)  评论(0编辑  收藏  举报