调试工具gdb

1.1 gdb符号调试器简介

  gdb是一个用来调试C和C++程序的功能强大的调试器,它能在程序运行时观察程序的内部结构和内存的使用情况。

  gdb主要提供以下几种功能:

  • 监视程序中变量值的变化
  • 设置断点,使程序在指定的代码行上暂停执行,便于观察
  • 单步执行代码
  • 分析崩溃程序产生的core文件

    gdb filename(执行文件名)

    编译时需加上-g 或 -ggdb3 选项

1.2 gdb功能详解及其应用

  1.2.1调试步骤

    1.调用gdb

      gdb filename

    2.设置断点并调试

      break functionname/linenumer

      run 执行程序

      step 单步跟踪程序代码

    print命令:

      print 表达式

      print 变量=表达式

      print 开始表达式@要打印连续内存空间的大小

    display命令:

      display 表达式

      在使用display命令时,每次调试器中断程序,挂起指令都要显示变量的值

    next命令:

      不进入函数内部

    quit命令:

      退出gdb

  1.2.2 显示数据命令

    1. print命令与display命令

    finish 执行完当前函数

    2. 内存检查命令

      x /format address

        format指显示单元的个数以及显示的格式

      例如:x/2c 0x120100fa0

    3.printf      类似于c里的printf()函数

      例如:printf"%2.2s\n",(char*)0x120100fa0

    4.使用set命令

      set variable 变量=表达式                      设置变量值

  1.2.3 使用断点

    continue命令和cont命令(cont 数字  表示执行数字次继续)

    break 行号

    break 函数名

    条件断点:

      condition 断点编号 表达式                   程序在表达式为真时中断

    tbreak  行号  临时断点

    (break  行号

       enable delete 断点号)等效于临时上一个断点

    enable  断点编号                恢复失效断点

    disable  断点编号     使断点失效

    delete    断点编号或表达式        清除断点(无提示信息)

    clear   要清除的断点所在行号      清除断点(有提示信息)

  1.2.4 使用观察窗口

    watch  表达式                     如果表达式中某个变量的取值超过了范围,就不能再对表达式取值了。这一点与条件断点设置不同,因为它只在代码的固定位置取值。

  1.2.5 查看栈信息

    backtrace

    bt

    bt n  栈顶上n层栈信息

    bt -n  栈顶下n层栈信息

    frame n

    f n          n是一个从0开始的整数,是栈中的层编号。比如:frame 0表示栈顶,frame 1表示栈的第二层

    up n  表示向栈的上面移动n层,不输入n表示移动一层

    down n  表示向栈的下面移动n层

    以下为不带提示信息的移动栈层信息:

      select-frame n

      up-silently n

      down-silently n

      ---------------

      frame 或 f               查看当前栈层信息(包括栈层编号,当前函数名,函数参数值,函数所在文件及行号,函数执行到的语句)

      info frame 或 info f    该命令会显示更为详细的当前栈层的信息,只不过大多数都是运行时的内地址。

      info args  显示出当前函数的参数名及值

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

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

     1.2.6 查看源程序

    1. 显示源代码 

      list <linenum>    显示程序第linenum行的周围的源程序。

      list <function>    显示函数名为function的函数的源程序

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

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

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

      show listsize  查看当前listsize的设置

      list <first>,<last>  显示从first行到last行之间的源代码

      list ,<last>  显示当前行到last行之间的源代码

      list +  向后显示源代码

      一般来说,在list后面可以跟以下这些参数。

      <linenum>:行号。

      <+offset>:当前行号的正偏移量

      <-offset>:当前行号的负偏移量

      <filename:linenumber>:哪个文件的哪一行

      <function>:函数名

      <filename:function>:哪个文件的哪个函数

      <*address>:程序运行时的语句在内存中的地址

    2.搜索源代码

      forward-search <regexp>

      search <regexp>  向前搜索

      reverse-search <regexp>  全部搜索

    3.指定源文件的路径

      directory <dirname ...>

      dir <dirname ...>

      directory  清除所有自定义源文件搜索路径信息

      show directories  显示定义了源文件搜索路径

    4.源代码的内存

      info line  行号/函数名

      info line 文件名:行号/文件名:函数名

      disassemble func  查看func的汇编代码

      disassemble address

  1.2.7 查看运行时数据

    1.表达式

      @  一个和数组有关的操作符

      ::  指定一个在文件或是一个函数中的变量

      {<type>} <addr>   表示一个指向内存地址<addr>的类型为type的一个对象

    2.程序变量

      全局变量(所有文件可见)

      静态全局变量(当前文件可见的)

      局部变量(当前Scope可见的)

      示例:

        file::variable

        function::variable

        p 'f2.c'::x

    3.数组

      例如:程序中有如下语句

        int *array = (int *)malloc(len * sizeof(int));

      p *array@len

      如果是静态数组的话,直接用"print 数组名"就可以显示数组中所有数据的内容了。

    4.输出格式

      x  按十六进制格式显示变量

      d  按是禁止格式显示变量

      u  按十六进制格式显示无符号整形

      o  按八进制格式显示变量

      t  按二进制格式显示变量

      a  按十六进制格式显示变量

      c  按字符格式显示变量

      f  按符点数格式显示变量

    5.查看内存

      x/<n/f/u> <addr>  nfu是可选参数。

                n表示显示内存的长度,

                f表示显示的格式,

                u表示从当前地址往后请求的字节数,如果不指定的话,gdb默认是4个bytes。

                u可用以下字符来代替:b表示单字节,h双字节,w四字节,g八字节。

                addr表示一个内存地址。

      示例:

      x/3uh 0x54320    以无符号整形双字节为单位显示从地址0x54320开始的3个长度的内存中的内容

    6.自动显示

      可以设置一些自动显示的变量,当程序停住时,或是在单步跟踪时,这些变量会自动的显示。

      display <expr>

      display/<fmt> <expr>

      display/<fmt> <addr>

      格式i和s同样被display支持,一个非常又用的命令是:

      display /i $pc    $pc是gdb的环境变量,表示指令的地址,/i则表示输出格式为机器指令码,也就是汇编。与是当程序停下后,就会出现源代码和机器码相对应的情形。

      undisplay <dnums...>

      delete display <dnums...>

        删除自动显示,dnums意为设置好了的自动显示的编号。如果要同时删除几个编号,可以用空格分隔;如果要删除一个范围内的编号,可以用减号表示。

      disable display <dnums...>

      enable display <dnums...>

        不删除自动显示的设置,而只是让其失效和恢复,而只是让其失效和恢复。

      info diaplay

        查看display设置的自动显示的信息。gdb会显示出一张表格,报告中设置了多少个自动显示设置,其中包括设置的编号,表达式以及是否enable。

    7.设置显示选项

      set print address on/off  显示函数参数地址  系统默认打开

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

      set print array on/off      打开/关闭数组显示,打开后数组显示时每个元素占一行;关闭时每个元素以逗号分隔。这个选项默认时关闭的。

      show print array

      set print elements <number-of-elements>  这个选项主要时设置数组的,如果数组太大了,就可以指定一个<number-of-elements>来指定数据显示的最大长度,当达到这个长度时,gdb就不再往下显示了。如果设置为0,则表示不限制。

      show print elements

      set print null-stop <on/off>  如果打开了这个选项,那么当显示字符串时,遇到结束符则停止显示。这个选项默认为off。

      set print pretty on/off  选项打开时,当gdb显示结构体时会比较漂亮。

      show print pretty

      set print sevenbit-stirngs <on/off>   设置字符显示,是否按“\nnn”的格式显示。如果打开,则字符串或字符数据按\nnn显示,如“\065”

      show print sevenbit-stirngs

      set print union <on/off>    设置显示结构体时,是否显示其内的联合体数据。

      show print union  查看联合体数据的显示方式

      set print object <on/off>  对象选项设置。在C++中,当一个对象指针指向其派生类时,如果打开这个选项,gdb会自动按照虚方法调用的规则显示输出,如果关闭这个选项,gdb就不管虚函数表了。这个选项默认为off。

      show print object  查看对象选项的设置

      set print static-members <on/off>  这个选项表示,当显示一个C++对象中的内容时,是否显示其中的静态数据成员。默认为on。

      show print static-members  查看静态数据成员选项设置

      set print vtbl <on/off>  当此选项打开时,gdb将用比较规整的格式来显示虚函数表。其默认是关闭的。

      show print vtbl  查看虚函数显示格式的选项

    8.历史记录

      每一个print命令都会被gdb记录下来。gdb会以$1,$2,$3......这样的方式为每一个print命令编上号。于是,可以使用这个编号访问以前的表达式,如$1。

    9.gdb环境变量

      可以在gdb调试环境中定义自己的变量,用来保存一些调试程序中的运行数据。

      环境变量没有类型,可以给环境变量定义任意的类型,包括结构体和数组。

      set $foo = *object_ptr

      show convenience  查看当前所设置的所有的环境变量

      (set i = 0

      print bar[$i++]->contents)  这个一个比较强大的功能,环境变量与程序变量的交互使用使得程序调试更为灵活便捷。输入这样的命令后,按下Enter键,重复执行上一条语句,环境变量会自动增加,从而完成逐个输出的功能。  

    10.查看寄存器

      info registers  查看寄存器的情况(除了符点器存器)

      info all-registers  查看所有寄存器的情况

      info registers <regname...>   查看指定寄存器的情况

  1.2.8 改变程序的执行

    1.修改变量值

      print x=4

      whatis width  

      set var width=47

    2.跳转执行

      jump <linespec>  <linespec>可以是文件的行号,可以是file:line格式,可以是+num这种偏移量格式。表示下一条语句从哪里开始。

      jump <address>  这里的<address>是代码行的内存地址。

      建议在同一个函数内调转

      熟悉汇编的人都知道,程序运行时有一个寄存器用于保存当前代码所在的内存地址。所以,jump命令也就是改变了这个寄存器中的值。可以使用set $pc来更改调转执行的地址。如:

      set $pc=0x485

    3.产生信号量

      使用signal命令可以产生一个信号量给被调试的程序。如中断信号Ctrl+C。这非常方便与程序的调试,可以在程序运行的任意位置设置断点,并在该断点用gdb产生一个信号量。精确地在某处产生信号非常有利程序的调试。其语法是:

      signal <signal>

        Linux的系统信号量通常从1-15,所以<signal>也在这个范围。

    4.强制函数返回

      如果调试断点在某个函数中,还有语句没有执行完,可以使用return命令强制函数忽略还没有执行的语句并返回。

      return

      return expression

      使用return命令取消当前函数的执行,并立即返回。如果指定了<expression>,那么该表达式的值会被当作函数的返回值。

    5.强制调用函数

      call <expr>    表达式中也可以是函数

      另一个相似的命令也可以完成这一功能--print。print后面可以跟表达式,所以也可以用它来调用函数。print和call不同之处是,如果函数返回void,call则不显示,print则显示函数的返回值,并把该值存入历史数据中。

    6.在不同语言中使用gdb

      show language  查看当前语言环境

      info frame  查看当前函数的程序语言

      info source  查看当前文件的程序语言

      set language   如果set language后面什么也不跟,可以查看gdb所支持的语言种类。可以在set language 后面加上被列出的语言名,来设置当前的语言环境。

  1.2.9 core dump分析

    在进行程序开发时,常常由于种种原因导致程序崩溃。这时可以使用Linux下的core dump功能。在程序崩溃时,Linux会创建一个core文件,在程序结束后,利用这个文件中的信息,在使用gdb,就能指导程序崩溃时在做些什么。但core dump功能并不是所有的程序员都可以使用的,这是因为一些发行版和一些系统的管理员在默认时禁止使用core dump。可以使用ulimit -c unlimited

    这样就能使用core文件分析了。

    编译生成可执行文件test,然后运行./test生成core文件

    gdb test core

    bt(即backtrace)命令用来打印stack frame(栈桢)指针,可以了解当前程序运行过程中的函数之间的调用关系。

    使用frame命令:

      frame命令是用来打印栈桢的,它使用如下格式。

      frame 要打印的栈桢的编号  如果没有指定栈桢时,gdb会打印当前选择的栈桢

      可以使用info frame命令查看当前所选择的栈桢,它将给出栈桢的详细信息。

1.3 其他调试工具

  xxgdb  是X-Windows系统的调试工具,实际上它图形化的gdb,保留了gdb所有的特性。

1.4 小结

  在软件开发中出现错误在所难免,所以程序的调试就成为软件开发中非常重要的一个环节,gdb就是Linux系统下C程序调试工具中最常用的一种。本章首先介绍了gdb的程序调试步骤,进而深入地阐述了它的功能和一些高级调用方法。最后简单介绍了另一种调试工具。

posted on 2018-07-17 04:00  wtsgtc  阅读(368)  评论(0编辑  收藏  举报

导航