Linux - 还不懂 gdb 调试器?(调试软件)

前言

当前,我们可以使用 make/makefile 来程序化执行代码文件;可以使用 gcc/g++ 等编译器来编译代码;可以使用 vim 编辑器来编写代码;其实在 Linux 当中还有一个工具,可以实现调试工作,这个工具就是 -- gdb。

在了解调试器之前,你应该对代码的发布版本做一些了解:

我们在 VS 当中,在开始执行代码之前,可以选择以两种方式执行这个代码:debug & release :

一般在开发期间使用的都是 debug 模式,在编写好代码之后,如果我们的代码提交到远端,到客户手上的时候,比如在公司当中,用git提交到公司的 仓库当中,公司就可以以release 版本发布,同时,测试人员测试的模式也是 release 版本的。

debug 版本能调试 而 release 版本不能调试。而且,debug 版本代码文件要比 release 版本文件要大上不少。release 版本在执行效率上也要比 debug 要高。

那么出现上述几种区别的原因就是:debug 版本的代码,在形成可执行文件的时候,会生成调试信息,而 这个调试信息 是 release 版本没有的。

在 Linux 当中使用 gcc/g++ 编译器 编译可执行文件时候,默认是以 release 的方式进行发布 的。无法直接调试,如果要想以 dubug 方式发布,在使用 gc/g++ 编译的时候,需要带上**-g** 选项来进行编译。

在 下述博客的 进行了详细介绍,包括 如果查看 debug 文件等等:

Linux - 配置系统白名单 - gcc/g++_linux 白名单-CSDN博客

gdb 调试器

使用如下命令,就可以调试一个 可执行文件:

bash 复制代码
gdb 可执行文件名

如果,在使用上述命令之后,出现如下这个谈话框,并且没有任何报错的话,说明,当前你已经进入了 调试的 交互界面了:

如上所示,text 是一个可以调试的可执行程序,出现上述界面代表你已经成功进入到 调试界面了。

如果想退出的话,可以使用 q/quit

此时,我们还看不到代码,因为gdb 是以命令行的形式来进行 查看代码 和 调试代码的,不像 windows 当中 是使用图形化界面来实现,我们可以直接看到代码。

此时,你可以使用list/l来查看全部代码 :

你可以发现,我们上述是使用了两次命令(一次 list 一次 l),才查看到了全部的代码,其实 单独使用 list/l 不一定会从第一行显示全部的代码。 所以,我们的带上参数:

l/list 0 (0代表行数,可是代码当中任意行开始)就代表 从第 0 行开始显示:

上述都是只打印了 10 行,如果我们想显示全部代码的话,下面有一种方式:

当我们使用了 l/list 0 这个命令之后,其实 gdb 是会自动记录上一条指令的,当我们按下 回车 之后(前提是 使用了 l/list 0 这个命令之后 ) ,他就会认为我们此时想要继续执行 list/l命令,那么他就会继续显示代码(在上一次显示的最后一行的下一行开始):

而且**,最后还会提示,从共有多少行代码。**


还可以 使用下述命令,来查看 代码当中某一个函数的全部代码:

cpp 复制代码
list/l 函数名 

那么我们在调试的时候,肯定不只是 查看代码,而是要先找到问题所在,对于问题的所在,我们可以看报错位置,然后推测报错位置,然后使用条件断点,或者是在代码当中写入停止的代码语句,比如用 if 判断一下 ,当 程序走到哪一步的时候就停止,这种方法在 程序栈帧迭代较深的 代码当中尤其适用,比如 在 八数码问题当中,我们很有可能会遍历到很深的 状态矩阵当中(在八数码问题当中我们 不管使用 A* 还是sm 启发式算法,都会遍历出很多的 状态矩阵,这些状态矩阵就是 我们在挪动 其中方块,移动不同方块,和方块移动位置不同,都会产生不同的状态矩阵(也就是一种中间过程的情况)),关于八数码问题的介绍具体请看下述博客:八数码问题-c语言_八数码问题c语言代码_chihiro1122的博客-CSDN博客

之所以在上述举出这么多篇幅的例子,就是想说:调试最离不开的就是断点,不管是是在最开始的时候,比如在 VS 当中我们需要打上断点,然后按下 F5 程序就会直接运行到 断点处停止,然后我们进行 进步一调试;还有一种可能是在 调试阶段打上断点,在调试过程当中可能也会遇到程序运行比较麻烦的地方,也可以在调试过程当中打上断点来跳过这一步骤。

