【Linux】调试器 gdb / cgdb

目录

  • 一、什么是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 在已有断点基础上修改其为条件断点)
  • 四、调试的本质

个人主页:矢望

个人专栏:C++LinuxC语言数据结构

一、什么是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 无法显示源代码、变量名等信息。这是为什么呢?

程序状态分为两种模式,分别是 DebugReleaseDebug版本包含调试信息,是程序员在开发期间所处的模式,而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很不直观,这里推荐使用cgdbCGDB 是一个基于 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 变量:打印指定变量的值。

但我们要是每一步都想查看怎么办,这还要每一步都自己敲吗?

可以使用displaydisplay 变量名:跟踪显示指定变量的值

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账号,我们一同成长!
(~ ̄▽ ̄)~

相关推荐
徐子元竟然被占了!!3 小时前
Linux-systemctl
linux·数据库·oracle
_w_z_j_6 小时前
Linux----mmap
linux
程序员zgh7 小时前
Linux系统常用命令集合
linux·运维·服务器·c语言·开发语言·c++
Bigan(安)7 小时前
【奶茶Beta专项】【LVGL9.4源码分析】09-core-obj_class对象类系统
linux·c语言·mcu·arm·unix
紫郢剑侠8 小时前
飞秋@Windows +iptux@Linux,打造内网跨平台IM环境
linux·运维·服务器·im·qq
保持低旋律节奏8 小时前
linux——调试
linux·运维·服务器
牛奶咖啡138 小时前
Linux系统故障排查思路实践教程(下)
linux·运维·服务器·su命令切换用户问题解决·文件打开过多问题解决·linux网络故障问题解决·linux故障排查思路
coder4_8 小时前
Linux 数据同步全攻略:NFS 共享、inotify+rsync 与 sersync 实战指南
linux·rsync·文件共享·nfs·数据同步·inotify·实时备份
Lynnxiaowen8 小时前
今天我们继续学习kubernetes内容Helm
linux·学习·容器·kubernetes·云计算
Bigan(安)9 小时前
【奶茶Beta专项】【LVGL9.4源码分析】08-theme主题管理
linux·c语言·mcu·arm·unix