GDB是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。 对于一名Linux下工作的c/c++程序员,gdb是必不可少的工具;

二、gdb使用流程

这里用c程序做基本演示,c++程序也是一样的;

1、启动gdb

编译一个测试程序,-g表示可以调试,命令如下:

gcc -g test.c -o test

1

启动gdb,命令如下:

gdb test

gdb -q test //表示不打印gdb版本信息,界面较为干净;

测试如下:

root@ubuntu:/home/eit/c_test# gdb test

GNU gdb (Ubuntu 7.7-0ubuntu3) 7.7

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

Type "show configuration" for configuration details.

For bug reporting instructions, please see:

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

Find the GDB manual and other documentation resources online at:

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

For help, type "help".

Type "apropos word" to search for commands related to "word"...

Reading symbols from test...done.

(gdb) q

root@ubuntu:/home/eit/c_test# gdb -q test

Reading symbols from test...done.

(gdb)

到此gdb启动完成!

2、查看源码

list(简写 l): 查看源程序代码,默认显示10行,按回车键继续看余下的。

测试如下:

(gdb) list

9 #define MAX_SIZE

10

11 int main()

12 {

13 int i,fd,size1 ,size2 ,len;

14 char *buf = "helo!I'm liujiangyong ";

15 char buf_r[15];

16 len = strlen(buf);

17 fd = open("/home/hello.txt",O_CREAT | O_TRUNC | O_RDWR,0666);

18 if (fd<0)

(gdb)

19 {

20 perror("open :");

21 exit(1);

22 }

23 else

24 {

25 printf("open file:hello.txt %d\n",fd);

26 }

27 size1 = write(fd,buf,len);

28 if (fd<0)

(gdb)

29 {

30 printf("writre erro;");

31

32 }

33 else

34 {

35 printf("写入的长度:%d\n写入文本内容:%s\n",size1,buf);

36

37 }

38 lseek(fd,0,SEEK_SET);

(gdb)

39 size2 = read(fd,buf_r,12);

40 if (size2 <0)

41 {

42 printf("read erro\n");

43 }

44 else

45 {

46 printf("读取长度:%d\n 文本内容是:%s\n",size2,buf_r);

47 }

48 close(fd);

(gdb)

49

50

51 }

(gdb)

Line number 52 out of range; write.c has 51 lines.

(gdb)

3、运行程序

run(简写 r) :运行程序直到遇到 结束或者遇到断点等待下一个命令;

测试如下:

(gdb) r

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /home/eit/c_test/test

open file:hello.txt 3

写入的长度:22

写入文本内容:helo!I'm liujiangyong

读取长度:12

文本内容是:helo!I'm liu

[Inferior 1 (process 19987) exited normally]

(gdb)

4、设置断点

break(简写 b) :格式 b 行号,在某行设置断点;

info breakpoints :显示断点信息

Num: 断点编号

Disp:断点执行一次之后是否有效 kep:有效 dis:无效

Enb: 当前断点是否有效 y:有效 n:无效

Address:内存地址

What:位置

(gdb) b 5

Breakpoint 3 at 0x400836: file write.c, line 5.

(gdb) b 26

Breakpoint 4 at 0x4008a6: file write.c, line 26.

(gdb) b 30

Breakpoint 5 at 0x4008c6: file write.c, line 30.

(gdb) info breakpoints

Num Type Disp Enb Address What

3 breakpoint keep y 0x0000000000400836 in main at write.c:5

4 breakpoint keep y 0x00000000004008a6 in main at write.c:26

5 breakpoint keep y 0x00000000004008c6 in main at write.c:30

(gdb)

5、单步执行

使用 continue、step、next命令

测试如下:

(gdb) r

Starting program: /home/eit/c_test/test

Breakpoint 3, main () at write.c:12

