GDB调试:教你简单了解并使用GDB调试程序

2023-11-05

什么是GDB?

GDB(GNU symbolic debugger) 是由 GNU 软件系统社区提供的调试工具。当下的 GDB 支持调试多种编程语言编写的程序,包括 C、C++、Go、Objective-C、OpenCL、Ada 等。实际场景中,GDB 更常用来调试 C 和 C++ 程序,同 GCC 配套组成了一套完整的开发环境。

何谓调试?就是让代码一步一步慢慢执行,跟踪程序的运行过程。比如,可以让程序停在某个地方,查看当前所有变量的值,或者内存中的数据;也可以让程序一次只执行一条或者几条语句,看看程序到底执行了哪些代码。

所以GDB可以帮我们:
程序启动时,可以按照我们自定义的要求运行程序,例如设置参数和环境变量;
可使被调试程序在指定代码处暂停运行,并查看当前程序的运行状态(例如当前变量的值,函数的执行结果等),即支持断点调试;
程序执行过程中,可以改变某个变量的值,还可以改变代码的执行顺序,从而尝试修改程序中出现的逻辑错误。

使用GDB前的准备工作

我们需要在用gcc/g++编译器编译可执行程序时需要加入 -g 参数,才能去生成可供GDB调试的可执行程序。

参数 -g :在编译的时候,加入调试信息,让该程序可以被调试器调试。

所谓调试信息就是各行代码所在的行号、包含程序中所有变量名称的列表(又称为符号表)等

注意⚠️:一旦生成了可调试程序文件,就不要再去修改源文件里面的信息,否则调试的时候就会出现一些错误。如果需要修改源文件,则修改后要重新生成调试文件以供调试。

这个时候,我们输入命令

gdb 文件名

就可以进入到gdb调试页面了,这个时候会生成一系列的免责条款,加上参数:–silet 就可以屏蔽掉这些免责信息。

GDB中的一些基础调试命令。

在使用gdb调试命令的过程中,为了操作方便,有一些时候我们可以按下tab键去进行自动补全操作。

启动和退出

上文已经讲过如何生成可供gdb调试的调试文件,和如何启动gdb调试界面来调试程序了,接下来我们讲一下,如何退出gdb。

在gdb调试页面中,我们输入 q/quit ,即可退出gdb调试界面回到终端。

查看代码信息

我们刚刚进入到gdb调试界面时,除了有一堆免责信息,其他的什么都是没有的。如果需要查看源代码,我们就要输入 l/list 去查看源代码。默认设置是查看主函数文件的前10行。

l/list //查看主函数文件的前10行
l/list 行号 //查看包括当前行号的前5行与后5行代码
l/list 函数名 //查看当前函数所在文件的前10行
l/list 文件名:行号 //查看指定文件行号的上下5行文件

我们可以通过命令: set list/listsize 行号 来去修改默认查看的总行数。使用命令:show list/listsize,来查看当前一次性可以查看多少行。

清空调试信息

当我们有时候觉得调试信息太杂乱,或者不想看到当前的这些调试信息时,可以使用命令:

!clear

来将当前调试界面上的所有调试信息清空。

一系列的断点操作

设置断点的作用

我们在源代码的对应位置设置断点后,可以使被调试程序在断点处暂停运行,并查看当前程序的运行状态(例如当前变量的值,函数的执行结果等)。

注意⚠️:停在断点处的那一行代码是还未执行的代码。

设置断点

通过命令

b/break 行号 //在主文件(有main函数的文件)对应行上设置断点。
b/break 函数名 //在主函数指定的函数体内第一行处打上断点。
b/break 文件名:行号 //在指定文件的对应行上打上断点。
b/break 文件名:函数名 //在指定文件内的函数体内的第一行代码处打上断点

查看设置了哪些断点

使用命令:

i/info b/break

就可以查看所有已设置的断点信息,如在第几行,断点的编号是多少等

