GDB调试知识总结

GDB调试知识总结

GDB背景

  • 调试概念:调试就是让代码一步一步慢慢执行,跟踪程序的运行过程。也就是说,通过调试程序,我们可以监控程序执行的每一个细节,包括变量的值、函数的调用过程、内存中数据、线程的调度等,从而发现隐藏的错误或者低效的代码。

  • 常用的调试器(Debugger)

    调试器名称 特 点
    Remote Debugger Remote Debugger 是 VC/VS 自带的调试器,与整个IDE无缝衔接,使用非常方便。
    WinDbg 大名鼎鼎的 Windows 下的调试器,它的功能甚至超越了 Remote Debugger,它还有一个命令行版本(cdb.exe),但是这个命令行版本的调试器指令比较复杂,不建议初学者使用。
    LLDB XCode 自带的调试器,Mac OS X 下开发必备调试器。
    GDB Linux 下使用最多的一款调试器,也有 Windows 的移植版。

GDB安装

  • 判断当前 Linux 发行版是否安装有 GDBgdb -v
  • 安装GDB
    1. 情况1:直接调用该操作系统内拥有的 GDB 安装包,使用包管理器进行安装:
      • RedHat 系列的 Linux 发行版:sudo yum -y install gdb
      • Debian 系列的 Linux 发行版:sudo apt -y install gdb
    2. 情况2:到 GDB 官网下载相应的GDB源码包

使用GDB前期准备

  • 背景:使用gcc main.c -o main.exe生成的可执行文件不支持使用 GDB 进行调试。这是由于,使用 GDB 调试某个可执行文件,该文件中必须包含必要的调试信息(比如各行代码所在的行号、包含程序中所有变量名称的列表(又称为符号表)等),而上面生成的 main.exe 则没有。
  • 编译指令gcc main.c -o main.exe -g

GDB调试过程

  1. 启动GDB(有四种方式)
  2. GDB传递参数gdb --args main.exe a.txt
  3. 设置断点
    • 设置普通断点:break linenumbreak filename:linenum
    • 设置观察断点:watch [变量或表达式]
  4. 查看断点
    • 查看普通断点:info breakpoint [n]info break [n]
    • 查看观察断点:info watchpoint [n]
  5. 运行run
  6. 堆栈bt
  7. 进入堆栈相应行f [行号]
  8. 查看使用的动态库i shared
  9. 单步调试
    • next [执行行数count]:不进入函数内部。
    • step [执行行数count]:进入函数内部。
  10. 反向调试
  • reverse-step:反向执行一行代码,会退回到函数内部。
  • reverse-next:反向执行一行代码,不会退回函数内部。
  1. 查看变量

    • print [变量]
    • display\fmt [变量]:自动打印
  2. 禁用和删除断点

    • 删除断点:clear [linenum]delete [断点序号列表]
    • 禁用/激活断点:disable [num..]enable [num..]num..表示可以提供多个断点的编号

启动GDB调试器

  • 启动GDB调试命令gdb main.exe

    该指令在启动 GDB 的同时,会打印出一堆免责条款。通过添加 --silent(或者 -q、--quiet)选项,可将比部分信息屏蔽掉,即gdb main.exe --silent

GDB调试命令

  • 常用的GDB调试命令

    每一个指令既可以使用全拼,也可以使用其首字母表示。

命令(缩写) 功 能
run(r) 启动或者重启一个程序。
list(l) 显示带有行号的源码。
continue(c) 让暂停的程序继续运行。
next(n) 单步调试程序,即手动控制代码一行一行地执行。
step(s) 如果有调用函数,进入调用的函数内部;否则,和 next 命令的功能一样。
until(u)
until location(u location)
当你厌倦了在一个循环体内单步跟踪时,单纯使用 until 命令,可以运行程序直到退出循环体。 until n 命令中,n 为某一行代码的行号,该命令会使程序运行至第 n 行代码处停止。
finish(fi) 结束当前正在执行的函数,并在跳出函数后暂停程序的执行。
return(return) 结束当前调用函数并返回指定值,到上一层函数调用处停止程序执行。
jump(j) 使程序从当前要执行的代码处,直接跳转到指定位置处继续执行后续的代码。
print(p) 打印指定变量的值。
quit(q) 退出 GDB 调试器。

