Linux下的调试器 : gdb指令详解

🪐🪐🪐欢迎来到程序员餐厅💫💫💫
          主厨:邪王真眼
主厨的主页:Chef‘s blog  
所属专栏:青果大战linux
总有光环在陨落,总有新星在闪烁

gdb是什么

        gdn是linux下的一个开源的命令行调试器,它可以帮助程序员在调试程序时跟踪程序运行过程中的错误。它可以用于C、C++、Fortran、汇编语言等多种编程语言。通过GDB,你可以在程序运行时中断程序的执行,查看和修改变量的值,设置断点,单步执行代码,打印函数调用栈等操作。

       基于gdb强大的调试能力,我们可以快速定位程序运行过程中的错误。现在就让我们来学习它的使用吧。


调试信息

       程序的发布方式有两种,debug模式和release模式 ,那么我们之前gcc编译生成的可执行文件是那种类型呢?我们要知道生成的可执行文件是二进制文件,使用了ELF格式,而readelf指令就可以用来查看ELF文件的信息。
我们先创建一个test1.c文件
#include<stdio.h>
int add(int i)
{int sum=0;for(int j=0;j<=i;j++)sum+=j;return sum;
}
int main()
{int sum=0;for(int i=0;i<=10;i++){sum+=add(i);}printf("%d\n",sum);return 0;
}

现在对他进行gcc,因为我们gcc默认不支持c99的语法,所以要加上-std=c99来让他支持

gcc -o test1.exe test1.c -std=c99

可以看到文件生成了,并且可以正常运行,接下来我们来查看他的调试信息,即debug信息
readelf -S test1.exe |grep debug

        以上指令,管道左侧用于输出可执行文件内的内容,右侧用于筛选含有debug字段,最后该指令什么也没有输出,说明gcc默认生成的可执行文件不包含debug信息,无法被调试。

  • 得出结论:

       gcc默认发布的是release版本,要想发布debug版本,必须在源代码生成二进制程序的时候, 加上 -g 选项

gcc -o test1.exe.debug test1.c -std=c99 -g

文件正常生成并且运行正确

输入指令查看调试debug信息
readelf -S test1.exe.debug |grep debug

成功发现debug信息

  1 #include<stdio.h>2 int add(int i)3 {4     int sum=0;5     for(int j=0;j<=i;j++)6         sum+=j;7         return j;8 }9 int main()10 {11     int sum=0;12     for(int i=0;i<=10;i++)13     {14         sum+=add(i);15     }16     printf("%d\n",sum);17     return 0;                                                                                                                                                                                                18 }

gdb调试过程

进入gdb

输入指令

 gdb test1.exe.debug

出现一堆信息后左下角出现(gdb)说明进入了调试过程
输入:ctrl + d quit 命令即可退出

查看代码信息

  • 指令:l n

以第n行为中心,显示10行代码

  • 指令l
从上次显示的代码结尾开始,显示10行
展示:
输入 l  5,显示周围10行
再输入l,显示接下来10行,但是因为我代码不足10行所以就只显示剩下的部分
l+函数名,以该函数为中心,显示10代码
注意gdb会自动记录你最近一次的指令,如果你直接输入回车,他就会执行上一次的指令

断点:

  • b +行号
在该行设置一个断点
(gdb) b 12
Breakpoint 1 at 0x40055a: file test1.c, line 12.

gdb提醒我们 把断电设置到了test1.c文件的第12行

  • b +函数
在该函数定义的开头设置一个断点
(gdb) b add
Breakpoint 2 at 0x400524: file test1.c, line 4.

gdb提醒我们 把断电设置到了test1.c文件的第12行,因为add函数的定义是从第四行开始的

b是break的缩写,我们用break代替b也是可以的

(gdb) break 16
Breakpoint 3 at 0x40057a: file test1.c, line 16.
  • info b

显示断点信息

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000040055a in main at test1.c:12
2       breakpoint     keep y   0x0000000000400524 in add at test1.c:4
3       breakpoint     keep y   0x000000000040057a in main at test1.c:16
  1. Num那一列是断点的编号
  2. type那一列是类型(断点)
  3. Enb表示断点关闭或启动状态
  4. what是断点位置
  • d+断点编号

