【Linux系统编程】代码调试工具gdb

介绍:

        gdb是一个非常强大的调试工具,在gdb下,我们可对编写的代码进行各种调试,找出其中的bug,但是需注意的是,此工具调试与VS编译器的调试道理相同,只有在debug版本下才可以被调试,在release版本下不能被调试。因为debug版本是程序员专门开发时使用的版本,要包含一切与调试相关的数据,占用内存大,而release版本是最终开发后给用户使用的版本,也就是测试版本,没有与调试相关的数据,并且还将代码做了许多优化,占用内存小。

版本的调用:

        在Linux系统的CentOS 7版本下,gcc/g++编译时默认的模式是release模式,以下的所有演示都是在CentOS 7版本下进行的。其它版本下编译器的配置可能有些不同,默认的模式可能是debug。

        如果需要使用debug模式,通常需要在编译命令中添加 -g 参数,如 gcc -g 或 g++ -g等。如果想要编译为release模式,需要在编译命令中添加 -O2 -O3 参数。

[zhu@zhujunhao day11]$ g++ -o code-d -g code.cpp   //运用debug模式进行编译
[zhu@zhujunhao day11]$ g++ -o code-r -O2 code.cpp  //运用release模式进行编译
[zhu@zhujunhao day11]$ g++ -o code.exe code.cpp    //默认模式,使用release进行编译
[zhu@zhujunhao day11]$ ll

//下面可观察到release模式和debug模式编译形成的可执行程序占用内存大小差距很大
total 48
-rw-rw-r-- 1 zhu zhu   103 Dec 11 11:18 code.cpp
-rwxrwxr-x 1 zhu zhu 19536 Dec 11 12:29 code-d
-rwxrwxr-x 1 zhu zhu  8968 Dec 11 12:31 code.exe
-rwxrwxr-x 1 zhu zhu  8832 Dec 11 12:30 code-r

        gdb调试器只能在debug编译模式下运行,因为只有debug有与调试有关的数据。从上面可看出,debug生成的可执行程序占用的内存大,里面包含了可调试的数据。

readelf工具:

        readelf 工具用于读取可执行程序的格式问题。可执行程序所对应的格式在Linux中叫做ELF。通过使用 readelf 命令,我们可查看ELF文件的头部信息、节区信息、符号表等等。这些信息对于理解和分析程序的组成、结构和行为非常重要。后期在gdb调试工程过程中,会更加依赖使用readelf工具查看格式化问题。如使用 readelf -S [可执行文件] 只读取头部ELF信息。

[zhu@zhujunhao day11]$ readelf -S code-d   //显示节头

        这里提醒下,readelf只能用于程序的可执行文件。

gdb调试运用:

        首先,当我们生成可执行程序时,使用 gdb [可执行文件] 可进入调试阶段。当进入调试界面后,l 指令可查看源文件的内容,具体使用如下:

          1,l n(n代表行号) 从第n行开始,显示往后的10行源代码。

          2,只输入 l 将从源代码中光标所在的位置开始显示10行内容。

          3,l [文件]:n(n代表行号)  显示指定[文件]中10行内容,其中,第 n 行内容将会在中间。 

        若我们想往后面再观看源代码时,只需直接 “回车” 键即可,因为gdb会自动记录最近一次的指令。若想退出,输入quit后可退出调试界面。注意,gdb调试器调试的是生成的可执行文件,不是源文件。  

[zhu@zhujunhao day11]$ gdb code.exe    //进入code.exe的调试界面
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/zhu/day11/code.exe...done.
(gdb) l 1       //从第一行开始显示10行源代码
warning: Source file is more recent than executable.
1    #include <iostream>
2    using namespace std;
3    int main()
4    {
5        int i = 0, n = 5;  
6        while (i < n)
7        {
8            cout << "兔子" << endl;
9            i++;
10        }
(gdb)         //直接回车继续往下显示源代码,一次10行
11        cout << "Debug" << endl;
12        return 0;    
13    }
(gdb)         
Line number 14 out of range; code.cpp has 13 lines.   //表示已全部展开完毕
(gdb) quit   //退出调试界面

       当进入调试界面后,r(run的简写)指令可运行程序,即从头开始进行调试。

