GDB调试指南-单步调试

前言

前面通过《启动调试》,《断点设置》,《变量查看》,我们已经了解了GDB基本的启动,设置断点,查看变量等,如果这些内容你还不知道,建议先回顾一下前面的内容。在启动调试设置断点观察之后,没有我们想要的信息怎么办呢?这个时候,就需要单步执行或者跳过当前断点继续执行等等。而本文所说的单步调试并非仅仅指单步执行,而是指在你的控制之下,按要求执行语句。

准备

老规矩,先准备一个示例程序如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

/*计算简单乘法,这里没有考虑溢出*/

int (int a, int b)

{

int c = a + b;

return c;

}

/*打印从0到num-1的数*/

int count(int num)

{

int i = 0;

if(0 > num)

return 0;

while(i < num)

{

printf("%dn",i);

i++;

}

return i;

}

int main(void)

{

int a = 3;

int b = 7;

printf("it will calc a + bn");

int c = add(a,b);

printf("%d + %d = %dn",a,b,c);

count(c);

return 0;

}

编译:

1
gcc -g -o gdbStep gdbStep.c

程序的功能比较简单,这里不多做解释。

特别简单说明一条命令,list(可简写为l),它可以将源码列出来,例如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20
(gdb) list

1	

2	

3	/*计算简单乘法,这里没有考虑溢出*/

4	int (int a, int b)

5	{

6	    int c = a * b;

7	    return c;

8	}

9	int main(void)

10	{

(gdb) l

11	    int a = 13;

12	    int b = 57;

13	    printf("it will calc a * bn");

14	    int c = add(a,b);

15	    printf("%d*%d = %dn",a,b,c);

16	    return 0;

17	}

(gdb)

单步执行-next

next命令(可简写为n)用于在程序断住后,继续执行下一条语句,假设已经启动调试,并在第12行停住,如果要继续执行,则使用n执行下一条语句,如果后面跟上数字num,则表示执行该命令num次,就达到继续执行n行的效果了:

1

2

3

4

5

6

7

8

9

10

11
$ gdb gdbStep   #启动调试

(gdb)b 25       #将断点设置在12行

(gdb)run        #运行程序

Breakpoint 1, main () at gdbStep.c:25

25	    int b = 7;

(gdb) n     #单步执行

26	    printf("it will calc a + bn");

(gdb) n 2   #执行两次

it will calc a + b

28	    printf("%d + %d = %dn",a,b,c);

(gdb)

从上面的执行结果可以看到,我们在25行处断住,执行n之后,运行到26行,运行n 2之后,运行到28行,但是有没有发现一个问题,为什么不会进入到add函数内部呢?那就需要用到另外一个命令啦。

单步进入-step

对于上面的情况,如果我们想跟踪add函数内部的情况,可以使用step命令(可简写为s),它可以单步跟踪到函数内部,但前提是该函数有调试信息并且有源码信息。

1

2

3

4

5

6

大专栏  GDB调试指南-单步调试 class="line">7

8

9

10

11

12

13

14

15

16

17

18

19

20

21
$ gdb gdbStep    #启动调试

(gdb) b 25       #在12行设置断点

Breakpoint 1 at 0x4005d3: file gdbStep.c, line 25.

(gdb) run        #运行程序

Breakpoint 1, main () at gdbStep.c:25

25	    int b = 7;

(gdb) s          

26	    printf("it will calc a + bn");

(gdb) s     #单步进入,但是并没有该函数的源文件信息

_IO_puts (str=0x4006b8 "it will calc a + b") at ioputs.c:33

33	ioputs.c: No such file or directory.

(gdb) finish    #继续完成该函数调用

Run till exit from #0  _IO_puts (str=0x4006b8 "it will calc a + b")

at ioputs.c:33

it will calc a + b

main () at gdbStep.c:27

27	    int c = add(a,b);

Value returned is $1 = 19

(gdb) s        #单步进入,现在已经进入到了add函数内部

add (a=13, b=57) at gdbStep.c:6

6	    int c = a + b;

从上面的过程可以看到,s命令会尝试进入函数,但是如果没有该函数源码,需要跳过该函数执行,可使用finish命令,继续后面的执行。如果没有函数调用,s的作用与n的作用并无差别,仅仅是继续执行下一行。它后面也可以跟数字,表明要执行的次数。

