Linux环境下C编程指南(第二版) -- gdb调试工具

来源:互联网 发布:聚类分析数据集 编辑:程序博客网 时间:2024/05/08 03:00

四、gdb调试工具

       gdb主要提供的功能:

       监视程序中变量的值的变化

       设置断点,使程序在指定的代码行上暂停执行,便于观察

       单步执行代码

       分析崩溃程序产生的core文件

 

       使用命令:

       gdb filename  装入可执行文件进行调试

      

       注:由于调试需要加入调试信息,在编译是需要加入-g选项或-ggdb3选项

      

       调试:

       # gcc filename 进入调试环境

      

       (gdb) break main         main的下一行代码处加入断点

       (gdb) break n                     在第n行加入断点

      

       (gdb) run              运行程序

       (gdb) step / s        单步执行,

 

       (gdb) print 表达式    打印变量的值如 print input 打印变量input的值

       (gdb) print 变量=表达式 设置变量的值

       (gdb) print 开始表达式@要打印的连续内存空间大小  打印一段内存的内容

      

       (gdb) display变量值  执行到断点是会显示变量值,可以观察表达式的值的变化(需要在表达式(变量)作用范围内,一旦出了变量的作用范围不再显示变量值)

      

       (gdb) next   step相区别,next不能跟踪到函数内部,也即跳入与跳过的区别。

      

       (gdb) quit   退出调试环境

      

       使用代码:

      #include <stdio.h>

 

      int getinput( void);

      void printmessage(int counter, int input);

 

      int main(void)

      {

         int counter = 0;

         int input = 0;

 

        for(counter = 0; counter <= 200; counter++)

        {

            input = getinput();

            if(input == -1)

               end(0);

 

            printmessage(counter, input);

        }

 

        return 0;

      }

 

      int getinput(void )

      {

         int input;

         printf("Enter an integer, or use -1 to exit:");

                scanf("%d", &input);

         return input;

      }

 

      void printmessage(int counter, int input)

      {

        static int lastnum = 0;

        counter ++;

         printf("For number %d, you enterd %d(%d more than last time)\n", counter, input, input-lastnum);

         lastnum = input;

      }

      

       显示数据命令:

       显示命令最常用的是displayprint命令,另外还有printf set命令

      

       程序如下:

       #include <stdio.h>

      #include <stdlib.h>

      #include <string.h>

 

      typedef struct TAG_datastruct{

          char * string;

          int checksum;

      }datastruct;

 

      datastruct * getinput( void);

      void printmessage(datastruct * todisp);

 

      int main(void)

      {

          int counter = 0;

          int maxval = 0;

          datastruct * svalues[200];

 

          for(counter = 0; counter < 200; counter++)

          {

              svalues[counter] = getinput();

             if(!svalues[counter])

                 break;

             maxval = counter;

          }

          printmessage(svalues[maxval/2]);

       

          return 0;

      }

 

      datastruct * getinput( void)

      {

          char input[80];

          datastruct * instruct;

          int counter;

 

          printf("Enter a string, or leave blank when done:");

          fgets(input, 79, stdin);

          input[strlen(input)-1] = 0;

          if(strlen(input) == 0)

              return NULL;

          instruct = malloc(sizeof(datastruct));

         instruct->string = strdup(input);

          instruct->checksum = 0;

 

      for(counter = 0; counter < strlen(instruct->string); counter++)

      {

              instruct->checksum += instruct->string[counter];

       }

          return instruct;

      }

 

      void printmessage(datastruct * todisp)

      {

          printf("This structure has a checksum of %d.Its string is:\n", todisp->checksum);

          puts(todisp->string);   

      }

      

       $ gdb test2    进入调试环境

       (gdb) run         运行程序

       (gdb) print svalues    打印一个数组(svalues是一个结构体数组)

      

       (gdb) print svalues[0]->checksum  打印结构体的一个成员

       (gdb) print input           打印一个字符串数组,

       (gdb) print input@20  打印input地址处20个内存单元的内容

      

       (gdb) print input[0]    打印input数组的第一个元素

      

       (gdb) finish 强制结束调试

      

       内存检查命令:

       x/format address     format为显示内存单元个数和显示方式组成:如x/2c以字符形式显示两个内存单元

       (gdb) x/2c 0x9813008

       (gdb) x/2c instruct

      (gdb) x/2c instruct->string

 

      x/2x  以十六进制形式显示   x/2o  以八进制形式显示   x/2d 以十进制形式显示

 

      printf命令:

      printf  “%2.2s\n”, (char*)0x981e018

       printf  “%2.2s\n”, instruct->string

      

      %2.2s\n  第一个2表示最多输出2个单元第二个2表示从0x981e018开始的两个

 

      set命令在程序调试过程中设置变量的值。

 

使用断点:

       (gdb) break test2.c:21 test2.c文件的第21行设置断点

       (gdb) break 23            在调试文件的第23行设置断点

       (gdb) break printmessage 在调试文件的breakmessage函数处设置断点

      

       查看当前调试程序的断点:

       info break(b)

       编号 类型               可用      地址     断点信息

       Num  Type                  Disp  Enb       Address  What

      1     breakpoint     keep   y        0x080484b9  in main at test2.c:15

      2     breakpoint     keep   n        0x08948630  in printmessage at test2.c:57

 

      run 到断点处,执行continue命令恢复程序运行。

      continue   cont  两个命令作用相同

      cont 2 跳过两次断点

 

      (gdb) bbreak 32   32行加入一个临时断点,只能断点一次

 

      (gdb) enable 3    将断点3设置为可用

      (gdb) disable 3    将断点3设置为不可用

      (gdb) delete 2     将断点2删除

      (gdb) clear 行号  clear 23 23行的断点清除掉。注意此处是行号,而delete使用的是断点编号。

 