表示删除该断点,d是delete的缩写,二者可以相互替代

展示:可以发现我们成功删除了第三个断点

(gdb) delete 3
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000040055a in main at test1.c:12
2       breakpoint     keep y   0x0000000000400524 in add at test1.c:4
  • disable+断点编号

关闭该断点,注意是关闭不是删除

展示:可以发现此时2号断点的状态变成了关闭

(gdb) disable 2
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000040055a in main at test1.c:12
2       breakpoint     keep n   0x0000000000400524 in add at test1.c:4
  • enable+断点编号

开启断点,与disable相对

可以发现此时2号断点的状态变成了开启

(gdb) enable 2
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000040055a in main at test1.c:12
2       breakpoint     keep y   0x0000000000400524 in add at test1.c:4

运行:

  • r:

run的缩写,使用run也可以

开始运行程序,直到程序结束或遇到断点

我们先把断点关了

输入r指令,发现程序直接运行到结束
(gdb) r
Starting program: /home/qingguo/project7_gdb/test1.exe.debug 
220

再把断点都打开,发现程序停在了第一个断电处

(gdb) r
Starting program: /home/qingguo/project7_gdb/test1.exe.debug Breakpoint 1, main () at test1.c:12
12	    for(int i=0;i<=10;i++)

我们继续输入r

The program being debugged has been started already.
Start it from the beginning? (y or n) 

它说程序已经启动了,是否要重新启动,可以看出r不能帮我们进入后面的程序

  • c

是continue的缩写

继续执行程序直到程序结束,或者遇到下一个断点,

(gdb) continue
Continuing.Breakpoint 2, add (i=0) at test1.c:4
4	    int sum=0;
  • 逐过程-n

我们重新执行r,再输入n

我们在第12行设置了断点,所一程序现在这里停了下来,接着输入n,从第12行进入了第14行,这是因为13行是一个上括号{,这在gdb看来是不需要进行操作的,所以跳过了

Breakpoint 1, main () at test1.c:12
12	    for(int i=0;i<=10;i++)
(gdb) n
14	        sum+=add(i);
(gdb) 

        相信大家都记得逐过程的特点是不会进入函数内部,而会把调用函数所在语句当成一条语句。我们来演示一下

(gdb) n
14	        sum+=add(i);
(gdb) nBreakpoint 2, add (i=0) at test1.c:4
4	    int sum=0;

唉?不是,哥们,怎么进去了,这怎么想都进不去吧

        其实是因为我们最开始在add函数里放了断点,所以输入n后在执行函数内容时程序会被停下来,我们去掉断点就好了

12	    for(int i=0;i<=10;i++)
(gdb) n
14	        sum+=add(i);
(gdb) 
12	    for(int i=0;i<=10;i++)
  • s逐语句调试

会进入函数内部

12	    for(int i=0;i<=10;i++)
(gdb) s
14	        sum+=add(i);
(gdb) s
add (i=3) at test1.c:4
4	    int sum=0;

finish执行到当前函数结束,有返回值还会告诉你返回值

(gdb) finish
Run till exit from #0  add (i=3) at test1.c:4
0x000000000040056d in main () at test1.c:14
14	        sum+=add(i);
Value returned is $1 = 6
  •  until +行数 

输入r后程序开始运行,在输入until+行数可以直接运行到该行

(gdb) until 14
main () at test1.c:14
14	        sum+=add(i);

查看变量:

  • p+变量名

显示该变量的值,

12	    for(int i=0;i<=10;i++)
(gdb) p i
$2 = 3
  • display+变量名

跟踪查看一个变量,每次停下来都显示它的值

(gdb) display i
5: i = 5
(gdb) display sum
6: sum = 35
(gdb) n
14	        sum+=add(i);
6: sum = 35
5: i = 6
  • undisplay+编号

取消对先前设置的那些变量的跟踪

可以发现每次显示的i和sun左边都有一个编号,一个是5一个是6,我们输入undisplay 5

(gdb) n
12	    for(int i=0;i<=10;i++)
6: sum = 84
  • set var
在程序运行时修改变量的值
(gdb) set var i=8
(gdb) p i
$5 = 8
  • breaktrace(bt)
查看各级函数调用及参数
(gdb) bt
#0  main () at test1.c:14

我们现在再main函数中,下面使用until跳转到add里

(gdb) bt
#0  add (i=0) at test1.c:4
#1  0x000000000040056d in main () at test1.c:14

可以看到#0后面是add函数,而#1后面是main函数,说明main函数里调用了add,并且我们当前处于add中

  • infoi) locals
