linux下的调试工具gdb的详细使用介绍

ops/2024/9/24 8:52:16/

 在之前学习中我们使用的通常是集各种功能于一体的编译器,例如VS stdio,但是一个程序在编辑后还要进行编译,然后才能产生一个二进制的可执行文件,编辑和翻译工作都可以使用不同的软件进行,例如记事本就是一款编辑软件,除了编辑和翻译,还有一种功能在我们的学习过程中常常会用到,那就是调试。
 今天就带大家仔细学习如何在LInux(我使用的Linux版本是centos7.6。)下使用gdb对C程序进行调试。我会先进行讲解,然后会用截图进行演示,确保大家看到现象。
首先要知道自己是否下载调试工具gdb,我们可以通过这个指令进行查看。

gdb --version

在这里插入图片描述

 这样就能看到我们该操作系统下是否下载gdb,也可以详细看到他的版本,如果没有下载的话只需要使用yum指令进行下载即可。
在这里插入图片描述
 要注意,如果是普通用户需要进行提权才能下载,如果是root(超级用户)就不需要加上前边的sudo,因为我之前已经下载过了而且版本也是最新的,所以最下边告诉我什么都没有做。
准备工作已经结束,接下来进入正题
 首先一个常识就是,只能在degug模式下进行调试,因为release版本并没有调试信息,但是Linux下默认是release版本,所以我们要在编译时加上-g选项。
我们随便写一点C代码。
在这里插入图片描述
 如何证明加上-g选项产生的可执行文件是debug模式的呢?
 可以在使用默认release模式进行编译产生一个新的文件exe。
在这里插入图片描述
 通过大小我们可以明显看出a.out的大小是要大于exe文件的。还有一种方法就是直接使用gdb进行调试,如果能调试就一定是debug版本,如果不能就是release版本。
在这里插入图片描述
对比一下
在这里插入图片描述
 首先,从gdb模式下退出是q指令。输入q键后直接敲回车就退出到命令行模式。
l指令
 单单输入l会帮我们打印我们写的c程序的前十行代码,再输入l会自动向后打印,直至打印至末尾位置。
如图
在这里插入图片描述
 l指令也可以直接加行号,从num行开始打印。

l num

在这里插入图片描述

 l还可以直接在代码中查找某函数,然后直接打印出函数上下的几行代码。下图为C代码,我们可以看到有一个add函数和main函数。
在这里插入图片描述
 我们在gdb模式下想直接锁定main函数,就可以直接使用l指令,空格加main函数即可。
如图:
在这里插入图片描述
 如果单单只能看代码那就很low了,接下来我们对比VS stdio中调试时的操作,对gdb如何实现同样功能实现详细的讲解。
首先就是打断点操作。
 对应vs中F9就是打断点和取消断点,在gdb中对应的操作就是b加行号。
在这里插入图片描述
 命令行提示断点已经打好了,但是我们怎么知道断点是真的打好了呢?
info b指令
 info b指令就是用来查看我们所打得断点的信息。
在这里插入图片描述
 我们可以看到会给我们提供很多的断点的信息,前边序号和种类不必多说,Disp表示是否常显示,对于断点来说就是断点执行一次之后是否还有效,例如在循环中的断点,如果是keep状态下次就还会有效,如果继续调试还是会停在该断点的位置,如果状态为dis就为无效。
 Enb就是该断点的是使能开关,如果是y表示该断点继续使用,如果为n就表示该断点不生效,就会直接跳过该断点。
 后边Address表示该断点的地址,whta就是断点在哪个函数哪个位置第几行。
 上边都是粗略的解释,下边我会给大家详细演示如何使用它们或者改变他们的属性。
知道了如何创建断点,那么如何删除断点呢?
d 指令
 要注意的是,这里d后边跟的是断点的序号,而不是断点的行号。
我们来创建几个删除几个观察现象。
 创建时不会按照断点的行号进行排序,第几个打得断点就是几号。如图
在这里插入图片描述
删除断点的操作
在这里插入图片描述
 可见1号断点和3号断点成功被删除了。那么此时我们继续创建断点,序号是补上1和3呢,还是继续向后添加序号为5的断点呢?
