Linux工具学习之【gdb】

简介: vim 可以编写代码,gcc/g++ 可以编译代码,此时只最后一件神器,就能进行完整的开发工作,那就是通过 gdb 调试代码,毕竟谁都不敢保证自己的代码没有问题,所以就有调试器这种东西帮助我们定位问题,进而解决问题

✨个人主页: Yohifo

🎉所属专栏: Linux学习之旅

🎊每篇一句: 图片来源

🎃操作环境: CentOS 7.6 阿里云远程服务器


Whatever is worth doing is worth doing well.


任何值得去做的事情,都值得把它做好。

7e6edbddd0cf19a8a76ea65387537a8.png



📘前言


vim 可以编写代码,gcc/g++ 可以编译代码,此时只最后一件神器,就能进行完整的开发工作,那就是通过 gdb 调试代码,毕竟谁都不敢保证自己的代码没有问题,所以就有调试器这种东西帮助我们定位问题,进而解决问题

dd2fdf7531d4bf2be29075bc65b6599.png



📘正文


现在让我们一起进入 gdb 的世界,体验纯命令行调试代码的妙处

注意: 需要提前下载好 gdb


$ sudo yum install -y gdb


📖生成可调试文件


可能有的同学一安装好 gdb 就迫不及待地开始了调试,通过 gdb 最终生成文件 进入 gdb 后,会发现什么指令都用不了,除了 q 退出 gdb 和 r 运行程序


原因很简单:gcc/g++ 默认生成的程序为 realse 发行版,也就是说不含调试信息,所以我们首先要解决这个问题

dcef63bbb6fa60bf9cba8a798ea2b0c.png


📃realse 与 debug


程序分为 realse 与 debug 两个版本,其中前者是给测试工程师找毛病的,而后者则是我们开发使用的版本,debug 内置很多调试信息,因此它能很好的进行调试


而 gcc/g++ 默认不会生成 debug 版的可执行程序,我们可以通过指令来搜索默认生成的程序中是否含有调试信息


$ readelf -S myfile | grep -i debug //在默认生成的可执行程序 myfile 中查找调试信息

b3b7675078d224b6d818302108460c0.png

想要解决问题也很简单:在编译时,指定编译器生成 debug 版的程序就行了


注意:因为已经学习了 Makefile ,我们直接在文件中更改就行了


//Makefile 文件中
$ gcc test.c -o myfile -g -std=c99
//注意:其中 -g 就是指定其生成 debug 版的程序;-std=c99 是让其支持C99标准

9095dc40c70d9487f1ca6e3b6a67b7f.png

我们先通过 make clean 指令清理原来的解决方案,然后再通过 make myfile 指令编译程序

得到可执行程序后,用同样的方法对其进行查找

6a5512a3ec76f68b3c60389163c4270.png

接下来就可以愉快的进入 gdb 进行调试了


📖调试打开与关闭


首先要学习如何打开和关闭 gdb


📃启动调试


我们调试的对象是已经生成的可执行程序,并非最开始的源文件

这很好理解,因为在VS中也是先编译、再调试


通过 Makefile 的自动化任务生成 myfile 可执行程序

然后通过指令 gdb myfile 即可进入调试

$ gdb myfile  //进入 gdb 调试

212e8dc79c548288d762db9f6eff1f0.png

注意: 调试的是最终生成的可执行程序;要确保生成的程序为 debug 版,不然后续无法调试


📃l 查看代码


只要进入了 gdb ,我们可以通过 l 指令随时随地查看我们的代码,且查看代码时不会干扰其他调试命令


l 命令一般是配合数字进行查看,每次只可查看十行,如 l 1 就表示从代码第一行开始查看其前后十行,按回车后可接着往下展示,直到代码展示完毕


(gdb) l 1 //从代码第一行开始查看其前后十行
(gdb) l //默认查看代码最中间的十行内容

1aae6c8ccc6d53c9538dd7d21237a68.png


注意: 经过测试发现,l 的查看策略是每次展示十行,然后想要查看的第n行位于中间,l 1 能直接能从第一行开始的原因是前面已经没有代码了,因此如果默认只输入 l 就会展示当前代码的最中间位置前后十行


📃退出调试


gdb 退出不像 vim 那样麻烦,指令 q 就表示退出 gdb 调试

(gdb) q //退出 gdb 调试

0d20bc6627976c67b3378ffb9223034.png

📖运行与断点


调试最重要的目的是帮助我们快速定位到问题,然后分析解决,此时断点就显得很重要了,如果没有断点,那只能一步步的调试,效率很低,下面就来看看如何让程序在 gdb 中跑起来及断点相关操作