(gdb) r   //启动运行,这里没有设置断点,直接运行完毕
Starting program: /home/zhu/day11/code.exe 
兔子
兔子
Debug
[Inferior 1 (process 12251) exited normally]
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64 libgcc-4.8.5-44.el7.x86_64

断点功能:

        break(简写:b)是设置断点的指令,使用方法有:

                1,b n 在第n行处设置断点。    

                2,b [函数名] 在指定的函数入口处设置断点。 

                3,b [文件名]:n 在指定的文件第n行设置断点。

        当设置完断点后可使用 info b 指令查看我们设置的所有断点。具体的解释如下:

//使用b n 在第n行设置断点,设置完之后可观察到断点的地址、文件的来源和设置的行数

(gdb) b 5     
Breakpoint 1 at 0x4007e5: file code.cpp, line 5.     
(gdb) b 8
Breakpoint 2 at 0x4007f5: file code.cpp, line 8.
(gdb) b 11
Breakpoint 3 at 0x40081d: file code.cpp, line 11.
(gdb) info b

//显示所有有关断点的信息

/*Num表示断点的编号。Type表示设置类型,这里是断点。 Enb表示断点的功能的开闭,y是yes的意思,表示断点的功能正常,n是no的意思,表示断点的功能关闭,但断点还存在。Address表示断点的地址。What表示断点在哪个函数、哪个文件、哪一行中。*/
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004007e5 in main() at code.cpp:5
2       breakpoint     keep y   0x00000000004007f5 in main() at code.cpp:8
3       breakpoint     keep y   0x000000000040081d in main() at code.cpp:11

        delete(简写:d)是删除断点的指令。使用方法:d n 删除编号为n的断点。注意,这里的n代表编号,不是行数。这里可使用info b指令查看Num中的标号。

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004007e5 in main() at code.cpp:5
2       breakpoint     keep y   0x00000000004007f5 in main() at code.cpp:8
3       breakpoint     keep y   0x000000000040081d in main() at code.cpp:11
(gdb) d 1       //删除编号1的断点
(gdb) info b
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x00000000004007f5 in main() at code.cpp:8
3       breakpoint     keep y   0x000000000040081d in main() at code.cpp:11
(gdb) d 2       //删除编号2的断点
(gdb) info b
Num     Type           Disp Enb Address            What
3       breakpoint     keep y   0x000000000040081d in main() at code.cpp:11
(gdb) d 3        //删除编号3的断点
(gdb) info b
No breakpoints or watchpoints.    //显示断点已删除完毕
        

        当我们设置完断点时,默认断点的功能是打开的。当我们使用 disable n(这里的n表示断点的编号) 指令时,可将编号为n的断点功能失效,但不删除。当使用 enable n(这里的n表示断点的编号) 指令时,可将编号为n的断点功能打开,与disable功能相反。

        这里要说明的是,使用disable/enable后,由于调试断点的设置已被更改,当使用 r(run) 运行程序时,系统可能会提醒是否重新生成程序运行。

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004007e5 in main() at code.cpp:5
2       breakpoint     keep y   0x00000000004007f5 in main() at code.cpp:8
3       breakpoint     keep y   0x000000000040081d in main() at code.cpp:11
(gdb) disable 2
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004007e5 in main() at code.cpp:5
2       breakpoint     keep n   0x00000000004007f5 in main() at code.cpp:8
3       breakpoint     keep y   0x000000000040081d in main() at code.cpp:11
(gdb) enable 2
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004007e5 in main() at code.cpp:5
2       breakpoint     keep y   0x00000000004007f5 in main() at code.cpp:8
3       breakpoint     keep y   0x000000000040081d in main() at code.cpp:11

