gdb 的用法(Linux调试器)

在Linux应用程序开发中,最常用的调试器是gdb,它可以在程序中设置断点、查看变量值、一步一步跟踪程序的执行过程

GDB(GNU symbolic debugger)简单地说就是一个调试工具。它是一个受通用公共许可证即GPL保护的自由软件。

像所有的调试器一样,GDB可以让你调试一个程序,包括让程序在你希望的地方停下,此时你可以查看变量、寄存器、内存及堆栈更进一步你可以修改变量及内存值。GDB是一个功能很强大的调试器,它可以调试多种语言(Ada、C++、Java、Pascal)。还有一点要说明的是,GDB是一个调试器,而不像 VC 是一个集成环境。你可以使用一些前端工具如XXGDB、DDD等。他们都有图形化界面,因此使用更方便,但它们仅是GDB的一层外壳。因此,你仍应熟悉GDB命令。事实上,当你使用这些图形化界面时间较长时,你才会发现熟悉GDB命令的重要性。

一、启动和退出gdb

首先注意一点,gdb调试的对象是可执行文件,而不是程序的源代码,所以你要先用gcc生成可执行文件

另外,如果要使一个可执行文件可以被gdb调试,那么在使用编译器gcc编译程序时需要加入-g选项。-g选项告诉gcc在编译程序时加入调试信息,这样才可以调试这个被编译的程序。 例如:gcc -g hello.c -o hello(-o是命名编译出来的可执行文件)

(一)、调试一个程序的命令格式

格式:gdb <可执程序文件名>

例:#gdb hello


1、 #gdb →( 进入gdb环境)
2、 (gdb) file hello → (把hello可执行文件加载到gdb里面)

(二)、退出

(gdb) quit

二、显示和查找程序的源代码

在调试时,一般要查看程序的源代码。list 命令用于列出程序的源代码,使用格式如下:

(gdb) list 显示10行代码,若再次运行该命令则显示接下来的10行代码(gdb默认设置)

(gdb) list 5,10 显示源代文件test.c中的第5行到第10行的代码,

(gdb) list test.c:5,10 显示源文件test.c中第5行到第10行的代码,在调试含有多个源文件的程序时使用

(gdb) list get_sum 显示get_sum函数周围的代码

(gdb) list test.c:get_sum 显示源文件test.c中get_sum函数周围的代码,在调试含多个源文件的程序时使用

(gdb) search <字符串> 用来从当前行向后查找第一个匹配的字符串

(gdb)reverse-search<字符串> 用来从当前行向前查找第一个匹配的字符串

举例:
在这里插入图片描述

三、执行程序和获得帮助

使用gdb hello或(gdb) file hello只是装入程序,程序并没有运行,如果要使程序运行,将文件装入gdb以后,在gdb提示符下输入run即可。

(gdb) run
在这里插入图片描述
如果想要详细了解gdb某个命令的使用方法,可以使用help命令

(gdb)help list

(gdb)help all

四、设置和管理断点

在调试程序时,往往需要程序在运行到某行、某个函数或某个条件发生时暂停下来,然后查看此时程序的状态,如各个变量的值、某个表达式的值等。为此,可以设置断点(break)。断点使程序运行到某个位置时暂停下来,以便检查和分析程序。

1、 以行号设置断点

在gdb中,大部分都是使用break命令为程序设置断点。而指定断点时,最常用的是为某行设置断点。例:

(gdb) break 7

Breakpoint 1 at0x80483c0: file test.c, line 7.

然后我们输入run命令运行程序:

(gdb) run

Starting program:/tmp/test

Breakpoint 1,get_sum (n=100) at test.c:7

7 sum +=i;

可以看到,程序运行完第6行的指令后就暂停了,第7行的代码并没有执行而是被gdb的断点中断了。此时,我们可以查看各个变量和表达式的值,以了解程序的当前状态。

2、以函数名设置断点

在break命令后跟上函数名,就可以为函数设置断点。例:

(gdb) break get_sum

Breakpoint 1 at0x80483aa: file test.c, line 5.

(gdb) run

Starting program:/tmp/test

Breakpoint 1,get_sum (n=100) at test.c:5

5 int sum = 0,i;

可以看到,程序在第5行停了上来。

3、以条件表达式设置断点

程序在运行过程中,当某个条件满足时,程序在某行中断暂停执行

方法1 命令格式:break行号或函数名 if 条件

例:

(gdb) clear

Deleted breakpoint1

(gdb) break7 if i==99

Breakpoint 2 at0x80483c0: file test.c, line 7.

(gdb) run

The program beingdebugged has been started already.

Start it from thebeginning? (y or n) y

Starting program:/tmp/test

Breakpoint 2,get_sum (n=100) at test.c:7

7 sum +=i;

可以看到,运行程序后在i==99时,程序中断在第7行。

方法2 watch <条件表达式>

例:(gdb) watchi==99

No symbol"i" in current context.