调用GDB调试器的4种方式

  1. 直接使用 gdb 指令启动 GDB 调试器gdb

    • 这种情况下需要手动指定要调试的目标程序:file /tmp/demo/main.exe
  2. 调试尚未执行的程序gdb main.exe

  3. 调试正在执行的程序:步骤如下:

    1. 获取该程序运行所对应的进程号:pidof main.exe(文件名)
    2. 使用以下任意一个指令,对该程序进行调试:
      • gdb attach PID
      • gdb 文件名 PID
      • gdb -p PID
    3. 手动将 GDB 调试器与程序分离,消除调试操作对该程序的影响:
      1. 执行 detach 指令,使 GDB 调试器和程序分离;
      2. 执行 quit 指令,退出 GDB 调试。
  4. 调试执行异常崩溃的程序

    • 核心转储(core dump):在 Linux 操作系统中,当程序执行发生异常崩溃时,系统可以将发生崩溃时的内存数据、调用堆栈情况等信息自动记录下载,并存储到一个文件中,该文件通常称为core文件,Linux 系统所具备的这种功能又称为核心转储。

      默认情况下,Linux 系统是不开启 core dump 这一功能的。

    • 查看是否开启核心转储功能:ulimit -culimit -a

      • 如果 core file size(core 文件大小)对应的值为 0,表示当前系统未开启 core dump 功能。
    • 开启核心转储功能:ulimit -c unlimited

      • 如果 core file size(core 文件大小)对应的值为unlimited,表示当前系统开启了 core dump 功能,unlimited 表示不限制 core 文件的大小。
    • 调试core文件:gdb main.exe core

GDB调试器启动可用参数

参 数 功 能
-pid number
-p number
调试进程 ID 为 number 的程序。
-symbols file
-s file
仅从指定 file 文件中读取符号表。
-q
-quiet
-silent
取消启动 GDB 调试器时打印的介绍信息和版权信息
-cd directory 以 directory 作为启动 GDB 调试器的工作目录,而非当前所在目录。
--args 参数1 参数2... 向可执行文件传递执行所需要的参数。

run 和 start 指令

  • 作用:run 和 start 指令都可以用来在 GDB 调试器中启动程序。
  • 区别
    • 默认情况下,run 指令会一直执行程序,直到执行结束。如果程序中手动设置有断点,则 run 指令会执行程序至第一个断点处;
    • start 指令会执行程序至 main() 主函数的起始位置,即在 main() 函数的第一行语句处停止执行(该行代码尚未执行)。

GDB调试传递参数

  • 方法1:使用 --args 选项指定需要传递给该程序的数据。

    • 示例:gdb --args main.exe a.txt,启动 GDB 调试器调试 main.exe 程序,并为其传递 "a.txt" 这个字符串。
  • 方法2:GDB 调试器启动后,可以借助 set args 命令指定目标调试程序启动所需要的数据。

    • 示例:set args a.txt,该命令表示将 "a.txt" 传递给将要调试的目标程序。
  • 方法3:使用 run 或者 start 启动目标程序时,指定其所需要的数据。

    • 示例:

      (gdb) run a.txt
      (gdb) start a.txt
      

GDB下修改环境变量

  • 修改 PATH 环境变量path /temp/demo

