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;数据隐私 …

英伟达的GPU(3)

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

pyqt QMainWindow菜单栏

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

【数据结构/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;可能需要在原数据的基础上插入新的数据&#…

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

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

【每日力扣】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;充分发挥资源效能以提升企业竞争…

【机器学习300问】99、多通道卷积神经网络在卷积操作时有哪些注意事项?

一、多通道卷积神经网络示例 还是以图像处理为例&#xff0c;如果你的目标不仅是分析灰度图像特性&#xff0c;还打算捕捉RGB彩色图像的特征。如下图&#xff0c;当面对一张66像素的彩色图像时&#xff0c;提及的“3”实际上是指红、绿、蓝三种颜色通道&#xff0c;形象地说&am…

书生·浦语第二期-笔记2

课程链接&#xff1a;https://github.com/InternLM/Tutorial/tree/camp2 视频地址&#xff1a;轻松玩转书生浦语大模型趣味Demo_哔哩哔哩_bilibili 大模型及InternLM介绍 大模型&#xff1a;人工智能领域中参数数量巨大、拥有庞大计算能力和参数规模的模型 特点&#xff1a…

【Linux杂货铺】进程通信

目录 &#x1f308; 前言&#x1f308; &#x1f4c1; 通信概念 &#x1f4c1; 通信发展阶段 &#x1f4c1; 通信方式 &#x1f4c1; 管道&#xff08;匿名管道&#xff09; &#x1f4c2; 接口 ​编辑&#x1f4c2; 使用fork来共享通道 &#x1f4c2; 管道读写规则 &…

初中英语优秀作文分析-002Who stole the cupcake-谁偷了纸杯蛋糕?

更多资源请关注纽扣编程微信公众号 记忆树 1 One Sunday afternoon, Leslie was at home with her kids, 3-year-old Angel, 6-year-old Carl, and 7-year-old Tony. 翻译 一个周日的下午&#xff0c;Leslie和她的孩子们在家&#xff0c;他们是3岁的Angel&#xff0c;6岁的…

镜子摆放忌讳多

镜子是我们日常生活中不可或缺的物品。在风水中&#xff0c;镜子的作用非常多&#xff0c;能够起到一定的作用。镜子的摆放位置也是非常有讲究的&#xff0c;摆放不好会直接影响到家人的事业、财运、婚姻乃至健康等诸多方面。 第一个风水忌讳&#xff0c;镜子对大门。大门的正前…

Linux防火墙之iptables(二)

一.SNAT策略概述 1.SNAT 策略的典型应用环境 局域网主机共享单个公网IP地址接入Internet&#xff08;私有IP不能在Internet中正常路由&#xff09; 局域共享上网 2.SNAT 策略的原理 源地址转换&#xff0c;Source Network Address Translation 修改数据包的源地址 未作SNAT转换…

用three.js+echarts给公司写了一个站点数据大屏系统经验总结

时间过的好快,参加公司的新项目研发快一年了,五一机器人项目首秀,我们遇到了高并发集中下单情景,然后海量数据处理场景来了,给我在后端领域的高并发实践业务上画上了漂亮的一笔经验。人都是在磨练中成长,我很感谢这次给我的机会,虽然有点累,但也有点小成就。正好现在有…

AGI系列(1):掌握AI大模型提示词优化术,提问准确率飙升秘籍

当我们向AI大模型提问时&#xff0c;通常人们的做法是有什么问题&#xff0c;就直接去问&#xff0c;得到大模型的回复结果&#xff0c;时好时坏&#xff0c;完全没有可控性。 那么有没有一种方式或是一套方法&#xff0c;可以让我们向大模型提问时&#xff0c;得到的结果更准确…