(gdb) list 6

1 #include <stdio.h>

2

3 int get_sum(int n)

4 {

5 int sum = 0,i;

6 for (i=0;i<n;i++)

7 sum +=i;

8 return sum;

9 }

10

(gdb) break 6

Breakpoint 1 at0x80483b1: file test.c, line 6.

(gdb) run

Starting program:/tmp/test

Breakpoint 1,get_sum (n=100) at test.c:6

6 for (i=0;i<n;i++)

Gdb运行后,以命令watch i==99设置条件断点,但是失败了,gdb提示在当前程序的上下文中没有符号i,这是因为此时test程序没有运行,变量i还没有被定义。

为了解决这个问题,首先在第6行设置断点,然后使用run命令运行程序,程序暂停在第6行,此时第5行的语句已经被执行,所以变量i已经定义。这时就可以使用watch i==99设置断点了。

4、查看当前设置的断点

使用info breakpoints命令可以查看当前所有的中断点,例如:

(gdb) break 7

Breakpoint 1 at0x80483c0: file test.c, line 7.

(gdb) break 15 if result=5050

Breakpoint 2 at0x8048405: file test.c, line 15.

(gdb) info breakpoints

Num     Type       Disp Enb  Address    What

1   breakpoint     keep y  0x080483c0 in get_sum at test.c:7

2   breakpoint     keep y  0x08048405 in main at test.c:15

stop only if result = 5050

其中:

Num 表示断点的编号

Type 说明类型,类型为breakpoint是指中断

Disp 指明中断点在生效一次后是否失去作用,是则为disp,不是则为keep

Enb 说明中断点是否有效,有效则为y,无效则为n

Address列 说明中断所处的内存地址

What列 列出中断发生在哪个函数的第几行

Stop only if result==5050 说明这是一个条件中断

5、使中断失效或有效

disable <断点编号> 可以使某个断点失效,程序运行到该断点时不会停下来而是继续运行

enable <断点编号> 可以使某个断点恢复有效

例:

(gdb) info breakpoints

Num    Type       Disp Enb    Address    What

1  breakpoint     keep y   0x080483c0 in get_sum at test.c:7

2  breakpoint     keep y   0x08048405 in main at test.c:15

stop only if result = 5050

(gdb) disable 2

(gdb) info breakpoints

Num Type          Disp Enb  Address    What

1  breakpoint     keep y   0x080483c0 in get_sum at test.c:7

2  breakpoint     keep n   0x08048405 in main at test.c:15

stop only if result = 5050

(gdb) enable 2

(gdb) info breakpoints

Num Type          Disp Enb   Address    What

1  breakpoint     keep y   0x080483c0 in get_sum at test.c:7

2  breakpoint     keep y   0x08048405 in main at test.c:15

stop only if result = 5050

6、删除断点

(gdb) clear 删除程序中所有的断点

(gdb) clear<行号> 删除此行的断点

(gdb) clear<函数名> 删除该函数的断点

(gdb) delete<断点编号> 删除指定编号的断点。如果一次要删除多个断点,各个断点编号以空格隔开

例:

(gdb) break 6

Breakpoint 1 at0x80483b1: file test.c, line 6.

(gdb) break 7

Breakpoint 2 at0x80483c0: file test.c, line 7.

(gdb) break 8 ifsum==5050

Breakpoint 3 at0x80483cf: file test.c, line 8.

(gdb) info breakpoints

Num Type           Disp Enb Address    What

1   breakpoint     keep y  0x080483b1 in get_sum at test.c:6

2   breakpoint     keep y  0x080483c0 in get_sum at test.c:7

3   breakpoint     keep y  0x080483cf in get_sum at test.c:8

stop only if sum == 5050

(gdb) clear 6

Deleted breakpoint1

(gdb) info breakpoints

Num Type           Disp Enb Address    What

2   breakpoint     keep y  0x080483c0 in get_sum at test.c:7

3   breakpoint     keep y  0x080483cf in get_sum at test.c:8

 stop only if sum == 5050

(gdb) delete 2 3

(gdb) info breakpoints

No breakpoints orwatchpoints.

7、display <表示式>

在每次程序停在断点位置时,自动显示表达式中的内容

8、commands

>命令

>end      结束命令输入

作用:指定在程序到达断点位置时需要执行的调试器命令

在这里插入图片描述

五、查看和设置变量的值

当程序执行到中断点暂停执行时,需要查看变量或表达式的值,借此了解程序的执行状态

1、print命令

作用:print命令一般用来打印变量或表达式的值,也可以用来打印内存中从某个变量开始的一段存区域的内容,还可以用来对某个变量进行赋值。

格式:

print <变量或表达式> 打印变量或表达式的当前值,gdb会用伪变量($n)来保存输出值以备用

Print <变量=值>; 对变量进行赋值

Print <表达式@要打印的值的个数n> 打印以表达式值开始的n个数

例:

(gdb) break 7