一试便知。
在这里插入图片描述
不会对断点进行补齐,而是继续向后排列,不要记错咯。
 当然我们前边添加和删除断点的操作是在该次调试下有效的,如果q退出调试后再次进入我们之前所打的断点就都不复存在了,再次调试后序号就会从1重新开始。
 有关断点,我们还需要知道如何打开或关闭使能开关,但是就算现在说了还是不能好好演示效果,所以在此之前讲一讲gdb中对应vs中f5的操作。下边的指令都要稍微记忆一下,不然很容易忘掉。
在这里插入图片描述
点击F5调试后,会直接跳到第一个断点的位置,在gdb中就是r指令。

r:对应vs下F5,跳到下一断点处。

来使用一下,现在我们打了以下三个断点。
在这里插入图片描述

 输入r进行调试,就可以直接运行到我们打断点的位置。此时再次查看断点信息就可以看到一号断点已经被命中了一次。
在这里插入图片描述
接下来介绍另一个操作,逐过程调试,即vs下的F10。
在这里插入图片描述
 逐过程和逐语句的区别就是,逐语句会进入函数中,会走完程序的所有代码,而逐过程会把函数认定为一个过程,直接走完该函数。
 逐过程对应的就是n(next),逐语句对应的就是s(step)。
我们来看现象
在这里插入图片描述
我们第一个缎带你打在第十行,可以看出下一步就是输入a的值,然后进行判断。
在这里插入图片描述
 此时运行到if判断句,我们逐语句或者逐过程调试时,会自动打印出当前所在行。因为linux下没有图形化界面,所以只能打印出提示我们当前光标所在行。作用就和下图的小箭头一样。
在这里插入图片描述
 因为n是逐过程,所以到达调用函数的语句只会执行一步,我们来观察现象。
我们直接在调用函数的语句前打上一个断点。
在这里插入图片描述
 直接r跳转,因为前边有打印操作,直接忽略就好了。
可以看到这样一条语句
在这里插入图片描述
此时执行n命令。

在这里插入图片描述
可以看到,并没有跳转到该函数位置。
 前边所说的s是逐语句运行,所以按理说会跳转到add函数的位置,实践检验真知。
 同样将断点设置在进入函数时的语句,r直接跳转到断点处,然后使用s指令观看现象
在这里插入图片描述
上边return的语句就是我们在add函数中的语句。

在这里插入图片描述
现在已经知道基本的调试的操作了,但是在vs中还有一个十分关键的功能就是
在这里插入图片描述
在调试中,一定想要知道程序中变量的变化,所以就需要我们的监视功能。
 gdb下当然也是有这个功能的,对应的就是p加上变量名,就可以查看当前程序中该变量的值。
为了验证这个功能,新写一段代码。(编译时记得-g选项哦)。
在这里插入图片描述

直接在main函数第一条语句前打上断点,然后单步运行进行观察。
在这里插入图片描述
可以看到,我们使用p指令时,下边就会给我们显式打印a的值。
在这里插入图片描述
未执行b的初始化时,b的值为0,单步运行后即为4,可见操作是正确的。
但是对比vs下是一个悬浮窗口,而且是常显示的,我们可以一直看到。
当然,gdb也可以设置常显示。
在这里插入图片描述
每次向下执行时都会打印两个变量的大小,这就是变量的常显示。
如何取消变量的常显示呢?
 我们可以看到,每次打印常显示变量的时候,前边都有一个编号,我们就是使用undisplay加序号即可。
如何查看我们设置的常变量呢?
info display
在这里插入图片描述
将一号变量取消常显示
在这里插入图片描述
 我们在display时,也可以同时常显示多个文件,将所有变量常显示全部关闭,然后同时将三个变量常显示。但是要求这几个变量是相同类型的即可。
在这里插入图片描述
还记得前边断点的描述吗?如何不使用某个断点呢?
我们可以关闭该断点的是能开关。
在这里插入图片描述
使用的指令就是disable加序号。要和前边的display要区分开哦!
在这里插入图片描述
此时这个断点就是未启用的。
如果想继续用这个断点呢?就要启用该断点,enable指令加序号就能使使能开关设置为y。
在这里插入图片描述
调试中还有其他的操作

  • until n行号:直接跑到第n行。