12 {

(gdb) n

14 char *buf = "helo!I'm liujiangyong ";

(gdb)

16 len = strlen(buf);

(gdb)

17 fd = open("/home/hello.txt",O_CREAT | O_TRUNC | O_RDWR,0666);

(gdb) s

open64 () at ../sysdeps/unix/syscall-template.S:81

81 ../sysdeps/unix/syscall-template.S: No such file or directory.

(gdb)

main () at write.c:18

18 if (fd<0)

(gdb)

25 printf("open file:hello.txt %d\n",fd);

(gdb)

__printf (format=0x400a26 "open file:hello.txt %d\n") at printf.c:28

28 printf.c: No such file or directory.

(gdb) c

Continuing.

open file:hello.txt 3

Breakpoint 4, main () at write.c:27

27 size1 = write(fd,buf,len);

(gdb)

Continuing.

写入的长度:22

写入文本内容:helo!I'm liujiangyong

读取长度:12

文本内容是:helo!I'm liu

[Inferior 1 (process 20737) exited normally]

(gdb)

6、查看变量

使用print、whatis命令

测试如下:

main () at write.c:28

28 if (fd<0)

(gdb)

35 printf("写入的长度:%d\n写入文本内容:%s\n",size1,buf);

(gdb) print fd

$10 = 3

(gdb) whatis fd

type = int

(gdb)

7、退出gdb

用quit命令退出gdb:

(gdb) r

Starting program: /home/eit/c_test/test

open file:hello.txt 3

写入的长度:22

写入文本内容:helo!I'm liujiangyong

读取长度:12

文本内容是:helo!I'm liu

[Inferior 1 (process 20815) exited normally]

(gdb) q

root@ubuntu:/home/eit/c_test#

continue(简写 c): 继续执行程序,直到下一个断点或者结束;

next(简写 n ):单步执行程序,但是遇到函数时会直接跳过函数,不进入函数;

step(简写 s) :单步执行程序,但是遇到函数会进入函数;

until:当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体;

until+行号: 运行至某行,不仅仅用来跳出循环;

finish: 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息;

call 函数(参数):调用程序中可见的函数,并传递“参数”,如:call gdb_test(55);

quit:简记为 q ,退出gdb;

三、gdb基本使用命令

1、运行命令

run:简记为 r ,其作用是运行程序,当遇到断点后,程序会在断点处停止运行,等待用户输入下一步的命令。

continue (简写c ):继续执行,到下一个断点处(或运行结束)

next:(简写 n),单步跟踪程序,当遇到函数调用时,也不进入此函数体;此命令同 step 的主要区别是,step 遇到用户自定义的函数,将步进到函数中去运行,而 next 则直接调用函数,不会进入到函数体内。

step (简写s):单步调试如果有函数调用,则进入函数;与命令n不同,n是不进入调用的函数的

until:当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。

until+行号: 运行至某行,不仅仅用来跳出循环

finish: 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。

call 函数(参数):调用程序中可见的函数,并传递“参数”,如:call gdb_test(55)

quit:简记为 q ,退出gdb

2、设置断点

break n (简写b n):在第n行处设置断点

(可以带上代码路径和代码名称: b OAGUPDATE.cpp:578)

b fn1 if a>b:条件断点设置

break func(break缩写为b):在函数func()的入口处设置断点,如:break cb_button

delete 断点号n:删除第n个断点

disable 断点号n:暂停第n个断点

enable 断点号n:开启第n个断点

clear 行号n:清除第n行的断点

info b (info breakpoints) :显示当前程序的断点设置情况

delete breakpoints:清除所有断点:

3、查看源码

list :简记为 l ,其作用就是列出程序的源代码,默认每次显示10行。

list 行号:将显示当前文件以“行号”为中心的前后10行代码,如:list 12

list 函数名:将显示“函数名”所在函数的源代码,如:list main

list :不带参数,将接着上一次 list 命令的,输出下边的内容。

4、打印表达式

print 表达式:简记为 p ,其中“表达式”可以是任何当前正在被测试程序的有效表达式,比如当前正在调试C语言的程序,那么“表达式”可以是任何C语言的有效表达式,包括数字,变量甚至是函数调用。

print a:将显示整数 a 的值

print ++a:将把 a 中的值加1,并显示出来

print name:将显示字符串 name 的值

print gdb_test(22):将以整数22作为参数调用 gdb_test() 函数

print gdb_test(a):将以变量 a 作为参数调用 gdb_test() 函数

display 表达式:在单步运行时将非常有用,使用display命令设置一个表达式后,它将在每次单步进行指令后,紧接着输出被设置的表达式及值。如: display a

watch 表达式:设置一个监视点,一旦被监视的“表达式”的值改变,gdb将强行终止正在被调试的程序。如: watch a

whatis :查询变量或函数

info function: 查询函数

扩展info locals: 显示当前堆栈页的所有变量

5、查看运行信息

where/bt :当前运行的堆栈列表;

bt backtrace 显示当前调用堆栈

up/down 改变堆栈显示的深度

set args 参数:指定运行时的参数

show args:查看设置好的参数

info program: 来查看程序的是否在运行,进程号,被暂停的原因。

6、分割窗口

layout:用于分割窗口,可以一边查看代码,一边测试:

layout src:显示源代码窗口

layout asm:显示反汇编窗口

layout regs:显示源代码/反汇编和CPU寄存器窗口

layout split:显示源代码和反汇编窗口

Ctrl + L:刷新窗口

7、cgdb强大工具

cgdb主要功能是在调试时进行代码的同步显示,这无疑增加了调试的方便性,提高了调试效率。界面类似vi,符合unix/linux下开发人员习惯;如果熟悉gdb和vi,几乎可以立即使用cgdb。


​​windows下配置 GNU的gdb调试功能​​


1、配置


修改环境变量(前提电脑中存在gdb.exe) 1. 我的电脑->属性->环境......在path那一项后面添加你DEV-C++ Bin目录的路径(gdb.exe所在目录),如: E:\Program Files\DEV-CPP\Bin (你自己的路径) 2. CMD命令行,输入: set path=%path%;E:\Program Files\DEV-CPP\Bin  这样之后,命令行就可以直接调用gdb命令了
2、使用gdb调试程序

GDB概述 ————

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。

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

1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。 2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式) 3、当程序被停住时,可以检查此时你的程序中所发生的事。 4、动态的改变你程序的执行环境。