当然它还有一个选项,用来设置当遇到没有调试信息的函数,s命令是否跳过该函数,而执行后面的。默认情况下,它是会跳过的,即step-mode值是off:

1

2

3

4
(gdb) show step-mode 

Mode of the step operation is off.

(gdb) set step-mode on

(gdb) set step-mode off

还有一个与step相关的命令是stepi(可简写为si),它与step不同的是,每次执行一条机器指令:

1

2

3

4

5

6
(gdb) si

0x0000000000400573	6	    int c = a + b;

(gdb) display/i $pc

1: x/i $pc

=> 0x400573 <add+13>:	mov    -0x18(%rbp),%eax

(gdb)

继续执行到下一个断点-continue

我们可能打了多处断点,或者断点打在循环内,这个时候,想跳过这个断点,甚至跳过多次断点继续执行该怎么做呢?可以使用continue命令(可简写为c)或者fg,它会继续执行程序,直到再次遇到断点处:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25
$ gdb gdbStep

(gdb)b 18    #在count函数循环内打断点

(gdb)run

Breakpoint 1, count (num=10) at gdbStep.c:18

18	        i++;

(gdb) c      #继续运行,直到下一次断住

Continuing.

1

Breakpoint 1, count (num=10) at gdbStep.c:18

18	        i++;

(gdb) fg     #继续运行,直到下一次断住

Continuing.

2

Breakpoint 1, count (num=10) at gdbStep.c:18

18	        i++;

(gdb) c 3    #跳过三次

Will ignore next 2 crossings of breakpoint 1.  Continuing.

3

4

5

Breakpoint 1, count (num=10) at gdbStep.c:18

18	        i++;

继续运行到指定位置-until

假如我们在25行停住了,现在想要运行到29行停住,就可以使用until命令(可简写为u):

1

2

3

4

5

6

7

8

9
$ gdb gdbStep

(gdb)b 25

(gdb)run

(gdb) u 29

it will calc a + b

3 + 7 = 10

main () at gdbStep.c:29

29	    count(c);

(gdb)

可以看到,在执行u 29之后,它在29行停住了。它利用的是临时断点。

跳过执行—skip

skip可以在step时跳过一些不想关注的函数或者某个文件的代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17
$ gdb gdbStep

(gdb) b 27

Breakpoint 1 at 0x4005e4: file gdbStep.c, line 27.

(gdb) skip function add    #step时跳过add函数

Function add will be skipped when stepping.

(gdb) info skip   #查看step情况

Num     Type           Enb What

1       function       y   add

(gdb) run

Starting program: /home/hyb/workspaces/gdb/gdbStep 

it will calc a + b

Breakpoint 1, main () at gdbStep.c:27

27	    int c = add(a,b);

(gdb) s

28	    printf("%d + %d = %dn",a,b,c);

(gdb)

可以看到,再使用skip之后,使用step将不会进入add函数。
step也后面也可以跟文件:

1
(gdb)skip file gdbStep.c

这样gdbStep.c中的函数都不会进入。

其他相关命令:

  • skip delete [num] 删除skip
  • skip enable [num] 使能skip
  • skip disable [num] 去使能skip

其中num是前面通过info skip看到的num值,上面可以带或不带该值,如果不带num,则针对所有skip,如果带上了,则只针对某一个skip。

总结

本文主要介绍了一些简单情况的单步调试方法或常见命令使用,但这些已经够用了,毕竟大部分程序的执行或停止都在我们的掌控之中了。

原文地址:https://www.cnblogs.com/lijianming180/p/12147572.html

时间: 2024-10-12 14:20:13

GDB调试指南-单步调试的相关文章

GDB调试指南-启动调试

前言 GDB(GNU Debugger)是UNIX及UNIX-like下的强大调试工具,可以调试ada, c, c++, asm, minimal, d, fortran, objective-c, go, java,pascal等语言.本文以C程序为例,介绍GDB启动调试的多种方式. 哪类程序可被调试 对于C程序来说,需要在编译时加上-g参数,保留调试信息,否则不能使用GDB进行调试.但如果不是自己编译的程序,并不知道是否带有-g参数,如何判断一个文件是否带有调试信息呢? gdb 文件 例如:

