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

news/2024/7/7 19:48:07

介绍:

        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://lihuaxi.xjx100.cn/news/1885967.html

相关文章

Goby 漏洞发布| 亿赛通电子文档安全管理系统 LinkFilterService 接口权限绕过漏洞

漏洞名称&#xff1a;亿赛通电子文档安全管理系统 LinkFilterService 接口权限绕过漏洞 English Name&#xff1a;Esafenet Electronic Document Security Management System LinkFilterService API Permission Bypass Vulnerability CVSS core: 9.3 影响资产数&#xff1a;…

Python核心编程之映射和集合类型

目录 一、映射类型:字典 核心笔记:什么是哈希表?它们与字典的关系是什么?

数据库中常用的锁

目录 1、数据库中常用的锁类型 2、常见的数据库 3、以MySQL为例 3.1 MySQL的事务 3.2 MySQL事务的四大特性 1. 原子性&#xff08;Atomicity&#xff09; 2. 一致性&#xff08;Consistency&#xff09; 3. 隔离性&#xff08;Isolation&#xff09; ⭐mysql中的事务隔…

unity Pc获取本机Mac地址

1.此方法只能获取众多Mac中的一个 private static string GetMacAddress(){string physicalAddress "";NetworkInterface[] nice NetworkInterface.GetAllNetworkInterfaces();foreach (NetworkInterface adaper in nice){Debug.Log(adaper.Description);if (adape…

2台MySQL 8.0快速配置主从同步

在MySQL 8.0中设置主从同步&#xff0c;并启用GTID&#xff08;全局事务标识符&#xff09;&#xff0c;可以按照以下详细步骤进行&#xff1a; 1. 准备主服务器 编辑MySQL配置文件&#xff08;通常是my.cnf或my.ini&#xff09;&#xff1a; [mysqld] server-id 1 log_bin …

使用 array_filter 对数据进行处理

目标格式&#xff1a; 目前的格式: 使用 array_filter 对数据进行处理 &#xff1a; public function teamOrderDetail($goodId){$goodIds explode(,,$goodId);$data [];foreach ($goodIds as $id){$data[] $this->order->where(good_id,$id)->field("user_…

Linux安装MySQL数据库系统

1、MySQL的编译安装。 1.1、准备工作 &#xff08;1&#xff09;为了避免发生端口冲突、程序冲突等现象&#xff0c;建议先查询MySQL软件的安装情况&#xff0c;确认没有使用以RPM方式安装的mysql-server、mysql软件包&#xff0c;否则建议将其卸载。 [rootlocalhost ~]# rp…

【Hive】——CLI客户端(bin/beeline,bin/hive)

1 HiveServer、HiveServer2 2 bin/hive 、bin/beeline 区别 3 bin/hive 客户端 hive-site.xml 配置远程 MateStore 地址 XML <?xml version"1.0" encoding"UTF-8" standalone"no"?> <?xml-stylesheet type"text/xsl" hre…