GDB设置断点

  • 查看所有断点

    • 方法1:info breakpoint [n]
    • 方法2: info break [n]
    • 参数 n :为可选参数,为某个断点的编号,表示查看指定断点而非全部断点。
    • 输出信息含义:断点编号(Num)、断点类型(Type)、是临时断点还是永久断点(Disp)、目前是启用状态还是禁用状态(Enb)、断点的位置(Address)、断点当前的状态(作用的行号、已经命中的次数等,用 What 列表示)。
  • 查看观察断点info watchpoint [n]

  • 格式1break location,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 函数的开头位置打断点。
  • 格式2break ... if cond

    • ... 可以是上表中所有参数的值,用于指定打断点的具体位置;cond 为某个表达式。
    • 整体的含义:每次程序执行到 ... 位置时都计算 cond 的值,如果为 True,则程序在该位置暂停;反之,程序继续执行。

GDB tbreak命令

  • 与break的不同:tbreak 和 break 命令的用法和功能都非常相似,唯一的不同在于,使用 tbreak 命令打的断点仅会作用 1 次,即使程序暂停之后,该断点就会自动消失。

GDB rbreak 命令

  • rbreak概述:和 break 和 tbreak 命令不同,rbreak 命令的作用对象是 C、C++ 程序中的函数,它会在指定函数的开头位置打断点。

  • 语法格式rbreak regex

    • regex 为一个正则表达式,程序中函数的函数名只要满足 regex 条件,rbreak 命令就会其内部的开头位置打断点。

    rbreak 命令打的断点和 break 命令打断点的效果是一样的,会一直存在,不会自动消失。

GDB watch命令:监控变量值的变化

  • watch命令

    • 背景知识:GDB 调试器支持在程序中打 3 种断点,分别为普通断点、观察断点和捕捉断点。其中 break 命令打的就是普通断点,catch命令建立的是捕捉断点,而 watch 命令打的为观察断点。
    • 作用:借助观察断点可以监控程序中某个变量或者表达式的值,只要发生改变,程序就会停止执行。
    • 语法格式:watch cond,cond 指的就是要监控的变量或表达式。
    • 类似命令:
      1. rwatch命令:只要程序中出现读取目标变量(表达式)的值的操作,程序就会停止运行;
      2. awatch命令:只要程序中出现读取目标变量(表达式)的值或者改变值的操作,程序就会停止运行。
      3. watch 命令:只有当被监控变量(表达式)的值发生改变,程序才会停止运行。
  • 查看当前建立的观察点的数量info watchpoints

  • watch监控不同类型变量/表达式

    • 当监控的变量(表达式)为局部变量(表达式)时:一旦局部变量(表达式)失效,则监控操作也随即失效;
    • 当监控的是一个指针变量(例如 *p)时:watch *pwatch p 是有区别的,前者监控的是 p 所指数据的变化情况,而后者监控的是 p 指针本身有没有改变指向;
  • watch命令的原理

    • watch 命令实现监控机制的方式:

      1. 软件观察点:用 watch 命令监控目标变量(表达式)后,GDB 调试器会以单步执行的方式运行程序,并且每行代码执行完毕后,都会检测该目标变量(表达式)的值是否发生改变,如果改变则程序执行停止。

        • 缺点:这种“实时”的判别方式,一定程度上会影响程序的执行效率。
      2. 硬件观察点:它在实现监控机制的同时不影响程序的执行效率。简单的理解,系统会为 GDB 调试器提供少量的寄存器,每个寄存器都可以作为一个观察点协助 GDB 完成监控任务。

        基于寄存器个数的限制,如果调试环境中设立的硬件观察点太多,则有些可能会失去作用,这种情况下,GDB 调试器会发出如下警告:Hardware watchpoint num: Could not insert watchpoint。

        受到寄存器数量的限制,可能会出现:无法使用硬件观察点监控数据类型占用字节数较多的变量(表达式)。比如说,某些操作系统中,GDB 调试器最多只能监控 4 个字节长度的数据,这意味着 C、C++ 中 double 类型的数据是无法使用硬件观察点监测的。这种情况下,可以考虑将其换成占用字符串少的 float 类型。

  • 强制 GDB 调试器只建立软件观察点set can-use-hw-watchpoints 0

    • 背景:目前,大多数 PowerPC 或者基于 x86 的操作系统,都支持采用硬件观点。并且 GDB 调试器在建立观察断点时,会优先尝试建立硬件观察点,只有当前环境不支持硬件观察点时,才会建立软件观察点。