在这里插入图片描述

  • finish进入某个函数时,如果想要直接走完这个函数就可以直接finish。

  • c:从这个断点直接到达下一个断点。

  • 如果在运行过程中想要修改某个变量的值,就可以使用set var指令,修改一个变量的值。
    在这里插入图片描述
     可以看出,在修改后a的值就变成了1,程序在后边的运行中a的变量都会因为这次改变而改变,从而影响程序运行的结果。
    gdb下基本的指令操作到这里就全部讲解完毕了,如果有什么错误还请指正,欢迎大家讨论。


http://www.ppmy.cn/ops/34488.html

相关文章

COUNT(1)\COUNT(*)\COUNT(列名)到底谁更快

今天来研究一个比较有趣的话题,关于我们平常使用mysql查询数量的到底那种方式查询效率更高的问题 起因 这个问题在我以前的认知里是,按效率从高到低品排序 count(1)>count(列名)>count(*),但是我也注意到过mybatis-plus官方提供的selectCount方法和分页查询时,它的SQL在…

mybaits在Oracle中使用merge into

逻辑&#xff1a;如果数据库里有&#xff0c;则进行更新操作&#xff0c;如果没有则插入数据。 这里的insert可以不用写字段 merge INTO table_name a using ( SELECT count( field01) co FROM table_name WHERE field01 123456 ) b ON ( b.co <> 0 ) WHEN MATCHED T…

【学习vue 3.x】(五)VueRouter路由与Vuex状态管理

文章目录 章节介绍本章学习目标 路由的基本搭建与嵌套路由模式vue路由的搭建嵌套路由模式 动态路由模式与编程式路由模式动态路由模式编程式路由 命名路由与命名视图与路由元信息命名路由命名视图路由元信息 路由传递参数的多种方式及应用场景路由传参 详解route对象与router对…

【neteq】tgcall的调用、neteq的创建及接收侧ReceiveStatisticsImpl统计

G:\CDN\P2P-DEV\Libraries\tg_owt\src\call\call.cc基本是按照原生webrtc的来的:G:\CDN\P2P-DEV\tdesktop-offical\Telegram\ThirdParty\tgcalls\tgcalls\group\GroupInstanceCustomImpl.cpptg对neteq的使用 worker 线程创建call Call的config需要neteqfactory Call::CreateAu…

pandas读取文件导致jupyter内核崩溃如何解决

读取execl文件出现以下问题: str_name "D:\\cao_use\\2017_2021(new).xlsx" train_df pd.read_excel(str_name, usecols[0])崩溃的指示图如下所示: bug原因:读入的文件太大&#xff0c;所需时间过长&#xff0c;在读取的过程中&#xff0c;使用中断按钮暂停会直…

前端面试题(八)

面试形式&#xff1a;线下面试&#xff1a;一面&#xff1a;30分钟二面&#xff1a;30分钟 特殊要求&#xff1a;内网开发自研UI组件库&#xff08;无文档介绍&#xff09;学习能力要求高 面试评价&#xff1a;题目灵活应用性较强 面试官&#xff1a;项目负责人前端负责人 …

简易版商城表设计

1、商品表 CREATE TABLE tz_prod (prod_id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 产品ID,prod_name varchar(300) NOT NULL DEFAULT COMMENT 商品名称,shop_id bigint(20) DEFAULT NULL COMMENT 店铺id,ori_price decimal(15,2) DEFAULT 0.00 COMMENT 原价,p…

ROS2学习——Docker环境下安装于使用(1)

目录 一、简要 二、ROS2和ROS1区别 三、环境搭建与安装 &#xff08;2&#xff09;拉取ubuntu22.04镜像 &#xff08;2&#xff09;安装ROS2 1. 基本设置 2.设置源 3.安装ROS2功能包 4.测试 四、相关指令学习 1.小海龟测试 2.ros2 node等指令 3.rqt 一、简要 随着R…