那么 gdb 作为一个好用的 调试器,他肯定也是支持断点的,那么接下来,将会对 gdb 当中打断点方式进行说明:


在 gdb 当中 运行程序,打断点

在 gdb 调试界面下,使用 r 命令就可以直接运行程序:

由于此时我们没有在程序当中打上断点,所以此时程序就直接运行到结束了。退出的时候也是正常退出的,就类似在 VS 当中的 F5/ shift F5 开始调试一样。

使用 在 gdb 调试窗口下,使用 b 行号 可以在当前调试文件当中的 指定行打上断点。此时我们在使用 r 命令既可以从程序运行,运行到 指定断点处 停下来了:

在 VS 当中如果我们在某一行打上了断点,是可以直接看到 这个红色的断点在哪一行存在的:

但是在 gdb 当中,这个断点我们是看不见的,就算我们 打完断点之后再去 使用 l 0 查看整个代码还是看不了断点:

其实使用 info b 就可以查看我们打上的所有所在断点行数了:

我们发现,在使用 info b 命令之后,出现的不只有 断点所在代码行数,还有一些其他信息,这些信息所代表的意思,如下所示:

我们发现,在gdb 当中的断点是有 编号的当我们像删除某一个断点的时候,不能像之前一样使用 行号来删除断点,而是应该使用 断点的编号来删除断点 。在 gdb 当中我们可以使用 d 断点编号

来删除某一个结点:

而且,需要注意的是,我们设置的断点这些信息,都是在当前gdb 运行进程之内使用的,也就是说,我们在当前 gdb 调试窗口下设置的各个调试信息,如果退出一个 gdb 然后在进去 gdb 调试的话,尽管是同一个文件,在上一次 gdb 进程当中保存的 调试信息都会删除。

在gbd 当中进行 逐语句 逐过程 调试

在 VS 当中有两种 逐语句的方式 调试,一种是 F10 逐过程,另一种是 F11 逐语句。

逐语句好理解,逐过程其实就是跳过一个过程,一个函数可以被称为一个过程。

使用 n/next 命令就可以进行 逐过程调试

当我们进行调试运行代码之后,在断点信息当中还有多出一个信息:断点被命中的次数

像上述两个断点,被命中的次数都是 1。

使用s 命令 进行逐语句调试

gdb 当中的监视窗口

在 VS 当中的监视窗口也是必不可少的,监视可以极大的方便我们查看某变量当前是否合法,或则可以查看很多很多的信息,具体要看自己怎么使用调试:

在gdb 当中也肯定不能缺少 调试窗口,但是因为 gdb 不是图形化界面,所以要 手动输入某个变量,来让 gdb 知道你当前想要查看哪一个变量的值。

我们使用 p 变量名/变量的某些变形之后的值 这个命令就可以查看 这个变量的值,或者是这个变量变形之后的值了。

此时我们就知道了,a 变量的值 在当前程序执行状态下 就是 10。

和VS 当中的调试窗口一样,我们还可以通过调试窗口,查看到 a 的地址等等变形信息:

但是,你有没有发现上述的监视太挫了,VS 当中还可以一遍进行 逐步调试,一般查看 变量的值,而上述 的 p 还有一个一个打出来。

其实 gdb 当中也是有 常显示 监视窗口命令的:display 变量名/变量的某些变形之后的值,这样的话,输入的变量 就会一直跟着你调试一起 走:

如果不想 常显示变量值 ,可以使用undisplay 命令 ,但是这个命令不能再后面直接加 变量名等等信息来删除掉 该变量信息的 监视信息

可以发现,是不行的。

需要注意的是:在常显示的 变量信息 当中,每一个信息是有自己的编号的,和上述 删除断点一样,需要按照编号来进行删除,也就是 使用 undisplay 常显示变量信息编号 删除某一个常显示信息:

可以发现此时就删除成功了。

对于 常显示信息编号,就是显示信息的最左侧数字

until 跳转指令 - finish 结束当前函数执行指令