逐过程和逐语句

        逐语句是一行一行进行分析,它将会进入函数内部。逐过程是一次直接执行一个过程,它将一次直接执行完一个函数,不会进行函数内部分析。

        在gdb调试中,逐过程的指令是next,简写:n。逐语句的指令是step,简写:s。当在使用一次逐过程/逐语句后,下面直接按 “回车” 键即可继续往下面运行,也可不断使用n/s往下面运行,而在此过程中,我们可使用 p [变量](print的简写) 查看变量的内容,如:p n 查看数据中n的值,p &s 查看变量s的地址。这里需注意,p指令使用无法一直显示数据,当再次进行操作时,变量的内容将会消失。display [变量] 将会永久的显示数据。undisplay n(这里的n代表编号) 将会把编号为n的显示内容删除。

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004007f3 in main() at code.cpp:6
2       breakpoint     keep y   0x0000000000400839 in main() at code.cpp:13
3       breakpoint     keep y   0x00000000004008fd in main() at code.cpp:20
4       breakpoint     keep y   0x0000000000400a15 in main() at code.cpp:30
(gdb) r
.........

(gdb) n   //逐过程分析
8            cout << "兔子" << endl;

(gdb)    //回车继续运行
兔子
main () at code.cpp:9
9            i++;
.........

//使用p指令显示一次数据的内容

(gdb) p i   
$1 = 5
(gdb) p n
$2 = 10
(gdb) p &i
$3 = (int *) 0x7fffffffe4dc

//可发现p指令不能永久显示
(gdb) n
8            cout << "兔子" << endl;
//使用display指令永久显示数据内容

(gdb) display i
1: i = 6    //i变量编号1
(gdb) display n
2: n = 10  //n变量编号2

//逐过程继续运行还会看到数据内容
(gdb) n
兔子
9            i++;
2: n = 10
1: i = 6
//使用undisplay指令删除指定数据内容,注意,这里要输入编号

(gdb) undisplay n   //输入变量,出现错误
warning: bad display number at or near 'n'
(gdb) undisplay 2  //输入编号2,删除编号2变量的内容
(gdb) n
8            cout << "兔子" << endl;
1: i = 8

范围式查找:

        范围式调试常用指令有以下:

            continue(简写:c):从一个断点运行到下一个断点或程序结束。它通常用来范围查找。

            bt:查看当前函数的堆栈信息,根据函数栈帧发现问题。

            finish:运行当前所在的函数,将当前所在的一个函数运行结束后就停止。但是,它不会            将主函数一次运行完。

            until n(n代表行号):直接将程序运行到第n行,若中间出现死循环,在运行中将会出现死            循环问题。

        以上几个指令都是在源代码基础上进行局部分析,但在调试中,我们可能会想测试源代码中某些变量改变后的情况。通常,使用 set var [改变内容] 指令即可完成如:set var flag=0 查看将源代码中变量flag的值变为0时的测试情况。

注意:

        1,使用set var指令改变内容时,要改变的变量必须已经在内部存储过,即程序已经运行到这部分时才可改变。

        2,set var改变内容只是在测试中改变,不会影响源代码的内容,在测试时可放心使用。

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004007f3 in main() at code.cpp:6
2       breakpoint     keep y   0x0000000000400855 in main() at code.cpp:14
3       breakpoint     keep y   0x00000000004008fd in main() at code.cpp:20
4       breakpoint     keep y   0x0000000000400a15 in main() at code.cpp:30
(gdb) r       //run的简写,直接运行到编号1断点的位置
.............
(gdb) c      //continue的简写,从当前断点位置运行到编号2断点的位置
.............
(gdb) bt
#0  main () at code.cpp:14   //主函数栈帧
(gdb) until 18    //将程序从当前位置直接运行到第18行
.............
(gdb) set var i=6    //改变变量i的值
(gdb) p i    //查看i已经改变过
$1 = 6
(gdb) finish   //直接运行完一个函数(方法),这里程序在主函数中,因此不能正常运行
"finish" not meaningful in the outermost frame.

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

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

相关文章