GDB catch命令:建立捕捉断点

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

  • 语法格式catch event

    • 常用的 event 事件类型:

      event 事件 含 义
      throw [exception] 当程序中抛出 exception 指定类型异常时,程序停止执行。如果不指定异常类型(即省略 exception),则表示只要程序发生异常,程序就停止执行。
      catch [exception] 当程序中捕获到 exception 异常时,程序停止执行。exception 参数也可以省略,表示无论程序中捕获到哪种异常,程序都暂停执行。
      load [regexp] unload [regexp] 其中,regexp 表示目标动态库的名称,load 命令表示当 regexp 动态库加载时程序停止执行;unload 命令表示当 regexp 动态库被卸载时,程序暂停执行。regexp 参数也可以省略,此时只要程序中某一动态库被加载或卸载,程序就会暂停执行。
  • tcatch 命令:和 catch 命令的用法完全相同,唯一不同之处在于,对于目标事件,catch 命令的监控是永久的,而 tcatch 命令只监控一次,也就是说,只有目标时间第一次触发时,tcath 命令才会捕获并使程序暂停,之后将失效。

GDB条件断点(condition命令)

  • 条件断点:以某个表达式的是否成立作为条件,从而决定自身是否生效的断点,又称为条件断点。

    • 除了普通断点外,观察断点和捕捉断点也可以成为条件断点。
    • 但捕捉条件断点无法直接生成,需要借助 condition 命令为现有捕捉断点增添一个 cond 表达式,才能使其变成条件断点。
  • 语法格式

    • condition bnum expression:用于为 bnum 编号的断点添加或修改 expression 条件表达式;
      • bnum :用于代指目标断点的编号;
      • expression :表示为断点添加或修改的条件表达式。
    • condition bnum:用于删除 bnum 编号断点的条件表达式,使其变成普通的无条件断点。
  • condition 命令的功能:既可以为现有的普通断点、观察断点以及捕捉断点添加条件表达式,也可以对条件断点的条件表达式进行修改。

GDB单步调试程序

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

  • 单步调试的方法:next、step 和 until 命令。

  • next命令

    • 语法格式:next count,参数 count 表示单步执行多少行代码,默认为 1 行。
    • next 命令可以缩写为 n 命令
  • step命令:step 命令和 next 命令的功能相同,都是单步执行程序。不同之处在于,当 step 命令所执行的代码行中包含函数时,会进入该函数内部,并在函数第一行代码处停止执行。

    • 语法格式:step count,参数 count 表示一次执行的行数,默认为 1 行。
    • step 命令可以缩写为 s 命令
  • until命令:until的两种格式的命令具有不同的作用。

    • 语法格式:

      1. until:能够使 GDB 调试器快速运行完当前的循环体,并运行至循环体外停止。

        只有当执行至循环体尾部(最后一行代码)时,until 命令才会发生此作用;反之,until 命令和 next 命令的功能一样,只是单步执行程序。

      2. until location:指示 GDB 调试器直接执行至指定位置后停止。

GDB finish和return命令

  • finish命令

    • 作用:实际调试时,在某个函数中调试一段时间后,可能不需要再一步步执行到函数返回处,希望直接执行完当前函数,这时可以使用 finish 命令。
  • return命令

    • 作用:与finish命令类似。
  • finish 命令和 return 命令的区别:finish 命令会执行函数到正常退出;而 return 命令是立即结束执行当前函数并返回,也就是说,如果当前函数还有剩余的代码未执行完毕,也不会执行了。

GDB jump命令

  • jump命令
    • 作用:jump 命令的功能是直接跳到指定行继续执行程序,也就是说,跳转处与指定行之前的程序都不会执行,因此程序可能会出现bug。
    • 语法格式:jump location,其中,location 通常为某一行代码的行号。

