前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GDB调试指南-单步调试

GDB调试指南-单步调试

作者头像
编程珠玑
发布2019-07-12 12:40:05
2.7K0
发布2019-07-12 12:40:05
举报
文章被收录于专栏:编程珠玑编程珠玑

前言

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

准备

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

代码语言:javascript
复制
 1/*gdbStep.c*/
 2#include<stdio.h>
 3/*计算简单乘法,这里没有考虑溢出*/
 4int add(int a, int b)
 5{
 6    int c = a + b;
 7    return c;
 8}
 9/*打印从0到num-1的数*/
10int count(int num)
11{
12    int i = 0;
13    if(0 > num)
14        return 0;
15    while(i < num)
16    {
17        printf("%d\n",i);
18        i++;
19    }
20    return i;
21}
22int main(void)
23{
24    int a = 3;
25    int b = 7;
26    printf("it will calc a + b\n");
27    int c = add(a,b);
28    printf("%d + %d = %d\n",a,b,c);
29    count(c);
30    return 0;
31}

编译:

代码语言:javascript
复制
gcc -g -o gdbStep gdbStep.c

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

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

代码语言:javascript
复制
(gdb) list
1    #include<stdio.h>
2    
3    /*计算简单乘法,这里没有考虑溢出*/
4    int add(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 * b\n");
14        int c = add(a,b);
15        printf("%d*%d = %d\n",a,b,c);
16        return 0;
17    }
(gdb)

单步执行-next

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

代码语言:javascript
复制
$ 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 + b\n");
(gdb) n 2   #执行两次
it will calc a + b
28        printf("%d + %d = %d\n",a,b,c);
(gdb) 

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

单步进入-step

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

代码语言:javascript
复制
$ 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 + b\n");
(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:

代码语言:javascript
复制
(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不同的是,每次执行一条机器指令:

代码语言:javascript
复制
(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,它会继续执行程序,直到再次遇到断点处:

代码语言:javascript
复制
$ 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):

代码语言:javascript
复制
$ 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时跳过一些不想关注的函数或者某个文件的代码:

代码语言:javascript
复制
$ 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 = %d\n",a,b,c);
(gdb)

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

代码语言:javascript
复制
(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。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程珠玑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 准备
  • 单步执行-next
  • 单步进入-step
  • 继续执行到下一个断点-continue
  • 继续运行到指定位置-until
  • 跳过执行--skip
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档