使用观察窗口:

      (gdb) watch counter>15

      当表达式满足条件时,显示变量的值

 

查看栈信息:

       backtrace bt 查看栈信息

       (gdb) bt        查看当前调用栈的所有信息

       (gdb) backtrace <n>  打印栈顶n层的栈信息

       (gdb) bt <-n>                     打印栈底n层的栈信息

       (gdb) frame <n>           n为一个从0开始证书,栈中的编号,frame 0表示栈顶 f 1 表示第二层

       (gdb) frame f          查看当前栈的信息

       (gdb) info frame          给出更为详细的当前栈信息

      

       info args   显示出当前函数中所有局部变量及值

       info locals  显示函数中所有局部变量及值

       info catch   显示当前函数中的异常处理信息

      

       查看源程序:

       gdb可以打印出来所调试的源代码,在程序编译时需要加入-g参数。

      

       (gdb) list  <linenum>          打印linenum行的代码

       (gdb) list  <function>         打印function函数的源程序

      

       (gdb) list                           显示当前行后面的源程序

       (gdb) list -                         显示当前行前面的源程序

      

       通过set listsize <count>     设置一次显示的源码行数

       show listsize                       查看当前listsize的设置

      

       (gdb) list <first>, <last>      显示从first行到last行的代码

      

       注:一路list,当到达文件结尾时,再输入list命令出现已经到结尾的提示,使用list num可以将list设置到num行开始显示。

      

       forward-search <regexp>     regexp为正则表达式,前向搜索regexp表达的字符串

       search <regexp>                  regexp为正则表达式,前向搜索regexp表达的字符串

      

       reverse-search <regexp>             反向搜索字符串

      

       搜索字符串时,对于源文件,只编译进了文件名称,没有目录名,可以通过directory进行设置。

       (gdb) directory <dirname …> 可以使用 “:”隔开多个目录名称

       show directories                         显示源文件的搜索路径

      

       info line 可以显示源代码在内存中的地址,info line 后可以跟行号,函数名,文件名:行号,文件名:函数名等。

      

       查看执行中变量内容:

       (gdb) print *array@len                显示数组的内容

      

       输出格式化

       print  </f>  <expr>                  其中f表示格式字符串

       f取值:

       x 十六进制                  d十进制                     u 十进制无符号整型

       o 八进制                     t 二进制格式             a 十六进制格式

       c 字符格式                  f 浮点数格式

       如:

       (gdb) p /c i  i按照字符形式输出

       (gdb) p /f i  i按照浮点数形式打印出来

      

       examine( x) 查看内存   x /<n/f/u> <addr>参考前面总结

      

       display <expr>                   自动显示表达式的值

       display /<fmt> <expr>        自动显示表达式的值

      display /<fmt> <expr>         自动显示表达式的值

       expr 为变量或表达式,fmt为格式

      

       undisplay <dnums …>

       delete display <dnums …>  dnums为设置好的自动显示的编号,也即显示表达式的编号,可以通过info display来查看自动显示的信息

      

      disable display <dnums …>

       enalble display <dnums …>  使得显示可用和不可用

      

       设置显示选项:

       set print address

       set print address on  打开地址输出,当程序显示函数信息时,会显示函数的参数地址

       set print address off             关闭函数的参数地址显示

       show print address             查看当前地址显示选项是否打开

      

       同样 array为显示数组

             elements 显示数组的元素个数信息

             null-stop  遇到结束符时停止显示

             pretty      显示结构体每个元素占一行

             union      显示结构体,是否显示其内的联合体数据

             object      C++对象显示

             static-members 显示静态成员

             vtbl  比较规整的格式来显示虚函数表

 

       改变程序执行:

       修改变量值  x=4直接修改变量x的值为4

       为了防止和系统的变量冲突,在设置变量值时,加上var set var x= 4

      

       跳转执行:

       jump <linespec>    指定下一个语句的运行点,linespec可以是文件的行号,file:line,可以是+num便宜格式

       jump <address>     address代表代码行的内存地址

      

       也可以通过 set $pc = 0x456             通过设置pc值来改变程序运行

      

       产生信号量:

       signal <signal>      Linux系统的信号量从115<signal>的取值也在这个范围。

      

       强制返回:

       return

       return <expression>      强制返回一个值,expression

      

       强制调用函数:

       call <expr>    表达式

      

       分析core文件:

       程序执行前,执行$ ulimit –c unlimited 命令,使得自己拥有core dump的权限。

      

       编译程序,直接执行(不要在gdb下执行),出现错误,就可以使用gdb分析core.*文件,看错出现位置。

      

       其中使用 bt命令可以查看栈的情况,使用frame命令(frame statcknum)查看指定栈帧的内容。

 

By Andy @ 2012-07-12 17:06

原创粉丝点击