Breakpoint 4 at0x80483c0: file test.c, line 7.

(gdb) run

Starting program:/tmp/test

Breakpoint 4,get_sum (n=100) at test.c:7

7 sum += i;

(gdb)print i<n 打印出i<n表达式的值,显然这个表达式为真,因此值为1

$1 = 1

(gdb) print i

$2 = 0

(gdb) print sum

$3 = 0

(gdb) print i=200

$4 = 200

(gdb) continue

Continuing.

1+2+…+100=200

Program exitednormally.

2、whatis 命令

作用:用来显示某个变量或表达式值的数据类型

格式:whatis <变量或表达式>

例:

(gdb) break 7

Note: breakpoint 4also set at pc 0x80483c0.

Breakpoint 5 at0x80483c0: file test.c, line 7.

(gdb) run

Starting program:/tmp/test

Breakpoint 4,get_sum (n=100) at test.c:7

7 sum += i;

(gdb) whatis i

type = int

(gdb) whatis sum+0.5

type = double

3、set 命令

作用:用来给变量赋值

格式:set variable 变量=值 相当于print 变量=值

例:set variable i=200,相当于print i=200

六、控制程序的执行

当程序执行到指定的中断点,查看了变量或表达式的值后,可以让程序继续运行。也可以让程序一步一步地执行,或可以让程序地直运行下去直到下一个断点或运行完为止。

1、 continue命令

作用:让程序继续运行,直到下一个断点或运行完为止。

格式:continue

2、 kill命令

作用:用于结束当前程序的调试

例:(gdb) kill

Kill the program being debugged? (y or n) y

3、 next和step命令

作用:一次一条地执行程序代码

next和step的区别:

1)、如果遇到函数调用,next会把该函数调用当作一条语句来执行,再次输入next会执行函数调用后的语句

2)、step则会跟踪进入函数,一次一条地执行函数内的代码,直到函数的代码执行完,才执行函数调用后的语句

例:next语句的用法

(gdb) list 1,17

1      #include <stdio.h>

2

3      int get_sum(int n)

4      {

5        int sum = 0,i;

6        for(i=0;i<n;i++)

7         sum += i;

8        return sum;

9      }

10

11     int main()

12     {

13       int i=100,result;

14       result = get_sum(i);

15       printf("1+2+...+%d=%d\n",i,result);

16       return 0;

17      }
(gdb) break 13

Breakpoint 1 at 0x80483f0: file test.c, line13.

(gdb) run

Starting program: /tmp/test

 

Breakpoint 1, main () at test.c:13

13       int i=100,result;

(gdb) next

14       result = get_sum(i);

(gdb) next

15       printf("1+2+...+%d=%d\n",i,result);

(gdb) next

1+2+...+100=4950

16       return 0;

(gdb) next

17     }

(gdb) next

0x4003328b in __libc_start_main () from/lib/libc.so.6

(gdb) next

Single stepping until exit from function__libc_start_main,

which has no line number information.

Program exited normally.

例:step语句的用法

(gdb) list 1,17

1       #include <stdio.h>

2

3       int get_sum(int n)

4       {

5         int sum = 0,i;

6         for(i=0;i<n;i++)

7          sum += i;

8         return sum;

9       }

10

11      int main()

12      {

13        int i=100,result;

14        result = get_sum(i);

15       printf("1+2+...+%d=%d\n",i,result);

16        return 0;

17      }
(gdb) break 13

Breakpoint 1 at 0x80483f0: filetest.c, line 13.

(gdb) run

Starting program: /tmp/test

Breakpoint 1, main () at test.c:13

13        int i=100,result;

(gdb) step

14        result = get_sum(i);

(gdb) step

get_sum (n=100) at test.c:5

5         int sum = 0,i;

(gdb) step

6         for(i=0;i<n;i++)

(gdb) step

7          sum += i;

(gdb) step

6         for(i=0;i<n;i++)

(gdb) step

7          sum += i;

 (gdb) step

6         for(i=0;i<n;i++)

(gdb) step

7          sum += i;

4、 nexti和stepi命令

作用:用来单步执行一条机器指令,注意不是单步执行一行语句。单步执行一行语句的命令是next和step命令

注意:

nexti和next类似,不会跟踪进入函数内部去执行
Stepi和step类似,跟踪进入函数执行。

参考:

https://blog.csdn.net/sanganqi_wusuierzi/article/details/54783958

https://sourceware.org/gdb/

https://blog.csdn.net/haoel/article/details/2879

https://blog.csdn.net/liigo/article/details/582231

https://www.cnblogs.com/chenmingjun/p/8280889.html

https://www.cnblogs.com/hanframe/p/3585622.html

总结:GDB中的命令固然很多,但我们只需掌握其中十个左右的命令,就大致可以完成日常的基本的程序调试工作。
在这里插入图片描述

发布了131 篇原创文章 · 获赞 44 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_38769551/article/details/103788059