【Linux】Linux工具——gdb

1. gdb 概述

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在 UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。

一般来说,GDB主要帮忙你完成下面四个方面的功能:

  • 1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
  • 2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
  • 3、当程序被停住时,可以检查此时你的程序中所发生的事。
  • 4、动态的改变你程序的执行环境。

从上面看来,GDB和一般的调试工具没有什么两样,基本上也是完成这些功能,不过在细节上,你会发现GDB这个调试工具的强大,大家可能比较习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。

2.使用gdb

mycode.c

 我们先生成一个Debug版本的可执行程序(gcc加上-g选项)

我们可以验证一下它是不是含有debug信息

 很好,有

接下来我们就可以使用gdb进行调试了

在此之前要确保安装了gdb

2.1.显示代码

 l(list) 行号/函数名 —— 显示对应的code,每次10行

  • 首先若是直接【L】的话便会随机显示出该源文件中的随机10行内容,这不是我们想要的
  • 若是【l 0】或者是【l 1】的话那就是从第一行开始往下列10行的内容
    • 注意这里的L是小写,而且与数字之间要有一个空格
  • 我们想要看第二行或者第10行,可以像下面这么做

  • 这个也没有显示出全部代码啊!!!只需要多Enter几次就可以了,gdb会自动记忆你上次敲入的指令

  • 我们还可以查看一个函数

2.2.设置断点

  • r或run:运行程序。

因为我们还没有设置断点,所以一直执行到尾了

 我们现在来打断点

  • break/b 行号:在某一行设置断点
  • break/b 函数名:在某个函数开头设置断点
  • b/break 源文件:行号 —— 在该源文件中的这行加上一个断点 

2.3.查看断点信息

 我们打了3个断点,我们发现我们的断点不像windows上面的断点,我们现在看不到断点,那我们怎么去查呢?

  • info break/b :查看断点信息。
  • 若是直接执行【info】的话,出来的就是所有的调试信息
  • 但若是我们只想查看一下所打的断点的信息,那就在后面加个b/break

 断点的信息都显示出来了

  • 接下来简要介绍一下断点的一些字段信息
  • Num —— 编号
  •  Type —— 类型
  •  Disp —— 状态
  •  Enb —— 是否可用
  •  Address —— 地址
  •  What —— 在此文件的哪个函数的第几行
  • 最后的话就是每个断点信息的下面这块breakpoint already hit 1 time即此断点被命中1次

2.4.删除断点 

我们想删除断点,该怎么做呢?

我们先看看我们之前设置的断点

  •  d + 当前要删除断点的编号 —— 删除一个断点【不可以d + 行号】
  • d + breakpoints —— 删除所有的断点
  • 此时若继续将这个20行的断点打上时,就可以发现其编号为【4】,而并不是从1开始,这是因为我们没有退出过gdb,所以会持续上一次的编号继续往下

2.5.开启/禁用断点

  •   disable b(breakpoints) —— 使所有断点无效【默认缺省】
  • 我们看到所有断点的Enb从y变成了n,代表从可用变成了不可用
  • enable b(breakpoints) —— 使所有断点有效【默认缺省】
  • 我们看到所有断点的Enb从n变成了y,代表从不可用变成了可用
  • disable b(breakpoint) + 编号 —— 使一个断点无效【禁用断点】

  • enable b(breakpoint) + 编号 —— 使一个断点有效【开启断点】

2.6.运行/调试 

r(run) —— F5【无断点直接运行、有断点从第一个断点处开始运行】

  • 首先若是将断点删除掉,使用【r】指令运行的话就会直接运行到程序结束
  • 再加上断点去运行的话就会在打的断点处停下来

2.7.逐过程和逐语句 

我们先看看我们设置的断点 

 n(next) —— 逐过程【相当于F10,为了查找是哪个函数出错了】

  • 可以看到,我从第一个断点处也就是17行的位置开始执行,按下【n】之后因为在其后即19行有一个断点,此时就会直接运行到断点处
  • 按n,再按n,直到结束
  • s(step) —— 逐语句【相当于F11,一次走一条代码,可进入函数,同样的库函数也会进入】

  • 此时我们按下【s】,也就相当于是【step】,让程序一步一步地走,继而进入了Addtop这个函数(如下图),若是你在printf()语句要执行时按下【s】的话gdb就会进入printf()库函数内部去执行,这里就不展示了

  • 接下去我们可以就继续【n】,然后进行逐过程调试,来到for循环中,那么逐过程也就是变量i的累加和计数器count的累加,所以会反复执行(通过图中最左侧可以看出是第8行和第10行在反复执行)
  • 可以看到后面我没有再按【n】了,但是依旧会执行上面的步骤,这点上面也有提到过,因为gdb会自动化记忆你上一次执行过的命令,所以若是不想再敲了,直接Enter就可以了

