zoukankan      html  css  js  c++  java
  • gdb调试

    Debugging with gdbhttps://www.eecs.umich.edu/courses/eecs373/readings/Debugger.pdf

                 http://sourceware.org/gdb/current/onlinedocs/gdb/   内容较新

    gdb概述: 

      UNIX及UNIX-like下的调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在 UNIX平台下做软件,你会发现GDB这个调试工具相比于VC、z的优点是具有修复网络断点以及恢复链接等功能,比BCB的图形化调试器有更强大的功能。所谓“尺有所短,寸有所长”就是这个道理。

      注意,如果要使用gdb调试指定的C/C++程序,则该程序在编译时要添加:-g选项,如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。

    gdb使用技巧:

    https://wizardforcel.gitbooks.io/100-gdb-tips/content/set-watchpoint.html

    https://sourceware.org/gdb/onlinedocs/gdb/index.html#SEC_Contents

    如何生成可调试程序

    以使用gcc为例,例如编写好test.c文件

    1、最简单的

    gcc test.c 会在当前路径下直接生成a.out

    2、分步骤编译

    将源文件编译成目标文件:gcc - c test.c,将生成test.o文件

    再将目标文件编译成可执行文件:gcc -o test test.o

    3、一步到位,并可通过 -o 设置生成文件名

    gcc test.c -o test  //test.c是文件名

    -o 表示输出,test是输出的文件名

      但是通过上述命令编译生成test,在使用gdb进行调试、加断点的时候,会出现:No symbol table is loaded. Use the "file" command.

      因为在编译的时候没有使用 -g 选项,通过命令:gcc -g test.c -o test 编译后,即可通过gdb进行调试,并且添加断点也可以。

    gdb调试相关命令

    调试

    • s:step,即跳进调用的函数
    • n:next,继续执行下一行代码,单条语句执行
    • c:继续运行程序,continue的缩写

    断点相关

     添加断点

    •  在文件特定行加断点:b file:linenum,如果在程序当前执行的文件上的某行加断点,则可简单的使用:b linenum 即可;弊端:如果你修改了源程序,则之前通过行号设置的断点可能就不是你想要的了,需要重新设置断点
    • 指定函数:b func,或 break func
    • 退出函数:finish

    设置断点的方法:
        break <function>
            在进入指定函数时停住。C++中可以使用class::function或function(type,type)格式来指定函数名。

        break <linenum>
            在指定行号停住。

        break +offset
        break -offset
            在当前行号的前面或后面的offset行停住。offiset为自然数。

        break filename:linenum
            在源文件filename的linenum行处停住。

        break filename:function
            在源文件filename的function函数的入口处停住。

        break *address
            在程序运行的内存地址处停住。

        break
            break命令没有参数时,表示在下一条指令处停住。

        break ... if <condition>
            ...可以是上述的参数,condition表示条件,在条件成立时停住。比如在循环境体中,可以设置break if i==100,表示当i为100时停住程序。

        查看断点时,可使用info命令,如下所示:(注:n表示断点号)
        info breakpoints [n]
        info break [n]

    保存断点信息为文件 & 加载含断点信息的文件

      在gdb中,可以使用如下命令将设置的断点保存下来:

    (gdb) save breakpoints file-name-to-save

      下次调试时,可以使用如下命令批量设置保存的断点:

    (gdb) source file-name-to-save

    设置临时断点

      设置临时断点后,该断点只执行一次,通过tbreak(缩写:tb)进行临时断点设置:tb file:linenum

    条件断点

    gdb可以设置条件断点,也就是只有在条件满足时,断点才会被触发,命令是“break … if cond”,只有在表达式为true的时候断点才会生效 

     查看:

    • 查看断点:info b回车,或者info break
    • 查看堆栈:bt

    断点管理

      查看断点:info b回车后,会打印断点的编号及所在位置、是否使能等;如果要删除某个断点,可以:a)d 编号,b)delete 编号;如果要使某个断点disable/enable,可以:disable/enable 编号;

    观察点

      参考:https://wizardforcel.gitbooks.io/100-gdb-tips/content/set-watchpoint.html
      gdb可以使用“watch”命令设置观察点,缩写:wa,也就是当一个变量值发生变化时,程序会停下来。通过 watch 变量名 的形式,当变量的值发生改变时,程序就会停下来。

      观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,马上停住程序。有下面的几种方法:

       
        watch <expr>
            为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序。
           
        rwatch <expr>
            当表达式(变量)expr被读时,停住程序。
           
        awatch <expr>
            当表达式(变量)的值被读或被写时,停住程序。
       
        info watchpoints
            列出当前所设置了的所有观察点。

    打印

     打印变量

    • p 变量名,print的缩写
    • 以指定的格式打印变量:print /<f> expr,例如对于一些数据,可能要按16进制打印,就可以使用命令:print /x <expr>

      打印的格式包括:

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

      d  按十进制格式显示变量。
      u  按十六进制格式显示无符号整型。
      o  按八进制格式显示变量。
      t  按二进制格式显示变量。
      a  按十六进制格式显示变量。
      c  按字符格式显示变量。
      f  按浮点数格式显示变量。

      如果想要打印格式更好看些,可以输入命令:set print pretty on

      有时候在调试时,打印的变量并没有完全显示,显示完整的变量信息,输入命令:set print element 0

    打印ASCII和宽字符字符串

    • ASCII字符串:x/s 变量名
    • 打印宽字符字符串,首先确认宽字符的长度
    p sizeof(wchar_t)

    由于当前平台宽字符的长度为4个字节,则用“x/ws 变量名”命令。如果是2个字节,则用“x/hs 变量名”命令进行打印。

     打印大数组

    在gdb中,如果要打印大数组的内容,缺省最多会显示200个元素:

    可以使用如下命令,设置这个最大限制数:

    (gdb) set print elements number-of-elements

    也可以使用如下命令,设置为没有限制:

    (gdb) set print elements 0

    (gdb) set print elements unlimited
    (gdb) p array

     打印变量类型和所在的文件

    在gdb中,可以使用如下命令查看变量的类型,下面的he为变量名:

    (gdb) whatis he
    type = struct child

    如果想查看详细的类型信息:

    (gdb) ptype he
    type = struct child {
        char name[10];
        enum {boy, girl} gender;
    }

    如果想查看定义该变量的文件:

    (gdb) i variables he
    All variables matching regular expression "he":
    
    File variable.c:
    struct child he;
    
    Non-debugging symbols:
    0x0000000000402030  she
    0x00007ffff7dd3380  __check_rhosts_file

    gdb会显示所有包含(匹配)该表达式的变量。如果只想查看完全匹配给定名字的变量:

    (gdb) i variables ^he$
    All variables matching regular expression "^he$":
    
    File variable.c:
    struct child he;

    函数调用

    退出正在调试的函数

    • 输入finish
    • 输入return
    • 输入:return 值,例如:return 10,退出了函数并且修改了函数的返回值

    直接执行函数

    通过 call func(),或者 print func() 的形式,直接调用并执行某个函数

    列出附近的代码:

      GDB 可以打印出所调试程序的源代码,当然,在程序编译时一定要加上-g的参数,把源程序信息编译到执行文件中。不然就看不到源程序了。当程序停下来以后,GDB会报告程序停在了那个文件的第几行上。你可以用list命令来打印程序的源代码。还是来看一看查看源代码的GDB命令吧。
       
        list <linenum>
            显示程序第linenum行的周围的源程序。
       
        list <function>
            显示函数名为function的函数的源程序。
           
        list
            显示当前行后面的源程序。
       
        list -
            显示当前行前面的源程序。

    一般是打印当前行的上5行和下5行,如果显示函数是是上2行下8行,默认是10行,当然,你也可以定制显示的范围,使用下面命令可以设置一次显示源程序的行数。

        set listsize <count>
            设置一次显示源代码的行数。
           
        show listsize
            查看当前listsize的设置。

    list命令还有下面的用法:

        list <first>, <last>
            显示从first行到last行之间的源代码。
       
        list , <last>
            显示从当前行到last行之间的源代码。
           
        list +
            往后显示源代码。

     一般来说在list后面可以跟以下这们的参数:

         <linenum>   行号。

        <+offset>   当前行号的正偏移量。
        <-offset>   当前行号的负偏移量。
        <filename:linenum>  哪个文件的哪一行。
        <function>  函数名。
        <filename:function> 哪个文件中的哪个函数。
        <*address>  程序运行时的语句在内存中的地址。

     退出程序:

    • q:quit的缩写

    调试正在运行的进程

      已知进程号,通过gdb调试并查看问题:gdb -p 进程号

    调试中使用已编写好的断点文件

    • 在gdb调试过程中,可以通过 source xx文件的形式,这样不用每次都手动输入断点信息

     

    启动gdb

      启动gdb有以下三种方式:

       1、gdb <program>
           program也就是你的执行文件,一般在当然目录下。

        2、gdb <program> core
           用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。

        3、gdb <program> <PID>
           如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试它。program应该在PATH环境变量中搜索得到。

    信号(Signals)

      信号是一种软中断,是一种处理异步事件的方法。一般来说,操作系统都支持许多信号。尤其是UNIX,比较重要应用程序一般都会处理信号。UNIX定义了许多信号,比如SIGINT表示中断字符信号,也就是Ctrl+C的信号,SIGBUS表示硬件故障的信号;SIGCHLD表示子进程状态改变信号;SIGKILL表示终止程序运行的信号,等等。信号量编程是UNIX下非常重要的一种技术。

      GDB有能力在你调试程序的时候处理任何一种信号,你可以告诉GDB需要处理哪一种信号。你可以要求GDB收到你所指定的信号时,马上停住正在运行的程序,以供你进行调试。你可以用GDB的handle命令来完成这一功能。

        handle <signal> <keywords...>
        在GDB中定义一个信号处理。信号<signal>可以以SIG开头或不以SIG开头,可以用定义一个要处理信号的范围(如:SIGIO-SIGKILL,表示处理从SIGIO信号到SIGKILL的信号,其中包括SIGIO,SIGIOT,SIGKILL三个信号),也可以使用关键字all来标明要处理所有的信号。一旦被调试的程序接收到信号,运行程序马上会被GDB停住,以供调试。其<keywords>可以是以下几种关键字的一个或多个。

            nostop
                当被调试的程序收到信号时,GDB不会停住程序的运行,但会打出消息告诉你收到这种信号。
            stop
                当被调试的程序收到信号时,GDB会停住你的程序。
            print
                当被调试的程序收到信号时,GDB会显示出一条信息。
            noprint
                当被调试的程序收到信号时,GDB不会告诉你收到信号的信息。
            pass
            noignore
                当被调试的程序收到信号时,GDB不处理信号。这表示,GDB会把这个信号交给被调试程序会处理。
            nopass
            ignore
                当被调试的程序收到信号时,GDB不会让被调试程序来处理这个信号。


        info signals
        info handle
            查看有哪些信号在被GDB检测中。

       例如,对于SIGUSR1信号,如果不想处理该信号,可以输入:handle SIGUSR1 nostop noprint

    数组

        有时候,你需要查看一段连续的内存空间的值。比如数组的一段,或是动态分配的数据的大小。你可以使用GDB的“@”操作符,“@”的左边是第一个内存的地址的值,“@”的右边则你你想查看内存的长度。例如,你的程序中有这样的语句:
        
            int *array = (int *) malloc (len * sizeof (int));
           
        于是,在GDB调试过程中,你可以以如下命令显示出这个动态数组的取值:

           *array@len

        @的左边是数组的首地址的值,也就是变量array所指向的内容,右边则是数据的长度,其保存在变量len中,其输出结果,大约是下面这个样子的:
       
            (gdb) p 
    *array@len
            $1 = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40}

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

    参考:

    https://blog.csdn.net/haoel/article/details/2880

    https://blog.csdn.net/haoel/article/details/2881

    https://baike.baidu.com/item/gdb/10869514

  • 相关阅读:
    mysql 数据类型
    drop、delete和truncate三者的区别
    JavaScript中的闭包
    MySQL数据类型的最优选择
    常见卤制问题
    四川红油的制法
    Make Sense ?
    大学英语四级考试题型结构
    小数据池、is 和 ==的区别
    各种数据类型相互转换
  • 原文地址:https://www.cnblogs.com/zyk1113/p/13502181.html
Copyright © 2011-2022 走看看