Linux中的gdb调试

2024-07-30 13:47:35 浏览数 (2)

1、背景

在Linux命令行中,我们还不知道怎么调试我们编写的代码。按照通常情况来说的话,Windows版本下我们编写代码有debug和release版本,那么Linux下也应该是有这两个版本的,那么我们该如何操作的呢? Linux中gcc/g 出来的二进制程序,默认是release模式。 所以我们需要在gcc/g 的过程中需要加上一些指令。

2、为什么会有Debug与Release版本的区别

Debug版本下通常是程序员用的,能够适合程序员进行程序的调试,而Release版本通常情况下都是发布出来给普通人使用的版本。正常情况下,给程序员使用的版本都会比较大一些,因为需要添加一些调试信息,能够保证调试的时候能够正常的运行。可是对于普通用户来说的话并不需要这些功能,这样的话也就导致,Release版本本身的大小就会比Debug版本小很多。用户只需要能够运行就行了,没必要去调试。 在这种情况之下,就会导致不得不产生两种状态,分别适合于不同的人去使用,一种方便调试,但是可能文件会大一点,一种方便运行,没有多余的信息,文件相对而言大小会少一点。

3、Linux命令语句界面下观察版本区别

代码语言:javascript复制
gcc/g   (文件) -g:让编译器在debug模式下编译

如何进行对比比较? 观察大小,因为debug版本下就是会新增一些信息。

果然见到了debug模式下,会大一点。并且要是运行的话,两个生成的文件都能够运行。 想要进一步的查看到底是不是有什么区别的话

代码语言:javascript复制
readelf -S (文件):查看文件的头部信息

这样就能够看到两者之间的真正的区别了。

debug版本存在这样的区域,而release没有这样的区域。这也就怪不得前面的比后面的文件大了。

4、使用gdb调试的命令

代码语言:javascript复制
gdb (需要调试的文件):gdb使用方法
//在gdb情况之下的命令
list:查看源文件(可简写为 l )
l n:l是list的缩写,n代表的是查看第几行
l (文件名):n :表示查看指定文件的第n行

上面的操作保证的是所输入的行代表的是,第n行能基本的显示在屏幕的中心位置,并不是说是从15行开始。 可是如果像上面那样操作的话,只能显示出10行,如果想要看到后续的行应该怎么操作呢?

代码语言:javascript复制
(Enter):按回车
代码语言:javascript复制
l (函数名):能够直接定位到函数定义的部分,展示文中的内容
其实想看到全文的内容也很简单,直接l 0,然后按回车键直到结尾就行

在Windows之下的vscode中,存在着F5,F9,F10,F11这样的快捷键,方便我们的调试。 那么在Linux中的gdb下,我们应该怎么运行呢? 首先确保的是,程序得先运行起来。所以在gdb下

代码语言:javascript复制
r/run:运行程序

可是直接运行的话就直接结束了,所以还要再run之前先打一个断点。

代码语言:javascript复制
b n:在第n行打断点
b (文件):n :在指定文件的第n行打断点
b (函数名):在函数内部第一行打上断点

那我们怎么能够看得出来在哪里打的断点呢? 在有图形化界面的时候能够看到头部的时候会有红点,那Linux下怎么看的出来断点在哪里呢?

代码语言:javascript复制
info b/i b:查询断点细节

那断点怎么取消呢?

代码语言:javascript复制
//错误示范
b (文件名):n(行号) :这种方法是错的。
//每个断点都有自己的编号
d n(断点的编号) :去除断点

删除之前的断点的话,继续重新设置断点的话,断点的序号会是线性增长的,不会重复使用。

打完断点之后,重新输入run之后,运行的时候会自动停到打断点的位置。当然了,我们也能够在不删除断点的条件下让断点失去作用。这样的话,算是让断点“失去能量”的效果。

代码语言:javascript复制
disable n:关闭n号断点的效果

如果运行过程中突然不想运行了,或者换句话说是想要重新运行的话,就需要再输入一遍run命令

再选择y,就能够实现重新运行调试。同样的,如果刚刚还没有重新开始的时候就跟随着文章让断点失去作用的话,现在也应该能够发现现在的断点没有停留在上次的地方,反而是继续向下进了几步。如果断点的位置是空行的话,不会执行停留,会到下一个断点的位置 如果想要打开原本“失去作用的断点”的话应该这样子做

代码语言:javascript复制
enable n:使能n号断点

那么逐过程和逐语句是怎么实现的呢? 逐过程:遇到函数语句的时候直接执行到最后返回,不会进入函数一行一行的实现。 逐语句:不同于逐过程,会进入到函数中一行一行的执行。 gdb会记住最新一次输入的指令,所以逐过程或者逐语句的时候能够直接一次过后就按回车就行。

代码语言:javascript复制
n(next):逐过程
s(step):逐语句

那么我们怎么在gdb的情况下查看变量的值呢?

代码语言:javascript复制
p (想要查询的变量的名称)

前面的$n的意思是代表总共查询了n次。 当然了,能够查看变量的值,也能够查看变量的地址

代码语言:javascript复制
p &(变量的名称)

还是不够,我们再vs里面查询数值之后就能够直接显示再下面,我们能不能再Linux的gdb也常显示再下方,不要一次一次的重新输入语句来查看变量值呢? 当然!能够实现变量的常显示

代码语言:javascript复制
display (变量名)

每一个变量面前都是有序列的,这是不是又是似曾相识啊!和原来的断点好像是很像啊,那到底有什么作用呢?下面就来介绍。 怎么取消常显示呢?

代码语言:javascript复制
//错误示范
undisplay (变量名)
//正确方法
undisplay n(序号名)

怎么实现F5的功能呢?就是实现断点间的过程跳跃呢?

代码语言:javascript复制
c (continue):实现断点间的跳跃运行
finish:直接执行完所在函数就停下来(逐函数运行)

如果写的一个函数里面有一个比较大的循环的话,我们进来运行几遍发现并没有什么问题,那我们进来了怎么出去呢?

代码语言:javascript复制
until (行):跳转到指定行(中间部分的代码都是运行了的)

额外的几个小点

代码语言:javascript复制
info locals/i locals:查看当前栈帧的变量
set var (变量名)=(数值):设置变量为指定的数值
bt:查看调用栈

5、命令总结

对于基础代码还是很方便使用的,但是到后期的时候,调试大代码的时候可能就是会有一些难以解决的问题。所以后期的时候,我们就会将Linux远程连接到我们本地的vscode就能够相对于是方便我们的使用。 那为什么我还会写这篇文章呢?那是因为即使是有图形化界面能够方便我们去进行一系列的操作,但是对于学习来说,我们还是需要去理解命令行的含义的,需要理解服务器的基本指令的。

0 人点赞