从上面看来,GDB和一般的调试工具没有什么两样,基本上也是完成这些功能,不过在细节上,你会发现GDB这个调试工具的强大,大家可能比较习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。让我们一一看来。


为调试编译代码(Compiling Code for Debugging)

为了使 gdb 正常工作, 你必须使你的程序在编译时包含调试信息. 调试信息包含你程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号. gdb 利用这些信息使源代码和机器码相关联.

在编译时用 -g 选项打开调试选项.

gdb 基本命令

gdb 支持很多的命令使你能实现不同的功能. 这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令, 表27.1列出了你在用 gdb 调试时会用到的一些命令. 想了解 gdb 的详细使用请参考 gdb 的指南页.

表 27.1. 基本 gdb 命令.

cd

改变工作目录



pwd

显示当前工作目录



Tbreak

设置临时断点。它的语法与break相同。区别在于用tbreak设置的断点执行一次之后立即消失



awatch

设置读写监视点。当要监视的表达式被读或写时将应用程序挂起。它的语法与watch命令相同

rwatch

设置读监视点,当监视表达式被读时将程序挂起,等侍调试。此命令的语法与watch相同



display:在应用程序每次停止运行时显示表达式的值。 info break:显示当前断点列表,包括每个断点到达的次数。 info files:显示调试文件的信息。 info func:显示所有的函数名。 info local:显示当前函数的所有局部变量的信息。

info prog: 显示调试程序的执行状态。 print: 显示表达式的值。 delete命令: 删除断点。指定一个断点号码,则删除指定断点。

一个调试示例 ——————



1 新建一个源文件vi swap.cc


源文件内容如下:

#include<iostream>

using namespace std;

void swap(int &a,int &b)

{

        int tmp;

        tmp=a;

        a=b;

        b=tmp;

}

int main()

{

        int i,j;

        cout<<endl<<"Input two int number:"<<endl;

        cin>>i>>j;

        cout<<"Before swap(),i="<<i<<" j="<<j<<endl;

        swap(i,j);

        cout<<"After swap(),i="<<i<<" j="<<j<<endl<<endl;

        return 0;

}