GDB print和display命令

  • display命令与print命令的区别:使用 display 命令查看变量或表达式的值,每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动帮我们打印出来,而 print 命令则不会。

  • display命令:用于调试阶段查看某个变量或表达式的值。

    • 语法格式:display 命令没有缩写形式,常用的语法格式有 2 种。

      1. display expr

      2. display/fmt expr

        display 命令和 /fmt 之间不要留有空格。以 /x 为例,应写为 (gdb)display/x expr。

    • 参数:

      1. expr :表示要查看的目标变量或表达式;
      2. fmt :用于指定输出变量或表达式的格式
    • fmt常用值:

      /fmt 功 能
      /x 以十六进制的形式打印出整数。
      /d 以有符号、十进制的形式打印出整数。
      /u 以无符号、十进制的形式打印出整数。
      /o 以八进制的形式打印出整数。
      /t 以二进制的形式打印出整数。
      /f 以浮点数的形式打印变量或表达式的值。
      /c 以字符形式打印变量或表达式的值。

GDB禁用和删除断点

  • 删除断点

    • clear命令:
      • 语法格式: clear location
      • 参数 location :通常为某一行代码的行号或者某个具体的函数名。当 location 参数为某个函数的函数名时,表示删除位于该函数入口处的所有断点。
    • delete命令:
      • 语法格式:delete [breakpoints] [num]
        1. breakpoints 参数可有可无
        2. num 参数为指定断点的编号,其可以是 delete 删除某一个断点,而非全部。
  • 禁用断点:使目标断点暂时失去作用,必要时可以再将其激活,恢复断点原有的功能。

    • 语法格式:disable [breakpoints] [num...]
      1. breakpoints 参数可有可无;
      2. num... :表示可以有多个参数,每个参数都为要禁用断点的编号。如果指定 num...,disable 命令会禁用指定编号的断点;反之若不设定 num...,则 disable 会禁用当前程序中所有的断点。
  • 激活断点:对于禁用的断点,可以使用 enable 命令激活。

    • 语法格式:
      • enable [breakpoints] [num...] :激活用 num... 参数指定的多个断点,如果不设定 num...,表示激活所有禁用的断点。
      • enable [breakpoints] once num… :临时激活以 num... 为编号的多个断点,但断点只能使用 1 次,之后会自动回到禁用状态。
      • enable [breakpoints] count num... :临时激活以 num... 为编号的多个断点,断点可以使用 count 次,之后进入禁用状态。
      • enable [breakpoints] delete num… :激活 num.. 为编号的多个断点,但断点只能使用 1 次,之后会被永久删除。
    • 参数:
      1. breakpoints 参数可有可无;
      2. num... :表示可以提供多个断点的编号,enable 命令可以同时激活多个断点。