假设我们现在在一个函数的循环体当中,现在已经陷入了这个循环体,但是这个我们又想跳出当前这个循环体 ,查看这个循环体结束之后,修改的内容,此时我们就可以使用 until 指定行 来跳转到某一行。

像上述我们使用 until 跳转出函数的循环体的时候,需要查看我们想要跳转到那一行,如果当前只是想要 跳出这个函数的话,也就是只是把当前函数执行完毕,然后查看这个函数的执行结果,那么我们可以在函数当中运行时,使用 finish 指令来结束当前函数的执行

finish 的使用场景,举个例子,比如当前写的代码崩掉了,但是在主函数当中有 很多个函数需要我们去判断,此时我们要想知道是哪一个函数当中导致代码奔溃的话,就可以执行具体函数当中,使用 finish 来执行函数体,看看是那个函数导致程序奔溃的。

continue 跳到下一个断点

VS 当中你肯定使用 F5 来跳到下一个断点处,在gdb 当中使用 countinue 也能达到 直接从当前位置跳到下一个断点的功能。

修改断点的 Enb 值

VS 当中右键 断点可以选择禁用断点,或者是启用断点,同样的 在gdb 当中有 Enb 值,这个值只有两个值,y or n ,也就代表着这个断点是否被启用。

使用 disable 断点编号 就可以修改 Enb 值:

此时我们 r 运行程序,直接就运行到 第三个断点处 了,第一第二个断点已经被跳过 了(上述是21 行是因为 20 行断点处为空行,gdb 自动跳过 了

gdb 命令总结

gdb 当中还有很多命令,像 b 命令打断点,可以用 b 文件名:行号 给指定可执行文件的行号位置处打上断点。

b 函数名 这种方式打出的断点,本质是就是在函数体的起始位置处,也就是函数体的第一行代码当中打上断点:

总结:

  • list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
  • list/l 函数名:列出某个函数的源代码。
  • r或run:运行程序。
  • n 或 next:单条执行。
  • s或step:进入函数调用
  • break(b) 行号:在某一行设置断点
  • break 函数名:在某个函数开头设置断点
  • info break :查看断点信息。
  • finish:执行到当前函数返回,然后挺下来等待命令
  • print(p):打印表达式的值,通过表达式可以修改变量的值或者调用函数
  • p 变量:打印变量值。
  • set var:修改变量的值
  • continue(或c):从当前位置开始连续而非单步执行程序
  • run(或r):从开始连续而非单步执行程序
  • delete breakpoints:删除所有断点
  • delete breakpoints n:删除序号为n的断点
  • disable breakpoints:禁用断点
  • enable breakpoints:启用断点
  • info(或i) breakpoints:参看当前设置了哪些断点
  • display 变量名:跟踪查看一个变量,每次停下来都显示它的值
  • undisplay:取消对先前设置的那些变量的跟踪
  • until X行号:跳至X行
  • breaktrace(或bt):查看各级函数调用及参数
  • info(i) locals:查看当前栈帧局部变量的值(相当于查看 VS 当中本地变量这个对话框)
  • quit:退出gdb
相关推荐
和煦的春风37 分钟前
性能案例分析 | Waiting for GPU completion
android·linux
道路与代码之旅1 小时前
Delphi - IndyHttpServer接收上传文件
运维·服务器
lybugproducer2 小时前
深入 Linux 文件系统:从数据存储到万物皆文件
linux
烦躁的大鼻嘎2 小时前
【Linux】深入Linux多线程架构与高性能编程
linux·运维·服务器·开发语言·c++·ubuntu
羚羊角uou2 小时前
【Linux】system V共享内存
linux·运维·服务器
林克爱塞尔达2 小时前
Linux入门(二)
linux·运维·chrome
破烂儿2 小时前
Ubuntu Server 安装图形界面和通过Window远程桌面连接服务器(Xrdp)
linux·服务器·ubuntu
Hello.Reader2 小时前
Kafka 运维实战基本操作含命令与最佳实践
运维·kafka·linq
存储服务专家StorageExpert2 小时前
手搓一个 DELL EMC Unity存储系统健康检查清单
linux·运维·服务器·存储维护·emc存储
笑口常开xpr3 小时前
Linux 库开发入门:静态库与动态库的 2 种构建方式 + 5 个编译差异 + 3 个加载技巧,新手速看
linux·c语言·动态库·静态库