直接复制粘贴生成源文件

2.生成可执行文件 g++ -g -o swap swap.cc,注意必须使用-g参数,编译会加入调试信息,否则无法调试执行文件


3.启动调试 gdb swap


3.1 查看源文件 list 1,回车重复上一次指令


3.2设置调试断点 break 16,在第16行设置断点,info break查看断点信息(亦可使用缩写i b )


3.3 调试 运行 输入run 或者r


3.3 单步调试,step 或者 s进入函数内部


3.4查看变量 print b 或者 p b


3.5查看函数堆栈bt,退出函数finish


3.6 继续运行直到下一个断点或主函数结束continue或者c


3.7 退出调试 输入q




1、配置


修改环境变量(前提电脑中存在gdb.exe) 1. 我的电脑->属性->环境......在path那一项后面添加你DEV-C++ Bin目录的路径(gdb.exe所在目录),如: E:\Program Files\DEV-CPP\Bin (你自己的路径) 2. CMD命令行,输入: set path=%path%;E:\Program Files\DEV-CPP\Bin  这样之后,命令行就可以直接调用gdb命令了
2、使用gdb调试程序

GDB概述 ————

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。

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

1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。 2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式) 3、当程序被停住时,可以检查此时你的程序中所发生的事。 4、动态的改变你程序的执行环境。

从上面看来,GDB和一般的调试工具没有什么两样,基本上也是完成这些功能,不过在细节上,你会发现GDB这个调试工具的强大,大家可能比较习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。让我们一一看来。


为调试编译代码(Compiling Code for Debugging)

为了使 gdb 正常工作, 你必须使你的程序在编译时包含调试信息. 调试信息包含你程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号. gdb 利用这些信息使源代码和机器码相关联.

在编译时用 -g 选项打开调试选项.

gdb 基本命令

gdb 支持很多的命令使你能实现不同的功能. 这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令, 表27.1列出了你在用 gdb 调试时会用到的一些命令. 想了解 gdb 的详细使用请参考 gdb 的指南页.

表 27.1. 基本 gdb 命令.

cd

改变工作目录



pwd

显示当前工作目录



Tbreak

设置临时断点。它的语法与break相同。区别在于用tbreak设置的断点执行一次之后立即消失



awatch

设置读写监视点。当要监视的表达式被读或写时将应用程序挂起。它的语法与watch命令相同

rwatch

设置读监视点,当监视表达式被读时将程序挂起,等侍调试。此命令的语法与watch相同



display:在应用程序每次停止运行时显示表达式的值。 info break:显示当前断点列表,包括每个断点到达的次数。 info files:显示调试文件的信息。 info func:显示所有的函数名。 info local:显示当前函数的所有局部变量的信息。

info prog: 显示调试程序的执行状态。 print: 显示表达式的值。 delete命令: 删除断点。指定一个断点号码,则删除指定断点。

一个调试示例 ——————



1 新建一个源文件vi swap.cc


源文件内容如下:

#include<iostream>

using namespace std;

void swap(int &a,int &b)

{

        int tmp;

        tmp=a;

        a=b;

        b=tmp;

}

int main()

{

        int i,j;

        cout<<endl<<"Input two int number:"<<endl;

        cin>>i>>j;

        cout<<"Before swap(),i="<<i<<" j="<<j<<endl;

        swap(i,j);

        cout<<"After swap(),i="<<i<<" j="<<j<<endl<<endl;

        return 0;

}

直接复制粘贴生成源文件

2.生成可执行文件 g++ -g -o swap swap.cc,注意必须使用-g参数,编译会加入调试信息,否则无法调试执行文件


3.启动调试 gdb swap


3.1 查看源文件 list 1,回车重复上一次指令


3.2设置调试断点 break 16,在第16行设置断点,info break查看断点信息(亦可使用缩写i b )



3.3 调试 运行 输入run 或者r


3.3 单步调试,step 或者 s进入函数内部


3.4查看变量 print b 或者 p b


3.5查看函数堆栈bt,退出函数finish


3.6 继续运行直到下一个断点或主函数结束continue或者c


3.7 退出调试 输入q