一起talk GDB吧(第二回:GDB单步调试)

各位看官们,大家好,我们在上一回中说简单地介绍了GDB.这一回中,我们介绍GDB的调试功能:单步 调试.闲话休提,言归正转.让我们一起talk GDB吧! 看官们,我们先说一下什么是单步调试.大家都知道,程序是按照指令,一步一步地执行,只是程序运行 的很快,所以你没有办法看到走过的每一步.这个有点类似我们平常走路,一步一步地向前走,在路上可 以看到许多风景,如果坐车,那么车速太快了,就会看不清楚路上的风景.单步调试就是不让程序很快地 执行,通俗点说,说是不让程序"坐车"走,让程序一步一

使用GDB 单步调试Android本地代码

转载:http://www.360doc.com/content/12/1228/11/9462341_256747689.shtml 下面就以GDB调试Rild为例,来说明如何调试Native进程. 说明 #cmd     表明该命令运行于android设备控制台上 $cmd     表明该命令运行于Linux PC控制台上 (gdb)cmd 表明该命令运行于GDB控制台上 1. 调试已运行的rild #ps | grep rild 得到rild的进程rild-pid #gdbserver :

gdb单步调试时top看不到所调试的进程

最近用gdb调试程序时,新开窗口用top命令查看调试进程的内存占用情况,但总遇到在单步调试时,由于程序执行太慢,top看不到调试进程的情况. 后查明,这是由于默认进入top时,各进程是按照CPU的占用量来排序的,单步调试程序执行太慢,有时cpu占用量为0. 解决办法:在top窗口用键盘敲"u",然后输入当前用户名,则top窗口显示的都为该用户下的进程信息. 其他一些有用也很有意思的top视图 多U多核CPU监控在top基本视图中,按键盘数字"1",可监控每个逻辑CP

Linux Kernel - Debug Guide (Linux内核调试指南 )

http://blog.csdn.net/blizmax6/article/details/6747601 linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 建立调试环境 发行版的选择和安装 安装交叉编译工具 bin工具集的使用 qemu的使用 initrd.img的原理与制作 x86虚拟调试环境的建立 arm虚拟调试环境的建立 arm开发板调试环

linux内核调试指南

linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 建立调试环境 发行版的选择和安装 安装交叉编译工具 bin工具集的使用 qemu的使用 initrd.img的原理与制作 x86虚拟调试环境的建立 arm虚拟调试环境的建立 arm开发板调试环境的建立 gdb基础 基本命令 gdb之gui gdb技巧 gdb宏 汇编基础--X86篇 用户手册 AT&

利用GDB对程序进行调试

第一章初涉调试会话 调试工具 GDB Unix下最常用的调试工具 DDD 基于GUI的调试器,大多数工具都是GDB的GUI前端. Eclipse IDE也是一种调试工具 atoi( )把字符串变为整数,头文件是include<stdlib.h> gcc -g -Wall -o insert_sort ins.c -g选项可以让编译器将符号表(对应于程序的变量和代码行的内存地址列表)保存在生成的可执行文件里中. 这样才能在调试会话的过程中引用源代码中的变量和行号,比如"在第30行停止&

[编译器]dev c++单步调试

一.dev c++调试崩溃的解决方案 1.点击“工具 -> 编译选项”. 2.选择“编译器”选项卡,勾选“编译时加入以下命令”,输入“-g3”. 3.选择“代码生成/优化”选项卡,选择“连接器”选项卡,将“产生调试信息”选为“Yes”. 4.点击确定,重新编译需要调试的程序,就可以单步运行了. 二.单步调试 1.设置断点:在行号附近单击即可,如何调出行号,请转到文末. 2.单击“调试”按钮. 当然也可以在“运行”里找到: 这时界面是这样的: 蓝色的横行左侧带有一个蓝色的箭头,代表当前单步执行的位

Linux学习——Gdb基本调试方法&amp;&amp;多线程调试

1.Gdb的基本调试 示例代码 //e.c #include <stdio.h> void debug(char *str) { printf("debug info :%s\n",str ); } int main(int argc,char *argv[]){ int i,j; j=0; for(i=0;i<10;i++){ j+=5; printf("now a=%d\n", j); } } 1 2 3 4 5 6 7 8 9 10 11 1