📃r 运行程序


gdb 中能直接快速运行程序,假设没有断点,那么程序会直接运行出结果


(gdb) r //运行程序

eb2e5c418169aae69e3827118c8cb94.png


其实此时可以直接把这个看作VS中的黑框框,r 就相当于 F5 ,在没有断点的情况下,程序会直接出结果的,而最终的结果值也会紧跟着输出


📃b 断点操作


断点在 gdb 中意为 breakpoint ,其中首字母 b 就表示断点的意思,因为是纯命令行操作,所以刚开始调试麻烦点是必然的


🖋️设置断点


指令 b 需要配合行号或函数名进行断点设置

(gdb) b 行号  //在指定行号打断点
(gdb) b 函数名 //在指定函数处打断点

629163330c532ea82b1f9dedea340c2.png


注意: 纯命令打的断点不如图形化界面直观,但我们也可以通过指令查看断点信息


🖋️查看断点信息


指令 info b 可以搜索所有断点,并展示其详细信息


(info) b  //查看所有断点信息

10734ae61a79dead2a4954eb0f3c1578.png


🖋️编号含义


查看断点信息时,会发现有一栏 num ,这表示每个断点的编号,因为我们不能直接对断点进行区分,于是就需要引入编号这个概念,这个概念在 gdb 很多地方都有体现


注意: 除非 gdb 关闭,否则它的编号是一直累计的,比如我们把断点1、2都删了,然后再新打一个断点,断点编号就为3


🖋️取消断点


有时候想取消断点,就可以通过 d 断点编号,取消指定断点


(gdb) d 断点编号  //由此可见断点编号的重要性

c11b565124d2a03c69a5c2fddb5ad01.png

有了断点之后,我们就可以配合 r 指令,运行至断点处

b9499f6c6357db4f2c3c1249838eee7.png

注意: 不同于VS中的 F5,r 指令要么运行至最近一个断点处,要么将程序运行完,也就是说,r 是无法实现两个断点间移动的,再次按 r 会提示是否重新运行程序


📖单行与单步


调试这个东西总得一步一步来,不然问题就不好找到了


📃n 单行调试


单行调试即逐过程调试,对应着VS中的 F10,即遇到函数不会进入,指令为 n


(gdb) n //单行调试,不会进入函数内部

0ad6c8ff3fb40408fc5a75ef748f87c.png

单行:一行一行的来,每次运行完一行内容即可


📃s 单步调试


单步调试对应着VS中的 F11 ,不同于单行调试,单步调试能进入函数内部,指令为 s


(gdb) s //单步运行,会进入函数内部

a5bdb3786327334f3bfe2608ec29fd5.png


单步:即一步一步的来,如果遇到函数,就会进入函数内部,确保程序的每一步都被执行


📖查看变量


调试过程中还有一个很重要的工作:查看变量信息,如VS中的监视窗口,假设没有监视功能,那么我们可能连变量的变化情况都无法捕捉到,庆幸的是 gdb 支持监视功能


📃bt 查看调用堆栈


程序运行时,会先为 main 函数建立栈帧,然后运行程序,如果遇到函数,就会为函数建立栈帧,执行函数,因此程序的运行本质上就是栈帧的创建与销毁


我们可以通过指令 bt 查看当前程序的堆栈调用情况


(gdb) bt  //查看调用堆栈情况


0fde465eea379e05614205fd4c0a567.png


📃p 临时查看变量


指令 p 变量 可以查看指定变量的信息


(gdb) p 变量  //查看变量的信息

284ce3108657b20941c932641f89235.png


注意: 指令 p 只能做到临时监视,当执行下一条指令后,原来监视的变量就看不到了;可以看出,p 监视出的值也是有编号的,每调用一次指令,编号就会累加一次


📃display 常显示变量


gdb 当然也支持一直监视变量,使用指令 display 即可


(gdb) display 变量  //常显示变量信息,不会随着指令的执行而消失

718b36581e96bc8d794c040ed51f6c7.png


注意: 如果我们忘记了程序中有哪些变量,可以随时随地通过 l 指令查看,像这种查看式的指令,是不会影响其他指令运行的;不难发现,常显示的变量也有属于自己的编号,这个编号运行机制跟断点的一样,只要 gdb 不退出,它是会一直累加的


编号存在的主要意义就是方便我们进行监视变量删除

(gdb) undisplay 变量编号  //取消监视指定变量


📖快速跳转


gdb 提供了一些快速跳转的指令,赋予了我们在不打断点的情况下进行跳转的权力(注:先要打断点将程序运行起来),这是VS做不到的


