【Linux】Linux工具——gdb

news2024/11/20 3:20:50

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.coloradmin.cn/o/1791594.html

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

相关文章

创新“智”领长江经济带高质量发展研讨会调研实在智能

近日,创新“智”领长江经济带高质量发展研讨会暨央企智库沙龙第46期在浙江杭州顺利召开。 会议由中国联通主办,中国联通研究院、浙江联通、浙江省人民政府国有资产监督管理委员会联合承办,长江经济带沿线中央企业、地方国资国企等60余家单位…

SLAM精度评估—evo

evo是一款用于SLAM轨迹精度的评估工具。核心功能是(1)能够绘制(传感器运动)轨迹,(2)评估估计轨迹与真值(ground truth)的误差。evo支持多种数据集的轨迹格式(TUM、KITT、…

eNSP学习——连接RIP与OSPF网络、默认路由

目录 相关主要命令 实验一、连接RIP与OSPF网络 原理概述 实验目的 实验内容 实验拓扑 实验编址 实验步骤 1、基本配置 2、搭建RIP和OSPF网络 3、配置双向路由引入 4、手工配置引入时的开销值 实验二、使用OSPF、RIP发布默认路由 原理介绍 实验目的 实验内容 实…

认识微服务,认识Spring Cloud

1. 介绍 本博客探讨的内容如下所示 什么是微服务?什么是springcloud?微服务和springcloud有什么关系? 首先,没有在接触springcloud之前,我写的项目都是单体结构, 但随着网站的用户量越来越大,…

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

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

【Unity每日一记】效应器你应该知道是什么吧!五大2D效应器组件

👨‍💻个人主页:元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏:uni…

企业im即时通讯WorkPlus私有化部署适配国产信创环境

在信息化时代,高效的沟通和协作对于企业的运营至关重要。企业IM即时通讯平台提供了一种便捷、实时的沟通工具,旨在改善企业的内部和外部沟通效率。然而,随着企业对数据安全性和隐私保护的要求不断提高,许多企业开始选择私有化部署…

GPT-4o:人工智能技术的新里程碑

在人工智能领域,技术的不断演进为我们带来了许多惊喜。最近,GPT-4o横空出世,成为了人工智能技术的新里程碑。在这篇博客中,我们将对GPT-4o进行评价,并进行版本间的对比分析,探讨其技术能力以及个人整体感受…

04--Tomcat

前言:本章整理tomcat的知识点,tomcat知识点相较nginx比较少,但是也是运维必会的软件,这里结合实际项目整理一下。 1、tomcat简介 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器&#x…

Noisee AI中文站网页版 AI 音乐生成视频全新登场,快来抢先体验——国内第一个登场的中文站来袭 - 516篇

导读 Noisee AI是一个AI音乐转视频工具,可以将你喜欢的旋律转化为音乐视频。用户可以通过Noisee AI的官方网站或提供的链接加入其Discord服务器,并上传音频文件。Noisee AI支持来自Suno、YouTube、Soundcloud的链接,以及直接上传的MP3文件。…

运放应用1 - 反相放大电路

1.前置知识 反相放大电路存在 负反馈电路 ,工作在线性区,可以利用 虚短 概念来分析电路。 注:运放的 虚断 特性是一直存在的,虚短特性则需要运放工作在 线性区 有关运放的基础知识,可以参考我的另外一篇文章&#xff…

1103. 分糖果 II Rust等差求和+一元二次方程求根(击败100% Rust用户)

题目内容 排排坐,分糖果。 我们买了一些糖果 candies,打算把它们分给排好队的 n num_people 个小朋友。 给第一个小朋友 1 颗糖果,第二个小朋友 2 颗,依此类推,直到给最后一个小朋友 n 颗糖果。 然后,…

经典的泡泡龙游戏源码免费下载

源码介绍 HTML5泡泡龙冒险小游戏是一款休闲网页游戏,游戏玩法是玩家从下方中央的弹珠发射台射出彩珠,多于3个同色珠相连则会消失。 源码下载 经典的泡泡龙游戏源码免费下载

多目标优化-NSGA-II

文章目录 一、前置知识NSGA-II帕累托前沿 二、算法流程1.NSGA2.NSGA-II 一、前置知识 1.NSGA(非支配排序遗传算法):旨在同时优化多个冲突的目标函数,寻找帕累托前沿上的解集。 什么是多个冲突的目标: 比如你看上了一辆车,你既想要它便宜,又…

免费开源图片转文字识别软件:Umi-OCR

目录 1.介绍 2.项目亮点 3.项目功能(已实现) 4.功能体验 5.项目集成(调用接口) 6.项目地址 1.介绍 Umi-OCR:免费,开源,可批量的离线OCR软件,目前适用于 Windows7 x64 及以上。…

React@16.x(20)渲染流程-首次渲染

目录 1,渲染的前置知识点1.1,React 元素1.2,React 节点1.3,节点类型1.4,真实DOM 2,首次渲染2.1,根据参数创建节点2.2,不同节点,有不同处理2.3,生成虚拟DOM树2…

Ollama+FastAPI+React手把手构建自己的本地大模型,支持SSE

最近大家都在玩LLM,我也凑了热闹,简单实现了一个本地LLM应用,分享给大家,百分百可以用哦~^ - ^ 先介绍下我使用的三种工具: Ollama:一个免费的开源框架,可以让大模型很容易的运行在…

JVMの垃圾回收

在上一篇中,介绍了JVM组件中的运行时数据区域,这一篇主要介绍垃圾回收器 JVM架构图: 1、垃圾回收概述 在第一篇中介绍JVM特点时,有提到过内存管理,即Java语言相对于C,C进行的优化,可以在适当的…

【AI大模型】Transformers大模型库(三):特殊标记(special tokens)

目录​​​​​​​ 一、引言 二、特殊标记(special tokens) 2.1 概述 2.2 主要功能 2.3 代码示例 三、总结 一、引言 这里的Transformers指的是huggingface开发的大模型库,为huggingface上数以万计的预训练大模型提供预测、训练等服…

设计模式之过滤器模式FilterPattern(十)

一、过滤器模式 过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模…