为什么近期白酒市场股票暴跌?2024年中高端酒企发展如何撬动市场?

为什么近期白酒市场股票暴跌&#xff1f;2024年中高端酒企发展如何撬动市场&#xff1f; 近期白酒市场股票暴跌的原因主要有两个方面&#xff1a;一是宏观经济环境的不景气&#xff0c;导致投资者对白酒行业的未来发展持谨慎态度&#xff1b;二是白酒市场竞争激烈&#xff0c;龙…

Linux---计划任务

本章主要介绍如何创建计划任务 使用 at 创建计划任务使用 crontab 创建计划任务 有时需要在某个指定的时间执行一个操作&#xff0c;此时就要使用计划任务了。计划任务有两种&#xff1a; 一个是at计划任务&#xff0c;另一个是 crontab计划任务。 下面我们分别来看这两种计划…

深度学习——第3章 Python程序设计语言(3.7 matplotlib库)

3.7 matplotlib库 目录 1 matplotlib库简介 2 pyplot的plot函数 3 matplotlib基础绘图函数示例 数据可视化有助于深度理解数据。 本节介绍绘制图形的基本方法。 1. matplotlib库简介 matplotlib官网 1.1 matplotlib库概述 matplotlib是Python优秀的数据可视化第三方库&a…

PyQt6 表单布局Form Layout (QFormLayout)

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计43条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

easyexcel根据模板下载文件

为什么要使用EasyExcel easyExcel是阿里巴巴下在POI的基础上二次开发的开源api&#xff0c;以使用简单、节省内存著称。 POI由于在操作excel时是先将所有数据都读入内存后&#xff0c;再写入文件&#xff0c;比较消耗内存&#xff0c;特别是大数据量时&#xff0c;容易出现OOM…

(分页模拟)简单模拟操作系统分页管理

简单模拟一下内存分页&#xff0c;分配和回收。这里我就用最最最简化的方式没有技术含量。 每个进程维护一张页表&#xff0c;然后操作系统用位示图模拟内存分配情况(0: 未分配&#xff0c;1已经分配) import java.util.*;public class Main {public static int PAGE_COUNT …

Weblogic 数据库连接池溢出解决方法

引言 在信息运维工作中发现&#xff0c;由于部分应用系统编写的代码不够健壮&#xff0c;对于数据库连接没有及时进行回收处理&#xff0c;造成Weblogic数据库连接池溢出&#xff0c;影响系统的稳定运行。其实Weblogic提供了数据库连接的回收机制&#xff0c;可以将超过配置时…

基于redisson实现发布订阅(多服务间用避坑)

前言 今天要分享的是基于Redisson实现信息发布与订阅&#xff08;以前分享过直接基于redis的实现&#xff09;&#xff0c;如果你是在多服务间基于redisson做信息传递&#xff0c;并且有服务压根就收不到信息&#xff0c;那你一定要看完。 今天其实重点是避坑&#xff0…

【华为数据之道学习笔记】3-9以特征提取为核心的非结构化数据管理

随着业务对大数据分析的需求日益增长&#xff0c;非结构化数据的管理逐 渐成为数据管理的重要组成部分。非结构化数据包括无格式文本、各类格式文档、图像、音频、视频等多种异构的格式文件&#xff0c;较之结构化数据&#xff0c;其更难标准化和理解&#xff0c;因此在存储、检…

第二证券:结构性行情或将延续 泛科技有望继续走强

展望未来&#xff0c;当时已进入重要的方针窗口期&#xff0c;能否有超预期的新方针推出是改变商场的要害。但复盘2023年的行情来看&#xff0c;过早买卖方针预期的成功率并不高&#xff0c;因而主张该方位以防御性资产为主&#xff0c;高股息资产从本年9月份至今现已调整了2个…

MMdetection3.0 训练DETR问题分析