📃until 指定行


程序运行后,我们可以直接通过 until 行号 的方式跳转至指定行,这个指令通常用来跳过循环


(gdb) until 行号  //跳转至指定行



58bf771ac4187faa316e7a3ba5fafeb.png

📃finish 函数


这个指令主要是针对函数的,直接 finish 就可以在不打断点的情况下,跑完当前函数


(gdb) finish  //在不打断点的情况下跑完当前函数


2d8c7ac51888b3f4c141731c2df8cf7.png


📃c 断点


这个指令就是针对断点的了,前面说过 r 无法实现两个断点间的跳转,因此有一个专门的命令 c 进行断点跳转(注:依然需要先通过 r 指令把程序跑起来)


(gdb) c //进行断点间的跳转

7e93a5981bd6a78c60e3222603463fe.png



📖其他命令


接下来再列举一些其他命令


📃disable 断点使能


使能 的意思就是开关,比如电灯的开与关,我们的断点也能设置开关状态,在不取消断点的情况下让断点失效

(gdb) disable 断点编号  //关闭断点

9cf8264d5db48005d539074911ee05d.png

能关闭当然也能打开


(gdb) enable 断点编号 //打开断点


6a215ec794d110e6ce7e82adbb25c0f.png


📃set var 设置条件


给变量设置条件,使程序运行至设定值那一步,比如 set var i=5 后,程序就运行至 i=5 的那一步了


(gdb) set var 变量值 //设置变量值

29d8d6260c59eb73a8a9433ad327163.png

这个功能就像VS中的给断点设置条件,然后跳转


📃ptype 查看变量类型


本文只是介绍了部分常用指令,关于 gdb 还有很多很多指令,一时半会是学不完的,感兴趣的同学可以去这篇文章里看看《GDB使用详解》

a7c9e60d083277b4bfa795b495d8540.png

📘总结


以上就是关于Linux工具:gdb 的全部介绍了,gdb 是一款功能丰富的调试器,它赋予了我们在纯命令行环境下调试代码的能力,虽然它的使用门槛高,但用熟后就会很顺手,配合我们之前学习过的 vim、gcc ,能做到像VS那样的开发环境,让我们的 Linux 使用场景更加丰富


如果你觉得本文写的还不错的话,期待留下一个小小的赞👍,你的支持是我分享的最大动力!


如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正


相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
10天前
|
人工智能 监控 Shell
常用的 55 个 Linux Shell 脚本(包括基础案例、文件操作、实用工具、图形化、sed、gawk)
这篇文章提供了55个常用的Linux Shell脚本实例,涵盖基础案例、文件操作、实用工具、图形化界面及sed、gawk的使用。
27 2
|
2月前
|
Linux 开发工具
Linux查看已经安装软件的版本,安装软件的路径,以及dpkg、aptitude、apt-get、apt工具的使用
Linux查看已经安装软件的版本,安装软件的路径,以及dpkg、aptitude、apt-get、apt工具的使用
33 2
Linux查看已经安装软件的版本,安装软件的路径,以及dpkg、aptitude、apt-get、apt工具的使用
|
1月前
|
监控 安全 Linux
如何利用Kali Linux进行网站渗透测试:最常用工具详解
如何利用Kali Linux进行网站渗透测试:最常用工具详解
70 6
|
10天前
|
Linux
linux之centos安装dataease数据报表工具
linux之centos安装dataease数据报表工具
|
1月前
|
安全 Linux 测试技术
Kali Linux预装的自动化渗透测试工具
Kali Linux预装的自动化渗透测试工具
43 2
|
2月前
|
存储 缓存 监控
Linux性能分析工具-perf并生成火焰图
Linux性能分析工具-perf并生成火焰图
|
2月前
|
NoSQL Linux 编译器
内核实验(一):使用QEMU+GDB断点调试Linux内核代码
如何配置环境并使用QEMU虚拟机结合GDB进行Linux内核代码的断点调试,包括安装QEMU、交叉编译工具链,编译内核以及通过GDB远程连接进行调试的详细步骤。
42 0
内核实验(一):使用QEMU+GDB断点调试Linux内核代码
|
1月前
|
Linux
使用qemu来学习Linux的休眠和唤醒
使用qemu来学习Linux的休眠和唤醒
|
1月前
|
Linux
linux内核原子操作学习
linux内核原子操作学习
|
1月前
|
Ubuntu Linux
用crash工具学习Linux内核 —— 查看cgroup_roots
用crash工具学习Linux内核 —— 查看cgroup_roots
下一篇
无影云桌面