2.8.打印 / 追踪变量 

p(print) 变量名 —— 打印变量值

  • 都执行了那么多次了,不知道【i】和【count】发生了怎样的变化,将它们打印出来看看吧
  • 通过继续执行【n】,然后再去打印就可以发现i的值和count的值发生了变化
  • 但是你不觉得这样每次去打印会显得很繁琐吗,那一定会的,所以我们有更好的办法💡

    display —— 跟踪查看一个变量,每次停下来都显示它的值【变量/结构体…】
  • 我们也可以去追踪一下这两个变量的地址,不过可以看到对于地址来说是不会发生改变的
  • 但是呢,每次都追踪打印这么多内容又太多了,我想把它们取消了可以吗?答:当然是可以的
  • 既然有display那就有undisplay
  • undisplay + 变量名编号 —— 取消对先前设置的那些变量的跟踪

2.9. 查看函数调用 

bt —— 看到底层函数调用的过程【函数压栈】

  • 通过仔细观察刚才追踪的4个变量最左侧的编号,就可以看到它们的排列的顺序是倒着的。因为变量i和变量res是我们先追踪的,它们的地址是我们后追踪的,所以可以看出这很像是一个压栈的过程
  • 其实不仅是对于它们,Addtop函数和main函数也呈现这样的关系。此时我们就可以通过【bt】这个指令来查看函数压栈的过程,此时便可以看到因为

2.10.修改变量的值 

set var —— 修改变量的值

  • 对于这个修改变量的值,很像是在VS里调试之前设置的那种条件断点,可以使调试开始后直接运行到此断点处。不过对于【set var】而言是在调试过程中进行设置

 2.11.gdb指令合集

注:()括号里面是该指令的全称 

  1.  l(list) 行号/函数名 —— 显示对应的code,每次10行
  2. r(run) —— F5【无断点直接运行、有断点从第一个断点处开始运行】
  3. b(breakpoint) + 行号 —— 在那一行打断点
  4. b 源文件:函数名 —— 在该函数的第一行打上断点
  5. b 源文件:行号 —— 在该源文件中的这行加上一个断点吧
  6. info b —— 查看断点的信息
  7. breakpoint already hit 1 time【此断点被命中一次】
  8. d(delete) + 当前要删除断点的编号 —— 删除一个断点【不可以d + 行号】

  • 若当前没有跳出过gdb,则断点的编号会持续累加
  1. d + breakpoints —— 删除所有的断点
  2. disable b(breakpoints) —— 使所有断点无效【默认缺省】
  3. enable b(breakpoints) —— 使所有断点有效【默认缺省】
  4. disable b(breakpoint) + 编号 —— 使一个断点无效【禁用断点】
  5. enable b(breakpoint) + 编号 —— 使一个断点有效【开启断点】

  • 相当于VS中的空断点
  1. enable breakpount —— 使一个断点有效【开启断电】
  2. n(next) —— 逐过程【相当于F10,为了查找是哪个函数出错了】
  3. s(step) —— 逐语句【相当于F11,】
  4. bt —— 看到底层函数调用的过程【函数压栈】
  5. set var —— 修改变量的值
  6. p(print) 变量名 —— 打印变量值
  7. display —— 跟踪查看一个变量,每次停下来都显示它的值【变量/结构体…】
  8. undisplay + 变量名编号 —— 取消对先前设置的那些变量的跟踪

  • 排查问题三剑客🗡
  1. until + 行号 —— 进行指定位置跳转,执行完区间代码
  2. finish —— 在一个函数内部,执行到当前函数返回,然后停下来等待命令
  3. c(continue) —— 从一个断点处,直接运行至下一个断点处【VS下不断按F5】

3.最常用指令(指令三剑客) 

掌握了上面的这些,你就可以在Linux下调一些简单的代码了,不过想做到高效地进行调试,就需要学习一下【三剑客】

3.1.指定行号跳转 

until + 行号 —— 进行指定位置跳转,执行完区间代码

  • 可以看到,当前在for循环内容执行累加的逻辑,但若是我们一直这么执行下去,就没有时间排错了,除了上面的哪一种【set var】之外,还有一种方法其实起到直接结束当前循环的作用,那就是进行指定行号跳转
  • 通过观察下图可以看到,当我们运行了until 13之后,程序直接就给出了我们最终的结果count,而且即将要执行最后的打印语句,说明我们跳转成功了
  • 然后可以看到,在获取到返回值后,也就直接进行了printf打印

3.2.强制执行函数 

finish —— 在一个函数内部,执行到当前函数返回,然后停下来等待命令

  • 有时候我们会有这样的需求,在初步排查的时候推断可能是某个函数内部的逻辑出了问题,但是呢又不想一步步地进到函数内部进行调试,在VS中其实很简单,只需要在函数下方设个断点,然后F5直接运行到断点处即可
  • 但是在Linux下的gdb中,我们可以使用【finsh】指令来直接使一个函数执行完毕。从下图我们可以看到,首先【s】进到函数内部,接下去我直接使用finish,可以看到它直接回到了调用函数的位置,returned了一个返回值