MMdetection3.0 训练DETR问题分析 针对在MMdetection3.0框架下训练DETR模型&#xff0c;验证集AP值一直为0.000的原因作出如下分析并得出结论。 条件&#xff1a; 1、NWPU-VHR-10数据集&#xff1a;共650张&#xff0c;训练&#xff1a;验证611&#xff1a;39&#xff1b; 2、…

K8S学习指南(11)-k8s中配置pod的服务质量(QOS)

文章目录 前言什么是服务质量&#xff08;QoS&#xff09;&#xff1f;如何配置服务质量&#xff1f;CPU资源配置示例 内存资源配置示例 服务质量等级的判断服务质量的最佳实践结论 前言 Kubernetes&#xff08;简称K8s&#xff09;是一种开源的容器编排平台&#xff0c;用于简…

Linux vmstat命令:监控系统资源

vmstat命令&#xff0c;是 Virtual Meomory Statistics&#xff08;虚拟内存统计&#xff09;的缩写&#xff0c;可用来监控 CPU 使用、进程状态、内存使用、虚拟内存使用、硬盘输入/输出状态等信息。此命令的基本格式有如下 2 种&#xff1a; [rootlocalhost ~]# vmstat [-a…

FFmpeg-基础组件-AVFrame

本章主要介绍FFmpeg基础组件AVFrame. 文章目录 1.结构体成员2.成员函数AVFrame Host内存的获取 av_frame_get_bufferAVFrame device内存获取av_hwframe_get_buffer&#xff08;&#xff09; 1.结构体成员 我们把所有的代码先粘贴上来&#xff0c;在后边一个一个解释。 typede…

SpringBoot中实现跨域的几种常用方式

在SpringBoot中实现跨域请求可以通过以下几种方式&#xff1a; 1. 使用CrossOrigin注解&#xff0c;可以直接在Controller层的方法上使用&#xff0c;用来指定允许跨域请求的来源、方法和头信息。例如&#xff1a; CrossOrigin(origins "http://localhost:8080") …

[MySQL]SQL优化之sql语句优化

&#x1f308;键盘敲烂&#xff0c;年薪30万&#x1f308; 目录 一、索引优化 回顾&#xff1a; &#x1f4d5;索引分类&#xff1a; &#x1f4d5;索引失效&#xff1a; &#x1f4d5;设计原则&#xff1a; &#x1f4d5;SQL性能分析 二、SQL优化 语句优化 &#x1f4d…

越南语翻译,人工翻译哪个值得信赖?

近年来&#xff0c;随着中越两国的交流日益频繁&#xff0c;为了促进双方的交流与理解&#xff0c;市场上对越南语翻译的需求也日益增加。那么&#xff0c;如何做好越南语翻译&#xff0c;人工翻译哪家公司值得信赖呢&#xff1f; 据了解&#xff0c;中文翻译越南语是一项颇具挑…

科技与艺术相结合,虚拟人裸眼3D动画亮相城市商圈

随着元宇宙概念的火爆&#xff0c;虚拟制作技术的快速发展&#xff0c;虚拟人可以将虚拟世界与现实世界相结合&#xff0c;为用户带来沉浸式体验。如虚拟人壬子希以裸眼3D动画的形式亮相城市商圈&#xff0c;助力文旅以科技与艺术相结合的形式&#xff0c;展现城市文化与科技成…

从运维角度去了解redis

一、介绍 1.简介 redis是一个开源的、使用C语言编写的、可基于内存也可持久化的Key-Value数据库&#xff0c;采用单线程基于epoll模型实现IO多路复用非阻塞的处理模式。 2.特点 1.丰富的数据结构 -----Redis支持五种数据类型&#xff1a;string&#xff08;字符串&#xf…

【数据结构(九)】顺序存储二叉树(2)

文章目录 1. 相关概念2. 顺序存储二叉树的遍历 1. 相关概念 从数据存储来看&#xff0c;数组存储方式和树的存储方式可以相互转换&#xff0c;即数组可以转换成树&#xff0c;树也可以转换成数组&#xff0c;看右面的示意图。 转换原则:     1.上图的二叉树的结点&#xff…