(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000000b09 in main() at main.cpp:8
2       breakpoint     keep y   0x00000000000009b5 in bubbleSort(int*, int) at bubble.cpp:8

删除断点

使用命令:

d/del 断点编号

就可以删除错误设置的断点

设置断点不生效/生效

断点设置完成时,默认生效。当我们希望某些断点不要生效时,就使用命令:

dis/disable 断点编号

就可以使对应编号的断点无效化。如果想要无效化的断点重新生效了话,就要使用命令:

ena/enable 断点编号

来使对应断点重新生效。

设置条件断点

当我们设置的断点在某个循环内,我们可以通过设置条件断点,来让程序停在对应的条件处:

b 行号 if 变量名==值

运行调试程序

运行程序命令run与start的区别

之前讲过了如何去在程序上设置断点,现在就可以开始讲如何运行调试程序了。我们使用 r/run 命令 和 start 命令都可以开始运行调试程序。
它们的区别在于:

  • start命令会使被调试的程序停在主函数入口处。
  • run命令则是使程序停在第一个断点那一行

继续执行程序命令next、continue、step的区别

next、continue、step命令都是关于程序继续运行的命令,但是他们都之间都略有区别

  • 执行命令 c/continue 的意思是使程序继续运行,只到下一处断点才会停下

  • 执行命令 n/next 则是使程序向下执行一行,如果这一行是一个被调用的函数,使用next命令,不会进入到函数题内。

  • 执行命令 s/step 也是使程序向下执行一行与 next 不同的便是遇到被调用的函数,会进入到函数体内部。而我们如果想要出这个函数体,则可以使用 finish 命令去跳出函数体。

打印变量值命令print与display的区别

我们可以使用命令:

p/print 变量名
display 变量名

去获取对应变量名的值
它们直接的区别是,print只会在执行print命令的时候,将对应变量的值打印一遍。而使用display命令则是打印对应的变量值,当程序继续执行后,继续输出对应变量当前的值。

被display设置过的变量也称之为自动变量,多用于循环体内。
如这么一段代码:

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
(gdb) print array[i]
$1 = 12
(gdb) n
15          for(int i = 0; i < len; i++) {
(gdb) display array[i]
1: array[i] = 12
(gdb) n

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
1: array[i] = 22
(gdb) 
15          for(int i = 0; i < len; i++) {
1: array[i] = 22
(gdb) 

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
1: array[i] = 27
(gdb) 
15          for(int i = 0; i < len; i++) {
1: array[i] = 27
(gdb) 

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
1: array[i] = 55
(gdb) 
15          for(int i = 0; i < len; i++) {
1: array[i] = 55
(gdb) 

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
1: array[i] = 67
(gdb) 
15          for(int i = 0; i < len; i++) {
1: array[i] = 67
(gdb) 
18          cout << endl;
(gdb) 

我们就可以看出在循环体内,每向下执行一步,display变量都会输出一遍变量的值,而print只输出了一遍。

我们可以使用命令:

i/info display

去查看自己设置了哪些自动变量,也可以使用命令:

undisplay 自动变量编号 去删除刚刚设置的自动变量

使用命令:

ptype 变量名

则可以查看对应变量的类型

跳出循环命令until与跳出函数体命令finish

当我们程序停在一个循环体内的某一条输出语句时,如何跳出循环体呢?
首先我们将循环体内的断点删除或是停用。使用命令c 即可调到这个循环体外的下一个断点处。
使用n则是程序向下执行一行。不会跳出这个循环,使用命令s与n一样。
这个时候使用until命令则会回到未循环体的第一行,这个时候就可以重新选择是进入循环还是跳出循环了。

(gdb) run
Starting program: /home/nowcoder/Linux/lession08/mainApp 

Breakpoint 2, main () at main.cpp:8
8           int array[] = {12, 27, 55, 22, 67};
(gdb) c
Continuing.

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
(gdb) display array[i]
2: array[i] = 12
(gdb) c
Continuing.

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
2: array[i] = 22
(gdb) disa 3
(gdb) until
15          for(int i = 0; i < len; i++) {
2: array[i] = 22
(gdb) 

finish命令与until命令很相似,如果此时程序停在了函数体内部,如果函数体内部向下执行没有断点,则使用finish则可以跳出函数体,将程序停在执行完函数体的下一行。
如果函数体内部向下有断点,使用finish命令则就会停在断点处。

改变变量值的操作

我们可以使用命令:

set var 变量名=变量值

去修改某些变量的值,从而达到修改输出的目的。

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
2: array[i] = 22
(gdb) set var array[i] = 23
(gdb) c
Continuing.

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
2: array[i] = 27
(gdb) 
Continuing.

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
2: array[i] = 55
(gdb) 
Continuing.

Breakpoint 3, main () at main.cpp:16
16              cout << array[i] << " ";
2: array[i] = 67
(gdb) 
Continuing.
冒泡排序之后的数组: 12 23 27 55 67 
===================================
选择排序之后的数组: 11 25 36 47 80 
[Inferior 1 (process 1113) exited normally]
(gdb) 

GDB多进程调试

使用GDB调试的时候,GDB默认只能跟踪一个进程,可以在fork函数调用之前,通过指令设置GDB调试工具追踪父进程或者是跟踪子进程,默认跟踪父进程

设置调试父进程或者子进程:set follow-fork-mode parent/child

输入命令: show follow-fork-mode gdb会告诉你,你现在正在调试的是父进程还是子进程

设置调试模式:set detach-on-fork on/off 这个是设置的意思是,使用了fork函数后,另一个进程是否脱离gdb的调试。默认是on,也就是开启状态。
换句话说也就是,处于on状态下,表示调试当前进程的时候,其他的进程继续运行,处于off状态下,其他进程被gdb挂起。

输入命令: show fdetach-on-fork on/off gdb会告诉你,另一个进程是否会脱离。

查看调试的进程:info inferiors //会把调试的所有进程的进程号标识在这里,当前调试的会有一个*号,并且会有一个Num去记录gdb调试进程的id。

切换当前调试的进程:inferior id

使进程脱落GDB调试:detach inferiors id

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GDB调试:教你简单了解并使用GDB调试程序 的相关文章

随机推荐

  • Spring Cloud Alibaba 2021.0.1.0 版本发布啦

    01 什么是 Spring Cloud Alibaba Aliware Spring Cloud Alibaba 是由阿里巴巴 后文简称 阿里 中间件团队于 2018 年 7 月开源 为业界提供的一套基于阿里内部分布式技术的一站式微服务构建
  • JavaWeb学习-Servlet处理解析JSON文件导出Excel实例

    文章目录 前言 一 实例要求 二 主要问题点 1 保存请求中的文件 2 JSON的简单处理 3 Servlet共享数据 实现勾选信息导出为excel 三 源码 总结 前言 这里是javaweb小白第一次尝试写博客 主要是想记录一下自己在学习
  • vue 简单实现vuex原理

    效果图如下 1 准备好环境 使用 vue cil 初始化项目配置 npm install g vue cli 全局安装 vue cli vue create demo vue 创建项目 yarn add vuex安装vuex创建一个stor
  • 什么是区块链?区块链相关知识区入门

    初识区块链 1 区块链家族 一 去中心化 父亲 基本概念 中心化和去中心化就是集权与分权 去中心化是一种哲学中思想 在人类存在时即有 主旨为弱化中心 实现人与人之间的直接沟通 交易的一种方式 去中心化 不是不要中心 而是由节点来 自由选择中
  • 使用gdb调试出现 No debugging symbols found in a.out

    使用常规的gcc编译或者使用带调式信息 g的编译都有可能会在使用gdb工具的时候出现No debugging symbols found in a out错误 1 常规编译 使用常规编译生成的可执行文件正常一定会出现No debugging
  • 服务器强制关机后,无法开机

    服务器强制关机后 开不了机 开机后显示 dev sda1 recovering journal dev sda1 clean 3905813 58720032 files 193134708 234422272 blocks 经询问 是由强
  • 2014软专高级程序语言T4(三角形面积)

    平面有100个点 任意三个点可以构成一个三角形 编一个程序 输入100个点的坐标 输出在构成的所有三角形中 最大的三角形的面积 代码如下 include
  • 数据处理中的归一化与反归一化

    一 定义 数据归一化 标准化 是数据预处理的一项基础工作 不同评价指标往往具有不同的量纲和量纲单位 为避免影响数据分析结果 消除指标之间的量纲影响 须对数据进行标准化处理 数据的归一化 normalization 是将数据按比例缩放 使之落
  • redis必杀命令:键(key)

    语法 Redis 键命令的基本语法如下 redis 127 0 0 1 6379 gt COMMAND KEY NAME 例如 redis 127 0 0 1 6379 gt SET w3ckey redis OK redis 127 0
  • 使用UltraISO或Rufus制作U盘启动安装优麒麟19.04

    本文教你在Windows操作系统中使用UltraISO 软碟通 或Rufus制作U盘启动盘的方法 以优麒麟Ubuntu Kylin 19 04为例 适用于大多数Linux发行版 包括Ubuntu 18 04等 UltraISO和Rufus任
  • [网络安全自学篇] 三十八.hack the box渗透之BurpSuite和Hydra密码爆破及Python加密Post请求(二)

    这是作者的系列网络安全自学教程 主要是关于安全工具和实践操作的在线笔记 特分享出来与博友们学习 希望您们喜欢 一起进步 前文详细讲解了hack the box在线渗透平台获取邀请码 注册过程 本文将分享Web渗透三道入门题目 它们包括Pyt
  • python3 [爬虫入门实战] 爬虫之使用selenium 爬取百度招聘内容并存mongodb

    爬取的内容为百度招聘页面下的python 杭州地区 所要爬取的内容 一共爬取的是6个字段 1 招聘岗位 2 招聘城市 3 招聘公司 4 招聘薪资 5 招聘日期 6 招聘来源网站 用的是selenium beautifulsoup mongo
  • 餐饮开发项目有智能排菜算法遇到的问题

    说白了 智能排菜就是在用户下了订单之后自动的打印菜品 包含相同的菜品可以一起打出来 以提高饭店效率 个人的想法就是运行一个Timer 事实的检测智能排菜这个功能是否启用 若启用的话则自动打印菜品 Timer的用法就是要继承TimeTask把
  • 【无标题】Altium Designer 版本功能介绍收集

    尊敬的原文作者 感谢分享 如文章转载有冒犯之处 请您联系告知 鄙人将在第一时间删除 原文连接 Altium Designer更新得那么快 到底应该用哪个版本 电子发烧友网 AD19 0 6 显然 软件版本越高 功能越齐全 可能存在一些未知的
  • 使用JAVA实现语音朗读一段文本

    需求要用JAVA去调用windows自带的语音引擎去朗读一段文字 网上资料少得可怜 把百度和bing都翻遍了 总算找到一段代码 而且朗读起来还有感情色彩 win7测试 不过多音字还是暂时没解决 需要做的工作 1 下载jacob 1 17 M
  • 从源码出发浅析 Android TV 的焦点移动原理 (上篇)

    转自 https cloud tencent com developer article 1006289 焦点 焦点 Focus 可以理解为选中态 在Android TV上起很重要的作用 一个视图控件只有在获得焦点的状态下 才能响应按键的C
  • 安装Android Studio出现的问题--SDK Components Setup

    安装的时候遇到这样的问题 查了半天资料才解决 先看一看出错的地方 这一步是安装sdk 选择安装的位置 我选择直接安装到Android目录下 但是出问题了 换了其他的也不可以 再看一看我的文件夹安装目录 问题就出现在这里了 文件夹没弄对 解决
  • flex程序

    lt mx Application xmlns mx http www adobe com 2006 mxml layout absolute gt lt mx Script gt lt mx HTTPService id productS
  • pythonallowpos_Python 爬取 热词并进行分类数据分析-[数据修复]

    日期 2020 02 01 博客期 140 星期六 本博客的代码如若要使用 请在下方评论区留言 之后再用 就是跟我说一声 所有相关跳转 a 简单准备 c 拓扑数据 d 数据修复 本期博客 i App制作 j 安全性改造 今天问了一下老师 好
  • GDB调试:教你简单了解并使用GDB调试程序

    什么是GDB GDB GNU symbolic debugger 是由 GNU 软件系统社区提供的调试工具 当下的 GDB 支持调试多种编程语言编写的程序 包括 C C Go Objective C OpenCL Ada 等 实际场景中 G