目录
- 一、什么是gdb?
- [二、gdb 的使用](#二、gdb 的使用)
-
- [2.1 启动 gdb](#2.1 启动 gdb)
- [2.2 常见命令的使用](#2.2 常见命令的使用)
-
- [2.2.1 list / l 命令](#2.2.1 list / l 命令)
- [2.2.2 run / r 命令](#2.2.2 run / r 命令)
- [2.2.3 break / b 命令](#2.2.3 break / b 命令)
- [2.2.4 info 和 delete / d 命令](#2.2.4 info 和 delete / d 命令)
- [2.2.5 逐过程 next / n 和 逐语句 step / s](#2.2.5 逐过程 next / n 和 逐语句 step / s)
- [2.2.6 point / p 和 display 和 undisplay](#2.2.6 point / p 和 display 和 undisplay)
- [2.2.7 until 和 finish 命令](#2.2.7 until 和 finish 命令)
- [2.2.7 continue / c 命令](#2.2.7 continue / c 命令)
- [2.2.8 disable 和 undisable](#2.2.8 disable 和 undisable)
- [2.2.9 backtrace / bt 命令](#2.2.9 backtrace / bt 命令)
- 三、调试的常见技巧
-
- [3.1 watch](#3.1 watch)
- [3.2 set var](#3.2 set var)
- [3.3 条件断点](#3.3 条件断点)
-
- [3.3.1 添加条件断点](#3.3.1 添加条件断点)
- [3.3.2 在已有断点基础上修改其为条件断点](#3.3.2 在已有断点基础上修改其为条件断点)
- 四、调试的本质

个人主页:矢望
一、什么是gdb?
它是 Linux 系统下最强大、最核心的命令行调试工具。gdb 和其它命令一样就是一个普通的命令。

gdb 在大多数 Linux 发行版中通常需要手动安装sudo yum install gdb。
当执行gdb --version时出现以下内容证明已安装。

当你启动gdb时会进入它的交互界面,输入quit / Ctrl + d就可以退出。

二、gdb 的使用
现在准备了一份从1~100求和的程序code.c。和与之匹配的Makefile。

Makefile:

2.1 启动 gdb
当我们make编译形成可执行程序code,再进行gdb code时,它会有这样的信息说明:

上面说 code 没有包含调试信息,所以 gdb 无法显示源代码、变量名等信息。这是为什么呢?
程序状态分为两种模式,分别是 Debug 和 Release,Debug版本包含调试信息,是程序员在开发期间所处的模式,而release版本是给用户提供的,它的体积小,不包含调试信息,运行速度最快。
这和上面有什么联系呢?当然有,上面图片的信息说明我们的可执行程序是release版本,这是因为gcc/g++编译代码,默认模式是release模式。
如何证明它是release版本的呢?可执行程序不仅仅是二进制的集合,它的内部是有固定的格式的,这个固定格式叫做ELF。

而readelf -S code可以读取它内部的格式信息的细节,我们从中过滤一下debug调试信息。

从上图的结果,就可以知道,code内部没有调试信息,它就是release版本的。
那么如何形成debug版本的呢?很简单,在gcc/g++编译时加上-g选项。

从上图中可执行程序文件大小也可以看到,带有调试信息的会更大。以下是调试信息:

所以一般在开发时,我们都会把-g选项带上。
2.2 常见命令的使用
2.2.1 list / l 命令
l无参数作用:显示源代码,从上次位置开始,每次列出10行 。

l 文件名:行号作用:显示指定行号附近的代码 。当只有一个文件时,文件名可省略。

l 函数名作用:显示指定函数的源代码 。

l 开始行,结束行作用:显示指定行号范围的代码 。

注意:以上执行后按回车都会继续显示后面的代码,直到显示结束。
2.2.2 run / r 命令
作用:从程序开始连续执行 。

2.2.3 break / b 命令
b 行号作用: 在指定行设置断点 。

如上图,打完断点,此时运行,它就会在断点处停下来。
由上图我们可以发现gdb很不直观,这里推荐使用cgdb,CGDB 是一个基于 GDB 的增强版调试器,它提供了分屏界面 - 上方显示源代码,下方是 GDB 命令窗口,用户体验比纯命令行 GDB 好很多,安装命令sudo yum install cgdb。

此时再次打断点就可以在上面的源代码区域找到。
注意:上方是源代码窗口,下方是gdb窗口。如何退出:1、按 Esc 键切换到源代码窗口,然后输入 :q 并按回车。2、按 i 键切换到 GDB 命令窗口,然后输入 quit / Ctrl+d。
如果你不小心在cgdb交互界面触碰了鼠标的滑轮,导致再按按键cgdb界面没了反应,这是因为可能触碰了cgdb的模式切换,按一下i就重新进入了cgdb命令窗口。
2.2.4 info 和 delete / d 命令
info break/b:查看当前所有断点的信息 。
delete/d n:删除序号为n的断点 。

从上图中,我们可以看出当创建断点并删除之后,再次创建断点,断点序号就不再从1开始了,在一次调试过程中它是一个递增的序列。
2.2.5 逐过程 next / n 和 逐语句 step / s
next/n:逐过程,执行下一行代码,不进入函数内部,对标F10 。

step/s:逐语句,执行下一行代码,会进入函数内部,对标F11 。

注意:当执行完n或者s命令后你还想要执行下一行命令,可以继续输入n或者s,此外gdb会自动保存上一次执行的命令,此时你按回车也可以达到想要的效果。
2.2.6 point / p 和 display 和 undisplay
我们在Windows下进行调试代码时,是可以在搜索框查看变量的值的呀,cgdb也一样可以。
p 表达式:打印表达式的值。p 变量:打印指定变量的值。

但我们要是每一步都想查看怎么办,这还要每一步都自己敲吗?
可以使用display,display 变量名:跟踪显示指定变量的值 。

undisplay 编号:取消对指定编号变量的跟踪显示 。

2.2.7 until 和 finish 命令
until 行号:执行到指定行号 。它解决了这样的痛点:当你在循环内部单步调试时,不想一步步执行几十次甚至几百次循环迭代。

finish:执行完当前函数返回然后停止 。假设你的程序运行过程中发生了报错,你想看看是不是这个函数的程序执行引起的,此时你就可以进入到这个函数的内部并finish。

如上图,就直接执行结束了finish函数。
2.2.7 continue / c 命令
continue/c 的作用是:让暂停的程序继续运行,直到遇到下一个断点、程序结束或发生异常。

2.2.8 disable 和 undisable
disable:临时禁用断点(断点保留但不会触发)。
enable:重新启用被禁用的断点。
cpp
disable/enable 2-5 //禁用/启用2到5号断点
disable breakpoints //禁用所有断点
enable breakpoints //启用所有被禁用的断点
disable:

enable:

2.2.9 backtrace / bt 命令
bt 命令显示程序当前暂停时刻的函数调用链 ,告诉你:当前执行到哪个函数,这个函数是被谁调用的,调用路径是怎样的(从 main 开始的完整轨迹)。

三、调试的常见技巧
3.1 watch
执行时监视一个表达式(如变量)的值。如果监视的表达式在程序运行期间的值发生变化,GDB 会暂停程序的执行,并通知使用者。
例如我要在Sum函数内部监视result的值:

如果你认为有一些变量不应该修改,或者你怀疑它修改导致了问题,你可以watch它,如果变化了,就会通知你。
3.2 set var
set var 允许你在程序暂停时动态修改变量的值。
假设我在进行求和的时候,i初始值不是从1开始的,我们的start初始化时是-10,并且我们还不知道。

如上图,我们在调试过程中发现i的初始值不正确,我们之前的做法是退出cgdb,并且修改源代码,但在某些场景下,我们并不知道这次的修改是不是让程序正确。
现在有了set var我们可以暂时看看修改后的运行结果。我们可以看看i初始为1的结果。

如上图,我们可以确认问题就出在i的初始值上,此时就可以退出cgdb,并修改源代码了。
3.3 条件断点
3.3.1 添加条件断点
cpp
//在第 9 行的地方新增断点
//并且满足特殊条件i == 50才会被触发
b 9 if i == 50

3.3.2 在已有断点基础上修改其为条件断点
condition 命令是 GDB 中用于为断点添加条件的工具。
cpp
condition 2 i == 50
// 2 是已有断点的编号
// i == 50,是给已有断点添加的条件

四、调试的本质
调试的本质是找到问题 ,这是gdb的核心价值,至于发现问题 和分析问题 都是人的工作。gdb给我们提供的主要作用是找到问题,辅助作用是帮助我们分析问题,它提供辅助数据。
GDB 放大了开发者的调试能力,但无法替代开发者的思考过程。 这就是为什么说"工具再好,也要看谁在用"。
总结:
以上就是本期博客分享的全部内容啦!如果觉得文章还不错的话可以三连支持一下,你的支持就是我前进最大的动力!
技术的探索永无止境! 道阻且长,行则将至!后续我会给大家带来更多优质博客内容,欢迎关注我的CSDN账号,我们一同成长!
(~ ̄▽ ̄)~