3.3.跳转到下一断点

c(continue) —— 从一个断点处,直接运行至下一个断点处【VS下不断按F5】

  • 这点也是我刚才在上面有提到过的,在VS中,我们要直接跳转到下一个断点处只修要按下F5即可,那在gdb中该如何操作呢,你需要敲个【c】就可以了
  • 从下图我们可以看出,对于这个指令的用处可谓是非常大,当我处于第一个断点也就是20行的时候,直接敲下【c】,就可以运行到第二个断点处也就是第10行。之后若反复敲【c】,因为这是一个单语句的循环,所以循环的下一次还是会执行到此处。上面的这两个功能就和我们在VS中用的F5是一个道理

4.gdb实战演练

  •  本次演示使用的代码是
  • 我们取名mycode.c,用gcc编译成带有debug信息的
  • 接下来,我们进入GDB 调试模式。

  • 首先我们在程序第16行设置上一个断点,然后【r】从第15行开始运行
  • 然后我们使用【s】进入到swap函数中,因为我首先不想调试,想先立马看看运行结果,但是此时又已经进入调试了,那么我们就可以使用到【finish】来立马执行完这个函数,然后观察一下结果
  • 可以看到,最后打印出结果的时候a和b的值确实发生了交换
  • 既然清楚了二者会进行一个交换,接下去我们就逐语句【n】进行一个单步追踪吧
  • 因为提前看了执行结果,所以我们要重新开始调试,按下【r】即可,它会询问你是否需要重新开始调试,选择y之后就可以重新从16行开始进行调试
  • 首先通过【display】记录一下两个变量的值和地址
  • 接着按【s】进入到swap函数里,追踪一下指针x和指针y的内容,也就是它们所存放的地址,就可以看到,函数内部已经接受到了这两个变量的地址
  • 然后对我们要观察的值变化继续做一个追踪
  • 并且在执行完第一个语句t = *x时,临时变量t中已经存放了变量a的值,也就是指针所指向的那块空间中的值
  • 接下去执行*x = *y,此时*x中的值就发生了变化,因为指针x可以直接找到变量a的地址,所以可以对其中的内容做修改,就变为了20
  • 接下去执行*y = t,同理,指针y可以直接找到变量b的地址,所以可以对其中的内容做修改,将原本保存在临时变量t中的10赋值给到*y,也就修改了其中的内容
  • 再按【n】的话这个swap函数就执行结束了,回到了main函数,就可以清楚地看到函数内部的修改带动了函数外部值的变化,真正地通过【传址调用】交换了两个数
  • 整体的调试结束!!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/23030.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

和平饭店短视频:成都科成博通文化传媒公司

和平饭店短视频:历史的沉淀与现代的演绎 随着短视频平台的兴起,越来越多的人开始通过镜头记录生活、分享故事。在众多短视频中,以“和平饭店”为主题的短视频独树一帜,以其独特的魅力吸引了大量观众的目光。成都科成博通文化传媒…

【常见报错】影刀小窗口消失-作者:【小可耐教你学影刀RPA】

现象描述: 影刀能够正常登录并运行,但是从常规模式切换到调度模式后能出现启动页,然后程序就退出了,查看影刀日志和事件查看器中的日志都没有任何异常消息 问题原因: 正常切换调度后会在窗口右下角出现一个机器人的小…

QT+FFmpeg+Windows开发环境搭建(加薪点)

01、Windows 环境搭建 FFMPEG官网:http://ffmpeg.org/ 02、下载4.2.1版本源码 源码:https://ffmpeg.org/releases/ffmpeg-4.2.1.tar.bz2 03、下载4.2.1编译好的文件 下载已经编译好的FFMPEG)(迅雷下载很快) 网址:https://ffmpeg.zeranoe.com/builds/ 32位下载地址:(迅雷…

特征工程及python实现

一、特征构建 概述 从原始数据中构建新的特征,一般需要根据业务分析,生成能更好体现业务特性的新特征,这些新特征要与目标关系紧密,能提升模型表现或更好地解释模型。 方法 时间周期:不同的时间切片长度&#xff0…

超实惠的GPU云服务器安利!!

自己一个人抱着老笔记本学深度学习,没有GPU是真的难受。Colab用过,GPU稍微用用就被剥夺了。华为云在培训的时候也用过,好贵。现在学到大模型,cuda10.1举步维艰。 失眠在网上冲浪,刷到了潞晨云,一块六就能用…

SL4010 40V耐压 300W大功率升压IC 12V5A大功率UPS电源专用

