type
date
status
slug
summary
tags
category
password
icon
😀
通过学习GDB来提高代码调试思维和能力。

使用注意事项

  • 要使用gdb对可执行文件进行调试,必须要使该文件具有调试信息,可以利用选项-g来添加

    GDB常用调试命令

    调试指令
    作 用
    (gdb) break xxx (gdb) b xxx
    在源代码指定的某一行设置断点,其中 xxx 用于指定具体打断点的位置。
    (gdb) run (gdb) r
    执行被调试的程序,其会自动在第一个断点处暂停执行。
    (gdb) continue (gdb) c
    当程序在某一断点处停止运行后,使用该指令可以继续执行,直至遇到下一个断点或者程序结束。
    (gdb) next (gdb) n
    令程序一行代码一行代码的执行。
    (gdb) print xxx (gdb) p xxx
    打印指定变量的值,其中 xxx 指的就是某一变量名。
    (gdb) list (gdb) l
    显示源程序代码的内容,包括各行代码所在的行号。
    (gdb) quit (gdb) q
    终止调试。

    GDB调试环境搭建

    根据不同的场景需要,GDB调试器提供了多种方式来启动目标程序,其中最常用的就是run指令,其次为start指令。两者的区别是:
    • 默认情况下,run指令会一直执行程序,直到执行结束。如果程序中手动设置有断点,则run指令会执行程序至第一个断点处;
    • start指令会执行程序至main()主函数的起始位置,即在main()函数的第一行语句处停止执行(该行代码未执行)。
    在进行run或者start指令启动目标程序之前,还可能需要做一些必要的准备工作:
    • 有些C或者C++程序的执行,需要接收一些参数;
    • 目标程序在执行过程中,可能需要临时设置PATH环境变量;
    • 默认情况下,GDB调试器将启动时所在的目录作为工作目录,但很多情况下,该目录并不符合要求,需要在启动程序手动为GDB调试器指定工作目录;
    • 默认情况下,GDB调试器启动程序后,会接收键盘临时输入的数据,并将执行结果打印在屏幕上。但GDB调试器允许对执行程序的输入和输出进行重定向,使其从文件或其它终端接收输入,或者将执行结果输出到文件或其它终端。

    在GDB启动后指定文件(file)

    为GDB调试器指定的目标程序传递参数

    • 启动GDB调试器时,可以在指定目标调试程序的同时,使用--args选项指定需要传递给该程序的数据。
      • GDB调试器启动以后,可以借助set args命令指定目标调试程序启动所需要的数据。
        • 也可以使用run或者start运行目标程序时,指定其所需要的数据。

          GDB工作目录

          默认情况下,GDB调试器的工作目录为启动时所使用的的目录。GDB调试器提供修改工作目录的指令,即cd指令:

          GDB修改PATH变量

          在某些场景中,目标调试程序的执行还需要临时修改PATH环境变量,此时可以借助path指令:
          不过要注意,这种修改只是临时的,只在此次gdb运行过程中有效。

          GDB调试程序输出重定向

          直接给出例子:
          会在工作目录下生成文件a.txt。

          总的来说,只有将调试程序所需要的运行环境搭建好后,才能使用run或者start命令开始调。

          GDB break命令

          break(b)命令常用的语法格式如下:

          第一种格式

          location用于指定打断点的具体位置,其表示方式有多种,如下表所示。
          location 的值
          含 义
          linenum
          linenum 是一个整数,表示要打断点处代码的行号。要知道,程序中各行代码都有对应的行号,可通过执行 l(小写的 L)命令看到。
          filename:linenum
          filename 表示源程序文件名;linenum 为整数,表示具体行数。整体的意思是在指令文件 filename 中的第 linenum 行打断点。
          + offset - offset
          offset 为整数(假设值为 2),+offset 表示以当前程序暂停位置(例如第 4 行)为准,向后数 offset 行处(第 6 行)打断点;-offset 表示以当前程序暂停位置为准,向前数 offset 行处(第 2 行)打断点。
          function
          function 表示程序中包含的函数的函数名,即 break 命令会在该函数内部的开头位置打断点,程序会执行到该函数第一行代码处暂停。
          filename:function
          filename 表示远程文件名;function 表示程序中函数的函数名。整体的意思是在指定文件 filename 中 function 函数的开头位置打断点。

          第二种格式

          第二种格式中,...可以是上表中所有参数的值,用于指定打断点的具体位置;cond为某个表达式。整体的含义为:每次程序执行到

          GDB tbreak命令

          tbreak 命令可以看到是 break 命令的另一个版本,tbreak 和 break 命令的用法和功能都非常相似,唯一的不同在于,使用 tbreak 命令打的断点仅会作用 1 次,即使程序暂停之后,该断点就会自动消失。

          GDB rbreak命令

          和break和tbreak命令不同,rbreak命令的作用对象是C、C++程序中的函数,他会在指定函数的开头位置打断点。
          rbreak命令的使用语法格式为:
          其中regex为一个正则表达式,程序中函数的函数名只要满足regex条件,rbreak命令就会在其内部的开头位置打断点。rbreak与break产生的断点效果一样,会一直存在。

          实时监控变量值

          GDB调试器支持在程序中打3种断点,分别为普通断点、观察断点和捕捉断点。其中break命令打的就是普通断点,而watch命令打的为观察断点。
          使用GDB调试程序的过程中,借助观察断点可以监控程序中某个变量或表达式的值,只要发生改变,程序就会停止运行。相比于普通断点,观察断点不需要我们预测变量值发生改变的具体位置。
          watch命令的语法非常简单:
          其中cond指的就是要监控的变量或表达式,除此之外:
          • rwatch:只要程序中出现读取目标变量的值的操作,程序就会停止运行;
          • awatch:只要程序中出现读取目标变量的值或改变值的操作,程序就会停止运行。
          强调一下,watch命令的功能是:只有当被监控变量的值发生改变,程序才会停止运行。
          如果我们想查看当前建立的观察点的数量,借助如下指令即可:
          值得一提的是,对于使用 watch(rwatch、awatch)命令监控 C、C++ 程序中变量或者表达式的值,有以下几点需要注意:
          • 当监控的变量(表达式)为局部变量(表达式)时,一旦局部变量(表达式)失效,则监控操作也随即失效;
          • 如果监控的是一个指针变量(例如 *p),则 watch *p 和 watch p 是有区别的,前者监控的是 p 所指数据的变化情况,而后者监控的是 p 指针本身有没有改变指向;
          • 这 3 个监控命令还可以用于监控数组中元素值的变化情况,例如对于 a[10] 这个数组,watch a 表示只要 a 数组中存储的数据发生改变,程序就会停止执行。

          GDB catch命令:建立捕捉断点

          捕捉断点的作用是:监控程序中某一事件的发生,例如程序发生某种异常、某一动态库被加载等等,一旦目标时间发生,则程序停止执行:
          用捕捉断点监控某一事件的发生,等同于在程序中该事件发生的位置打普通断点。
          基本格式:

          GDB条件断点(condition命令)

          借助condition命令,我们可以将现有的普通断点、观察断点以及捕捉断点变成条件断点;而普通条件断点和观察条件断点,可以分别通过break if命令和watch if命令直接生成。

          GDB单步调试

          所谓单步调试,就是通过一行一行的执行程序,观察整个程序的执行流程,进而尝试发现一些存在的异常或者Bug。

          GDB next命令(n)

          next是最常用来进行单步调试的命令,其最大的特点是当遇到包含调用函数的语句时,无论函数内部包含多少条代码,next指令都会一步执行完。
          语法格式如下:
          其中count表示单步执行多少行代码,默认为1行。

          GDB step命令(s)

          用法与next相似,但是step会进入函数内部执行。

          GDB until命令(u)

          语法格式如下:
          其中,locationo为某一行代码的行号。
          不带参数的until命令,可以使GDB调试器快速运行完毕当前的循环体,并运行至循环体外停止。注意,until命令并非任何情况下都会发挥这个作用,只有当执行至循环体尾部(最后一行代码)时,until命令产生此作用;反之,until命令和next命令的功能一样,只是单步执行程序。
          until命令还可以跟某行代码的行号,以指示GDB调试器直接执行至指定位置后停止。

          GDB 查看变量的值

          GDB print命令(p)

          功能:输出或者修改指定变量或者表达式的值。
          语法格式:

          GDB display命令

          和print命令一样,display命令也用于调试阶段查看某个变量或者表达式的值,它们的区别在于,使用display命令查看变量或表达式的值,每当程序暂停执行(例如单步执行)时,GDB调试器都会自动帮我们打印出来。
          常用语法格式如下:
          其中fmt用于指定输出变量或表达式的格式,常用格式如下:
          /fmt
          功 能
          /x
          以十六进制的形式打印出整数。
          /d
          以有符号、十进制的形式打印出整数。
          /u
          以无符号、十进制的形式打印出整数。
          /o
          以八进制的形式打印出整数。
          /t
          以二进制的形式打印出整数。
          /f
          以浮点数的形式打印变量或表达式的值。
          /c
          以字符形式打印变量或表达式的值。
          PS:可以使用info display来列出所有监视变量,info命令也可以查看所有的断点。
          对于不需要再打印值的变量,可以将其删除或者禁用:
          • 通过如下命令,即可删除自动显示列表中的变量或表达式:
            • 通过执行如下命令,可以禁用自动显示列表中处于激活状态下的变量或表达式:
              num... 表示要禁用的变量或表达式的编号,编号的个数可以是多个,表示一次性禁用多个变量或表达式
              当然根据需要,也可以激活当前处于禁用状态的变量或表达式,执行如下命令即可:
              参数 num... 表示要激活的变量或表达式的编号,编号的个数可以是多个,表示一次性激活多个变量或表达式。

              GDB 禁用和删除断点

              借助如下指令,可以查看当前调试环境中存在的所有断点,包括普通断点、观察断点以及捕捉断点:
              参数 n 作为可选参数,为某个断点的编号,表示查看指定断点而非全部断点。
              除此之外,对于调试环境中已经建好且未删除的观察断点,也可以使用 info watchpoint 命令进行查看,语法格式如下:
              n 为可选参数,为某个观察断点的编号,功能是只查看该编号的观察断点的信息,而不是全部的观察断点。

              GDB删除断点

              无论是普通断点、观察断点还是捕捉断点,都可以使用 clear 或者 delete 命令进行删除。

              clear命令

              clear 命令可以删除指定位置处的所有断点,常用的语法格式如下所示:
              参数 location 通常为某一行代码的行号或者某个具体的函数名。当 location 参数为某个函数的函数名时,表示删除位于该函数入口处的所有断点。

              2) delete 命令

              delete 命令(可以缩写为 d )通常用来删除所有断点,也可以删除指定编号的各类型断点,语法格式如下:
              其中,breakpoints 参数可有可无,num 参数为指定断点的编号,其可以是 delete 删除某一个断点,而非全部。

              GDB禁用断点

              所谓禁用,就是使目标断点暂时失去作用,必要时可以再将其激活,恢复断点原有的功能。
              禁用断点可以使用 disable 命令,语法格式如下:
              breakpoints 参数可有可无;num... 表示可以有多个参数,每个参数都为要禁用断点的编号。如果指定 num...,disable 命令会禁用指定编号的断点;反之若不设定 num...,则 disable 会禁用当前程序中所有的断点。

              GDB help

              此外,GDB还支持自动补全功能。

              查看当前位置

               
              make一生一芯第一阶段总结