查看当前栈帧局部变量的值
(gdb) info locals
sum = 0
(gdb) i locals
sum = 0

        我们今天学习了gdb调试时会用到的十几条指令,下去记得好好复习,才能在以后调试的时候合理使用。


🥰创作不易,你的支持对我最大的鼓励🥰
🪐~ 点赞收藏+关注 ~

e3ff0dedf2ee4b4c89ba24e961db3cf4.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/16477.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开源大模型与闭源大模型,你更看好哪一方?

开源大模型与闭源大模型&#xff0c;你更看好哪一方&#xff1f; 简介&#xff1a;评价一个AI模型“好不好”“有没有发展”&#xff0c;首先就躲不掉“开源”和“闭源”两条发展路径。对于这两条路径&#xff0c;你更看好哪一种呢&#xff1f; 1.方向一&#xff1a;数据隐私 …

springBoot项目中的static和templates文件夹

SpringBoot里面没有我们之前常规web开发的WebContent&#xff08;WebApp&#xff09;&#xff0c;它只有src目录在src/main/resources下面有两个文件夹 static和templates springboot默认 static中放静态页面&#xff0c;而templates中放动态页面。但是webapp文件夹可以有&…

基于webpack+Vue3+JavaScript+antd+less+axios技术栈实现所有组件全局自动化注册

一、前言 最近在做一个项目&#xff0c;因为项目比较小&#xff0c;用户群体年龄跨度较大&#xff0c;同时对兼容性的要求较高&#xff0c;所以选择webpackVue3JavaScriptantdlessaxios的技术栈&#xff0c;在开发的当中发现一个问题&#xff0c;原来在vue2当中&#xff0c;可…

react native 下载功能实现

RN 下载 demo iOS 安装必要的包 react-native-fs 下载使用react-native-permissions 获取权限react-native-share 保存下载的内容到手机 修改 podfile 文件 # Resolve react_native_pods.rb with node to allow for hoisting # require Pod::Executable.execute_command(n…

英伟达的GPU(3)

上节内容&#xff1a;英伟达的GPU(2) (qq.com) 书接上文&#xff0c;上文我们讲到CUDA编程体系和硬件的关系&#xff0c;也留了一个小问题CUDA core以外的矩阵计算能力是咋提供的 本节介绍一下Tensor Core 上节我们介绍了CUDA core&#xff0c;或者一般NPU&#xff0c;CPU执行…

【大数据面试题】31 Flink 有哪些重启方法

一步一个脚印&#xff0c;一天一道面试题 Flink 提供了几种不同的重启方法&#xff1a; 异常自动从 Checkpoint 重启: Checkpoint是Flink的另一种状态快照机制&#xff0c;它比Savepoint更为频繁&#xff0c;提供了细粒度的状态恢复点。通过配置Checkpoint&#xff0c;Flink会…

pyqt QMainWindow菜单栏

pyqt QMainWindow菜单栏 pyqt QMainWindow菜单栏效果代码 pyqt QMainWindow菜单栏 QMainWindow 是 PyQt中的一个核心类&#xff0c;它提供了一个主应用程序窗口&#xff0c;通常包含菜单栏、工具栏、状态栏、中心窗口&#xff08;通常是一个 QWidget 或其子类&#xff09;等。…

头歌OpenGauss数据库-I.复杂查询第4关:计算平均分

本关任务:根据提供的表和数据,查询平均成绩小于60分的同学的学生编号(s_id)、学生姓名(s_name)和平均成绩(avg_score),要求平均成绩保留2位小数点。(注意:包括有成绩的和无成绩的) student表数据: s_ids_names_sex01Mia女02Riley男03Aria女04Lucas女05Oliver男06C…