在当今这个信息高速发展的时代,电力稳定已成为企业运营和个人生活的核心需求。UPS(不间断电源)作为电力的守护者,其性能和质量直接关系到我们的工作和生活能否顺畅进行。今天,我们为您推荐一款高性能的UPS应急电源芯片…

K8s service 底层逻辑

文章目录 K8s service 底层逻辑Kube-proxy 代理模式Service 请求情况Service-Iptables 模式iptables 规则介绍ClusterIP 模式分析NodePort 模式分析 Service- IPVS 模式 服务发现环境变量CoreDNSCoreDNS 策略ClusterFirst(默认DNS策略)CluterFirstWithHo…

gcc编译器

预处理gcc -E b.c -o g.i -S -s -c -o gcc a.c -L acc.c指导路径 3 /

创新入门|营销中的视频内容:不可或缺的策略

视频在营销中日益重要。你是否也发现,视频内容最近似乎无处不在?它占据着社交媒体的推文、网站首页,甚至电子邮件中的位置。事实上,并不是你一个人有这样的感受。在过去十年中,视频作为一种营销手段日益成熟和强大。这是因为,人类天生就是视觉动物。我们大脑处理视觉信息的速度…

基于EasyX的贪吃蛇小游戏 - C语言

游戏基本功能演示: 1.主菜单界面 2.自定难度界面 在这里可以自行设定游戏的难度,包括蛇的移动速度,初始节数,以及默认模式,参考线(网格)。这些设定的数据都会在右上角的游戏属性栏中实时显示。…

图解Mysql索引原理

概述 是什么 索引像是一本书的目录列表,能根据目录快速的找到具体的书本内容,也就是加快了数据库的查询速度索引本质是一个数据结构索引是在存储引擎层,而不是服务器层实现的,所以,并没有统一的索引标准,…

[AI资讯·0605] GLM-4系列开源模型,OpenAI安全疑云,ARM推出终端计算子系统,猿辅导大模型备案……

AI资讯 1毛钱1百万token,写2遍红楼梦!国产大模型下一步还想卷什么?AI「末日」突然来临,公司同事集体变蠢!只因四大聊天机器人同时宕机OpenAI员工们开始反抗了!AI手机PC大爆发,Arm从软硬件到生态…

【Git】Git 的基本操作 -- 详解

一、创建 Git 本地仓库 要提前说的是,仓库是进行版本控制的一个文件目录。我们要想对文件进行版本控制,就必须先创建一个仓库出来。 创建⼀个 Git 本地仓库对应的命令为 git init ,注意命令要在文件目录下执行,例如:…

HCIP-Datacom-ARST自选题库_10_多种协议多选【24道题】

1.如图所示,PE1和PE2之间通过LoopbackO接口建立MP-BGP邻居关系,在配完成之后,发现CE1和CE2之间无法互相学习路由,下列哪些选项会造成该问题的出现? PE1或PE2未在BGP-VPNV4单播地址族视图使能邻居A PE1或PE2上的VPN实例参数配置错…

windows系统 flutter 开发环境配置

1、管理员运行powershell,安装:Chocolatey 工具,粘贴复制运行下列脚本: Chocolatey 官方安装文档 Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol [System.Net.ServicePointManage…

CSS函数:scale、scale3d函数的使用

CSS函数scale()主要是为了实现元素的放大和缩小效果,使用的是元素的变换效果。使用的是元素的转换属性:transform的,该函数可以实现指定X轴和Y轴的放大、缩小效果。除此之外,我们还可以通过如下两种方式实现指定方向的转换&#x…

[论文笔记]Mixtral of Experts

引言 今天带来大名鼎鼎的Mixtral of Experts的论文笔记,即Mixtral-8x7B。 作者提出了Mixtral 8x7B,一种稀疏专家混合(Sparse Mixture of Experts,SMoE)语言模型。Mixtral与Mistral 7B具有相同的架构,不同之处在于每个层由8个前馈…

SpringCache 缓存 - @Cacheable、@CacheEvict、@CachePut、@Caching、CacheConfig 以及优劣分析

目录 SpringCache 缓存 环境配置 1)依赖如下 2)配置文件 3)设置缓存的 value 序列化为 JSON 格式 4)EnableCaching 实战开发 Cacheable CacheEvict CachePut Caching CacheConfig SpringCache 的优势和劣势 读操作…

reduce过滤递归符合条件的数据

图片展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head><…

Python 实现乘数加密法

乘数加密是简单代替密码的一种。乘数加密法脱胎于凯撒加密法,加密和解密符号设计把他们转换成数字,加上或者减去密钥,然后把新的数字转换回符号,当我们把加减密钥变成乘以密钥,就是乘法加密法。有关凯撒加密法可以看之前的文章《Python实现凯撒加解密》。 加密过程 乘数加…