GDB调试指南-单步调试

时间:2022-03-28 03:59:33

前言

前面通过《启动调试》,《断点设置》,《变量查看》,我们已经了解了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),
      
      
      

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/SQL/13964.html