【数据结构/C语言】深入理解 双向链表

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;数据结构与算法 在阅读本篇文章之前&#xff0c;您可能需要用到这篇关于单链表详细介绍的文章 【数据结构/C语言】深入理解 单链表…

[vue error] vue3中使用同名简写报错 ‘v-bind‘ directives require an attribute value

错误详情 错误信息 ‘v-bind’ directives require an attribute value.eslintvue/valid-v-bind 错误原因 默认情况下&#xff0c;ESLint 将同名缩写视为错误。此外&#xff0c;Volar 扩展可能需要更新以支持 Vue 3.4 中的新语法。 解决方案 更新 Volar 扩展 安装或更新 …

java人口老龄化社区服务与管理平台源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的人口老龄化社区服务与管理平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 人口老龄化…

Elasticsearch的Index sorting 索引预排序会导致索引数据的移动吗?

索引预排序可以确保索引数据按照指定字段的指定顺序进行存储&#xff0c;这样在查询的时候&#xff0c;如果固定使用这个字段进行排序就可以加快查询效率。 我们知道数据写入的过程中&#xff0c;如果需要确保数据有序&#xff0c;可能需要在原数据的基础上插入新的数据&#…

嵌入式进阶——震动马达PWM

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 PWMB的应用实现main.c PWMB的应用 实现不同占空比下的震动的效果 拷贝依赖 STC8H_PWM.hSTC8H_PWM.cNVIC.hNVIC.cSwitch.h 实现m…

vue实现页面渲染时候执行某需求

1. 前言 在之前的项目中&#xff0c;需要实现一个监控token是否过期从而动态刷新token的功能&#xff0c;然而在登录成功后创建的监控器会在浏览器刷新点击或者是通过导航栏输入网址时销毁... 2. 试错 前前后后始过很多方法&#xff0c;在这里就记录一下也许也能为各位读者排…

显式锁的分类

显式锁的分类 显式锁 有很多种&#xff0c;从不同的角度来看&#xff0c;显式锁大概有以下几种分类 可重入锁 和 不可重入锁悲观锁 和 乐观锁共享锁 和 独占锁可中断锁 和 不可中断锁公平锁 和 非公平锁 1.可重入锁&#xff08;Reentrant Lock&#xff09;与不可重入锁 可重入…

js学习第一周

1.变量 1.变量命名规则 严格区分大小写不能以数字开头不能是关键字&#xff0c;保留字&#xff0c;不能用name用作变量名小驼峰命名法命名符号只能用下划线 _ 和doller $并且中间不能有空格 2.类型推断 JavaScript是一种动态类型的语言&#xff0c;这意味着你不需要在声明变…

基于JAVA GUI的JDBC连接数据库

要在Java GUI中连接数据库&#xff0c;需要执行以下几个步骤&#xff1a; 导入必要的包。你需要导入Java数据库连接相关的包&#xff0c;例如java.sql和javax.sql。 与数据库连接相关的类和接口。 &#xff08;1&#xff09;DriverManger类。DriverManager类用于加载JDBD驱动…

【每日力扣】84. 柱状图中最大的矩形 与 295. 数据流的中位数

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害 84. 柱状图中最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为…

redis6.2.7 搭建一主多从

1、集群规划 节点端口角色192.168.137.1026379master192.168.137.1026380slave192.168.137.1036381slave 2、伪集群搭建 2.1 创建fake_cluster 目录存放 公共配置文件 # 进入redis目录 cd /app/apps/redis-6.2.7# 创建存放伪集群的目录 mkdir fake_cluster#复制redis.conf到…

DTC 2024回顾丨云和恩墨重塑数据库内核技术,革新企业降本增效之道

在数字化浪潮席卷全球的当下&#xff0c;关系型数据库作为市场主导力量的地位依然稳固。然而&#xff0c;面对新兴数据库与服务形态的挑战&#xff0c;以及企业日益强烈的降本增效需求&#xff0c;数据库技术的发展必须紧跟时代步伐&#xff0c;充分发挥资源效能以提升企业竞争…