🔥系列文章:《Linux入门》
目录
一、背景
GDB是Linux下的调试工具。
对于GDB调试器来说,是采用纯命令行的形式进行调试。
所以大家又要开始对于指令的学习!!
本文中采用C语言,编译器使用gcc
二、什么是GDB
🌷定义
GDB(GNU Debugger)是GNU开源组织发布的一个强大的Linux下的**程序调试工具。**它主要用来调试C/C++语言写的程序,但也可以调试其他语言程序。
GDB提供了丰富的命令来实现相关功能,如break设置断点、run启动程序、next单步执行、continue继续执行、print打印变量值等。此外,GDB还支持条件断点、断点命令列表、监视点等高级功能,满足开发者在调试过程中的各种需求。
🌷GDB调试工具---提供的帮助
- 启动程序
- 断点管理
- 检查程序状态
- 单步执行
- 继续执行
- 修改程序
- 查看源代码
- 反汇编
- 多线程调试
- 调试coredump文件
三、GDB的安装教程-Ubuntu
🌷gdb的安装
bash
sudo apt install gdb
四、哪类程序可被调试
🔥 要使用gdb调试,必须使用release 版本。
🌷程序的发布方式
只有两种:
- **debug版本:**程序本身会被加入更多的调试信息,以便于进行调试。
- r**elease版本:**不会添加任何调试信息,是不可调试的。
🌷Debug版本、Release版本的区别
- debug版本:有调试信息,文件大小更大
- release版本:无调试信息,文件更小
对于不同身份:
-
对于程序员:在编写代码后运行一般是使用【DeBug】环境进行运行。因为在企业里写软件项目,将代码写完后程序员自己要做简单的测试。当程序员自己测试完没有问题之后,就会将这个可执行程序给到测试人员进行测试,而且会给出自己的单元测试报告。
-
对于测试人员:所处的模式是【Release】,也就是将来客户要使用的这款软件的发布版本。 当测试在测的过程中,一定会发现一些问题。此时测试人员就会把报告再打回研发部。研发部做修改重新生成Release版本的可行性程序给到测试人员继续测试。最后只有当测试通过了,再将生成的【单元测试报告】与产品经理进行核对之后没有问题,那这个软件才可以真正地面向市场👉
🌷编译器的选择
不同编译器生成一个可执行程序时,默认发布版本是不同的。
在本文中使用的gcc编译器, 生成的可执行程序,它是一个**【Release】版本**的,因此无法进行调试。
如果想生成debug版本,就需要在使用gcc/g++生成可执行程序时加上-g选项。
如下,利用 test.c 生成可执行程序mytest的release版本
bash
gcc -o mytest test.c -g
五、调试指令
1)启动程序:
GDB可以按照自定义的要求启动程序,例如设置参数、环境变量等。
在GDB中,启动程序主要有两种方式:使用run命令或者start命令。
**run命令:(**无断点直接运行、有断点从第一个断点处开始运行 )
这是最常用的启动程序的方式。在GDB中输入run(或者简写为r)后,程序会开始执行。
如果程序中设置了断点,那么程序会执行到第一个断点处暂停;
如果没有设置断点,程序会一直执行到结束。此外,run命令也可以带参数,这些参数会被传递给被调试的程序。
start命令:与run命令不同,start命令会执行程序至main()主函数的起始位置,即在main()函数的第一行语句处停止执行(该行代码尚未执行)。
可以理解为,使用start命令启动程序,完全等价于先在main()主函数起始位置设置一个断点,然后再使用run命令启动程序。
2)断点管理:
GDB中的断点管理是一项关键功能,允许开发者在特定位置暂停程序执行以进行检查。以下是关于断点管理的一些常用操作和说明:
- 设置断点 :
- 使用break或b命令可以在源代码的特定行或函数上设置断点。例如,break filename:linenum在filename文件的linenum行设置断点,而break function_name在给定的function_name函数处设置断点。
- 也可以通过条件表达式来设置断点,格式如break location if condition,其中location可以是行号、函数名等,condition是一个条件表达式。只有当该条件为真时,断点才会生效。
- 查看断点 :
- 可以通过info breakpoints命令查看所有设置的断点,包括断点的位置、是否启用、类型、条件和命中次数等信息。
- 删除断点 :
- 使用delete或d命令后接断点编号,可以删除特定的断点,例如delete 1删除编号为1的断点。
- 要删除所有断点,可以使用delete命令而不带任何参数。
- 禁用和启用断点 :
- 可以使用disable和enable命令后接断点编号来禁用或启用特定的断点。例如,disable 2将禁用编号为2的断点,而enable 2将重新启用它。
- 断点的持久性 :
- 在GDB中设置的断点默认情况下是非持久的,也就是说,当你退出GDB并重新启动程序时,这些断点将不再存在。然而,有些GDB版本和前端可能提供了保存和恢复断点的功能,使断点具有持久性。这通常涉及将断点信息保存到一个文件中,并在启动GDB时加载该文件。
- 临时断点 :
- 除了普通断点外,GDB还支持所谓的"临时断点"(也称为"一次性断点")。这种类型的断点在程序到达其位置后会自动删除,因此只会命中一次。这可以通过特定的GDB命令或前端界面来实现。
3)检查程序状态:
当程序被暂停时,GDB可以查看程序中的变量值、内存内容、函数调用栈等信息,帮助开发者了解程序当前的状态。
在GDB中,当程序被暂停时,你可以检查程序的状态,这包括查看变量的值、内存内容、寄存器的内容,以及当前的函数调用栈等信息。
- 查看变量值:使用print命令(或简写为p)可以查看变量的值。例如,print var_name会显示变量var_name的当前值。你也可以使用print命令进行一些复杂的表达式计算,如print var1 + var2。
- 查看内存内容:x命令可以用来检查内存的内容。你可以指定要查看的内存地址和格式。例如,x/16xb address会以16进制格式显示从address开始的16个字节的内容。
- 查看寄存器内容:你可以使用info registers命令查看当前所有寄存器的值。如果你只想查看某个特定的寄存器,可以使用print命令,如print $eax。
- 查看函数调用栈:使用backtrace命令(或简写为bt)可以查看当前的函数调用栈。这会列出从主函数到当前函数的所有函数调用,以及每个函数的参数值。你还可以使用frame命令切换到调用栈中的某个特定函数帧。
- 查看源代码:GDB还可以显示当前执行的源代码行。使用list命令(或简写为l)可以查看当前的源代码,并允许你在源代码中设置断点或查看变量值。
4)单步执行:
GDB支持逐条执行程序中的指令,方便开发者逐步跟踪程序的执行过程。
在GDB中,单步执行是一种重要的调试手段,它允许开发者逐条执行程序中的指令,以便仔细观察程序的行为。GDB提供了几种不同的单步执行命令,以满足不同的调试需求。
- next (或 n) :
- 使用next命令可以执行程序中的下一行代码。如果当前行是一个函数调用,next命令会执行整个函数,然后在函数返回后暂停。
- 简而言之,next命令步进到下一行代码,但不进入函数内部。
- step (或 s) :
- 与next不同,step命令在执行下一行代码时,如果遇到函数调用,会进入函数内部并逐条执行函数内的指令。
- 使用step命令可以深入函数内部进行调试。
- finish :
- 当已经步入一个函数内部,并希望快速执行完剩余部分时,可以使用finish命令。它会继续执行程序直到从当前函数中返回。
- 这个命令在已经了解函数内部行为,只想快速跳到函数完成后的状态时非常有用。
- continue (或 c) :
- 虽然不是传统意义上的单步执行命令,但continue命令在调试过程中也很有用。它会继续执行程序,直到遇到下一个断点或程序结束。
- 在设置了断点后,使用continue可以让程序快速运行到下一个关注点。
- until :
- until命令用于在循环体内单步执行,直到退出循环。如果当前行不在循环体内,则等同于next命令。
- 这个命令在调试循环结构时特别有用,可以避免手动步进整个循环。
- advance :
- advance命令可以指定向前执行到程序的某个位置,这个位置可以是源代码行号、函数名或某个特定的地址。不过请注意,并非所有GDB版本都支持此命令。
5)继续执行:
GDB可以在暂停后继续执行程序,直到遇到下一个断点或程序结束。
在GDB中,继续执行被调试的程序是一个常见的操作,尤其是在设置了断点或进行了单步执行之后。以下是关于如何在GDB中继续执行程序的信息:
continue命令(或简写为c) :
这个命令用于继续执行被调试的程序。在程序暂停后(例如,由于遇到了断点或执行了单步调试命令),你可以使用continue命令恢复程序的执行。程序将继续运行,直到遇到下一个断点、接收到一个信号,或者程序正常结束。
示例:
bash
(gdb) continue
或者简写为:
bash
(gdb) c
如果希望程序继续执行并跳过一定数量的断点,可以在continue命令后加上一个数字,表示希望跳过的断点次数(包括当前这一次)。例如:
bash
(gdb) continue 5
上述命令将使程序继续执行,并跳过接下来的5个断点(但请注意,这种用法可能不是GDB的标准功能;标准的GDB通常只支持不带参数的continue命令)。
然而,在实际使用中,GDB通常只会继续执行到下一个断点或程序结束,而不支持跳过指定数量的断点**。如果需要跳过某些断点,可以考虑临时禁用或删除这些断点。**
总的来说,在GDB中使用continue命令是继续执行被调试程序的标准方式。在执行该命令之前,请确保已经设置了适当的断点或其他停止条件,以防止程序无限制地运行下去。
6)修改程序:
GDB允许在调试过程中修改程序中的变量值或内存内容,这对于测试某些特定条件非常有用。
在GDB中,修改程序通常指的是在调试过程中动态地改变变量的值或内存区域的内容。这种能力对于测试和调试非常有用,尤其是在需要模拟特定条件或绕过错误时。
以下是在GDB中修改程序的一些方法:
-
设置变量值 :
使用set命令可以修改变量的值。例如,set variable_name = new_value会将variable_name的值更改为new_value。这适用于全局变量和局部静态变量。对于非静态局部变量,你可能需要在正确的栈帧中操作。bashset variable_name = new_value
-
调用函数 :
在GDB中,你可以使用call命令调用函数,这可能会改变程序的状态。例如,c**all function_name(arguments)**会调用function_name并传递arguments。调用函数可能会影响程序的行为,因此在使用时需要谨慎。bashcall function_name(arguments)
-
跳转执行 :
尽管不常推荐,但在某些情况下,你可能想要改变程序的执行流程。使用jump命令(如果GDB支持的话)可以跳转到程序的另一个位置执行。然而,这可能会破坏程序的正常执行流程,因此应该非常小心地使用。
7)查看源代码:
GDB可以显示当前执行的源代码行,并允许开发者在源代码中设置断点或查看变量值。
以下是在GDB中查看源代码的几种方法:
- 使用list命令 :
GDB的list命令(或简写为l)可以用来显示当前行的源代码以及周围的代码。你可以指定要显示的行号或函数名。例如,list function_name将显示名为function_name的函数的源代码,而list linenum将显示指定行号linenum周围的代码。如果不带任何参数,list命令通常会显示当前执行点周围的代码。
8)退出gdb
输入 quit
或者 快捷键 ctrl + d