GDB调试多线程程序

  • 调试多线程与单线程程序的区别:调试多线程程序需要监控多个线程的执行过程,进而找到导致程序出现问题的异常或 Bug,而调试单线程程序只需要监控 1 个线程。

  • GDB多线程调试常用命令

    调试命令 功 能
    info threads 查看当前调试环境中包含多少个线程,并打印出各个线程的相关信息,包括线程编号(ID)、线程名称等。
    thread id 将线程编号为 id 的线程设置为当前线程。
    thread apply id... command id... 表示线程的编号;command 代指 GDB 命令,如 next、continue 等。整个命令的功能是将 command 命令作用于指定编号的线程。当然,如果想将 command 命令作用于所有线程,id... 可以用 all 代替。
    break location thread id 在 location 指定的位置建立普通断点,并且该断点仅用于暂停编号为 id 的线程。
    `set scheduler-locking off on
  • 编译多线程程序gcc main.c -o main.exe -g -lpthread

  • GDB查看所有线程info threads [id...]

    • 参数id:可选参数,表示要查看的线程编号,编号个数可以是多个。

    • 输出信息解析:Id 列表示各个线程的编号(ID 号);Target Id 列表示各个线程的标识符;Frame 列打印各个线程执行的有关信息,例如线程名称,线程暂停的具体位置等。

      输入的调试命令并不仅仅作用于当前线程,例如 continue、next 等,默认情况下它们作用于所有线程。

  • GDB调整当前线程thread [id]

  • GDB执行特定线程thread apply [id...] [command]

    • 示例:thread apply 2 next

    默认情况下,无论哪个线程暂停执行,其它线程都会随即暂停;反之,一旦某个线程启动(借助 next、step、continue 命令),其它线程也随即启动。GDB 调试默认的这种调试模式(称为全停止模式),一定程序上可以帮助我们更好地监控程序中各个线程的执行。

  • GDB为特定线程设置断点

    • 语法格式:
      1. break [location] thread [id]
      2. break [location] thread [id] if...
    • 参数:
      1. location:表示设置断点的具体位置;
      2. id :表示断点要作用的线程的编号;
      3. if... :作用指定断点激活的条件,即只有条件符合时,断点才会发挥作用。
    • 示例:
      • break 7 thread 3:在第 7 行代码处为 3 号线程单独设置了一个普通断点,该断点仅对 3 号线程有效。
  • GDB设置线程锁

    • 作用:使用 GDB 调试多线程程序时,默认的调试模式为一个线程暂停运行,其它线程也随即暂停;一个线程启动运行,其它线程也随即启动。设置线程锁则可以实现只让某一特定线程运行,其它线程仍维持暂停状态。

    • 命令:set scheduler-locking [mode]

      • 参数mode:值有 3 个,分别为 off、on 和 step。
        1. off:不锁定线程,任何线程都可以随时执行;
        2. on:锁定线程,只有当前线程或指定线程可以运行;
        3. step:当单步执行某一线程时,其它线程不会执行,同时保证在调试过程中当前线程不会发生改变。但如果该模式下执行 continue、until、finish 命令,则其它线程也会执行,并且如果某一线程执行过程遇到断点,则 GDB 调试器会将该线程作为当前线程。
    • 示例:set scheduler-locking on

  • 查看各个线程锁定的状态show scheduler-locking

GDB non-stop模式

  • all-stop 模式:只要有一个线程暂停执行,所有线程都随即暂停。

  • non-stop 模式:当某一线程暂停运行时,其它线程仍可以继续执行。

  • non-stop 模式与all-stop 模式区别:在 all-stop 模式下,continue、next、step 命令的作用对象并不是当前线程,而是所有的线程;但在 non-stop 模式下,continue、next、step 命令只作用于当前线程。

  • 命令set non-stop [mode]

    • 参数:mode 参数的值有 2 种,分别是 on 和 off,on 表示启用 non-stop 模式;off 表示禁用 non-stop 模式。
  • 查看 non-stop 模式是否开启show non-stop

GDB在后台执行调试命令

  • 背景run(r)continue(c)next(n)等调试命令在执行过程中,是无法使用其它 GDB 调试命令的,换句话说,只有当一个调试命令执行结束后,(gdb) 命令提示符才会出现,我们才能执行下一个调试命令。

  • GDB调试器的两种执行方式

    • 同步执行:必须等待前一个命令执行完毕,才能执行下一个调试命令。
    • 后台执行:又称“异步执行”,即当某个调试命令开始执行时,(gdb) 命令提示符会立即出现,我们无需等待前一个命令执行完毕就可以继续执行下一个调试命令。
  • 后台执行命令[command]&。command 表示就是要执行的调试命令。

  • 暂停后台线程执行interrupt

    在 all-stop 模式下,interrupt 命令作用于所有线程,即该命令可以令整个程序暂停执行;而在 non-stop 模式下,interrupt 命令仅作用于当前线程。 如果想另其作用于所有线程,可以执行 interrupt -a 命令。

GDB调试多进程程序

  • 查看进程数目info inferiors

  • 切换到指定编号的进程inferiors id

  • attach命令:能够调试父子进程。

    • 语法格式:attach pid
  • GDB显式指定要调试的进程

    • 方法1语法格式:set follow-fork-mode mode

      • 参数mode 的可选值有 2 个:
        1. parent:选项的默认值,表示 GDB 调试器默认只调试父进程;
        2. child:表示 GDB 只调试子进程。且当程序中包含多个子进程时,可以逐一对它们进行调试。
    • 方法2语法格式:set detach-on-fork mode

      • mode 参数的可选值有 2 个:
        1. on:默认值,表明 GDB 只调试一个进程,可以是父进程,或者某个子进程;
        2. off:程序中出现的每个进程都会被 GDB 记录,我们可以随时切换到任意一个进程进行调试。
    • 两种方法区别:借助 follow-fork-mode 选项,我们只能选择调试子进程还是父进程,且一经选定,调试过程中将无法改变。如果既想调试父进程,又想随时切换并调试某个子进程,就需要借助 detach-on-fork 选项。

  • GDB调试常用命令

    命令语法格式 功 能
    show detach-on-fork 查看当前调试环境中 detach-on-fork 选项的值。
    info inferiors 查看当前调试环境中有多少个进程。其中,进程 id 号前带有 * 号的为当前正在调试的进程。
    inferiors id 切换到指定 ID 编号的进程对其进行调试。
    detach inferior id 断开 GDB 与指定 id 编号进程之间的联系,使该进程可以独立运行。不过,该进程仍存在 info inferiors 打印的列表中,其 Describution 列为 ,并且借助 run 仍可以重新启用。
    kill inferior id 断开 GDB 与指定 id 编号进程之间的联系,并中断该进程的执行。不过,该进程仍存在 info inferiors 打印的列表中,其 Describution 列为 ,并且借助 run 仍可以重新启用。
    remove-inferior id 彻底删除指令 id 编号的进程(从 info inferiors 打印的列表中消除),不过在执行此操作之前,需先使用 detach inferior id 或者 kill inferior id 命令将该进程与 GDB 分离,同时确认其不是当前进程。

GDB反向调试

  • 背景:单步调试和断点调试方法,在调试过程中代码一直都是“正向”执行的。如果调试过程中不小心多执行了一次 next、step 或者 continue 命令,就会比较麻烦。所谓反向调试,指的是临时改变程序的执行方向,反向执行指定行数的代码,此过程中 GDB 调试器可以消除这些代码所做的工作,将调试环境还原到这些代码未执行前的状态。

  • 反向调试常用命令

    命 令 功 能
    record
    record btrace
    让程序开始记录反向调试所必要的信息,其中包括保存程序每一步运行的结果等等信息。进行反向调试之前(启动程序之后),需执行此命令,否则是无法进行反向调试的。
    reverse-continue (rc) 反向运行程序,直到遇到使程序中断的事件,比如断点或者已经退回到 record 命令开启时程序执行到的位置。
    reverse-step 反向执行一行代码,并在上一行代码的开头处暂停。和 step 命令类似,当反向遇到函数时,该命令会回退到函数内部,并在函数最后一行代码的开头处(通常为 return 0; )暂停执行。
    reverse-next 反向执行一行代码,并在上一行代码的开头处暂停。和 reverse-step 命令不同,该命令不会进入函数内部,而仅将被调用函数视为一行代码。
    reverse-finish 当在函数内部进行反向调试时,该命令可以回退到调用当前函数的代码处。
    set exec-direction mode mode 参数值可以为 forward (默认值)和 reverse:forward 表示 GDB 以正常的方式执行所有命令;reverse 表示 GDB 将反向执行所有命令,由此我们直接只用step、next、continue、finish 命令来反向调试程序。注意,return 命令不能在 reverse 模式中使用。
posted on 2024-01-22 10:15  WilliamMoa  阅读(478)  评论(0)    收藏  举报