Linux | 调试器GDB的详细教程【纯命令行调试】-1

简介: Linux | 调试器GDB的详细教程【纯命令行调试】

一、前言

  • 学习了【vim】知道了如何编辑一个代码文本
  • 学习了【gcc】知道了如何编译一个代码文本
  • 学习了【make/Makefile】知道了如何自动化构建一个代码文本

但是如何对一段代码去进行调试呢,此时就要使用到Linux下的调试器gdb了。对于这个调试器来说,不像是VS中那样的图形化界面形式,而是采用纯命令行的形式进行调试。可能我的讲解会比较晦涩难懂,在学习的过程中主要是会一些gdb下基本的操作即可

二、调试版本与发布版本

1、见见gdb

下面是本次调试所要使用到的代码

  1 #include <stdio.h>
  2 
  3 int AddToTop(int top)
  4 {
  5     printf("Enter AddToTop\n");
  6 
  7     int count = 0;
  8     for(int i = 1;i <= top; ++i)
  9     {
 10        count += i;
 11     }
 12 
 13     printf("Quit AddToTop\n");                                                                         
 14     return count;
 15 }
 16 
 17 int main(void)
 18 {
 19     int top = 100;
 20     int ret = AddToTop(top);
 21 
 22     printf("ret = %d\n", ret);
 23     return 0;
 24 }

下面是Makefile中的内容,用于自动化编译

  1 mytest:test.c
  2     gcc -o mytest test.c -std=c99                                                                      
  3 .PHONY:clean
  4 clean:
  5     rm -rf mytest

注:-std=c99表示以c99的标准来编译代码


  • 如果要进入gdb开始调试,那直接gdb + 可执行程序即可
  • 不过进去之后发现似乎有一些奇怪的内容,【no debugging symbols found】,翻译过来就是没有调试信息。那这是为何呢?是gdb出问题了吗?

image.png

  • 先不要着急,如果有经常调试的通过就可以知道只有在【DeBug】的环境下才会有我们想要的调试信息,所以可以初步推断这可能不是一个【DeBug】版本的可执行程序
  • 先使用q(quit)退出gdb

让我们先看下去,了解一下其他的知识再来解决这个问题

2、程序员与测试人员

接下去我们就来说说有关【DeBug】和【Release】版本的不同之处

📚【Debug】—— 调试版本📚【Release】—— 发布版本

  • 在使用VS的时候我们可以直接使用鼠标来进行操作,当前程序以DeBug或者是Release的形式进行运行,那么运行出来的可执行程序版本也是不同的,我们程序员在编写代码后运行一般是使用【DeBug】环境进行运行。因为在企业里写软件项目,将代码写完后==程序员自己要做简单的测试,保证代码没有问题==
  • 当程序员自己测试完没有问题之后,就会将这个可执行程序给到测试人员进行测试,而且会给出自己的单元测试报告。对于测试人员来说所处的模式是【Release】,也就是将来客户要使用的这款软件的发布版本
  • 当测试在测的过程中,一定会发现一些问题。此时测试人员就会把报告再打回研发部。研发部做修改重新生成Release版本的可行性程序给到测试人员继续测试
  • 最后只有当测试通过了,再将生成的【单元测试报告】与产品经理进行核对之后没有问题,那这个软件才可以真正地面向市场👉

3、为什么Release不能调试但DeBug可以调试❓

其实对于我们刚才直接make自动化生成的可执行程序是通过gcc直接编译产生得到的,它是一个【Release】版本的可执行程序,因此无法进行调试

  • 若是我们想要使用gcc/g++去生成一个可执行程序时,默认是【Release】版本的,而不是【DeBug】
  • 但若是我们想要去生成一个【DeBug】版本的可执行程序也是可以的,只需要修改一下我们的Makefile即可,给gcc后面带上一个-g的命令选项,此时再去make一下的话生成的就是【DeBug】版本的了

  • 为了之前的【Release】版本不被覆盖,我们将其重命名一下为mytest-release
  • 在生成【DeBug】版本后一样对其进行一个重命名为mytest-debug

image.png

  • 通过观察上图中两个可执行文件的大小便可以发现虽然它们都是可执行程序,但是容量大小却不一样,这是为什么呢❓
  • 因为以Release版本发布的软件是给客户的,客户是不需要调试信息
  • 往可执行程序里添加很多的调试信息意味着软件的体积会变大
  • 一方面,用户下载需要时间了
  • 另一方面,用户下载好之后将软件启动、运行都需要更多的时间,体验不好。一般能不加就不加
  • 但是对于DeBug来说会自动加调试信息,容量体积比Release大

但是就这么说说太抽象了,我们得看看这个可执行文件里的调试信息究竟是怎样的💻

readelf -S mytest-debug

image.png

当我们面对一堆二进制乱码措手不及的时候,给大家提到过一个东西叫做readelf,其实它是Linux中的一个指令,可以用来读取【elf】格式的文件

  • 加上-S的命令选项以==符号表==的形式来进行读取这个文件,就以一个列表的形式展现出了这个带调试信息的可执行程序
  • 下面展现几个比较常见的。例如这里的
  • .rodata就是read only data即只读全局数据区
  • .data就是已初始化全局数据区
  • .bss就是未初始化全局数据区

image.png

  • 不过这些呢是这个可执行文件中的所有内容,若是我们只是先要查看一些debug的调试信息,就要对这些东西进行一个筛选才行
  • 此时就可以使用到grep命令来进行一个筛选。便可以查看到所有的debug调试信息了

image.png

  • 上面是查看【DeBug】版本下的调试信息,在【Release】版本有没有呢
  • 我们也是读取并搜寻一下这个文件便可以发现对于【Release】版本来说是不存在调试信息的,所以什么都没有被打印出来

image.png【总结一下】

  • 程序的发布方式有两种,debug模式和release模式
  • Linux gcc/g++出来的二进制程序,默认是release模式
  • 要使用gdb调试,必须在源代码生成二进制程序的时候, 加上-g选项

好,说到这里,对于调试相关背景就全部讲完了,接下去我们正式进入【gdb】的学习:keyboard:

三、使用gdb调试代码

1、指令集汇总

因为这个调试器是在Linux环境下的,是纯命令行模式,所以会有很多的指令,做好心里准备:cry:

注:()括号里面是该指令的全称

  • l(list) 行号/函数名 —— 显示对应的code,每次10行
  • r(run) —— F5【无断点直接运行、有断点从第一个断点处开始运行】
  • b(breakpoint) + 行号 —— 在那一行打断点
  • b 源文件:函数名 —— 在该函数的第一行打上断点
  • b 源文件:行号 —— 在该源文件中的这行加上一个断点吧
  • info b —— 查看断点的信息
    breakpoint already hit 1 time【此断点被命中一次】
  • d(delete) + 当前要删除断点的编号 —— 删除一个断点【不可以d + 行号】
  • 若当前没有跳出过gdb,则断点的编号会持续累加
  • d + breakpoints —— 删除所有的断点
  • disable b(breakpoints) —— 使所有断点无效【默认缺省】
  • enable b(breakpoints) —— 使所有断点有效【默认缺省】
  • disable b(breakpoint) + 编号 —— 使一个断点无效【禁用断点】
  • enable b(breakpoint) + 编号 —— 使一个断点有效【开启断点】
  • 相当于VS中的空断点
  • enable breakpount —— 使一个断点有效【开启断电】
  • n(next) —— 逐过程【相当于F10,为了查找是哪个函数出错了】
  • s(step) —— 逐语句【相当于F11,】
  • bt —— 看到底层函数调用的过程【函数压栈】
  • set var —— 修改变量的值
  • p(print) 变量名 —— 打印变量值
  • display —— 跟踪查看一个变量,每次停下来都显示它的值【变量/结构体..】
  • undisplay + 变量名编号 —— 取消对先前设置的那些变量的跟踪

排查问题三剑客🗡

  • until + 行号 ——  进行指定位置跳转,执行完区间代码
  • finish —— 在一个函数内部,执行到当前函数返回,然后停下来等待命令
  • c(continue) —— 从一个断点处,直接运行至下一个断点处【VS下不断按F5】

2、命令演示

看了上面的这些命令后,相信你一定回到了刚开始学习Linux指令的时候那种恐惧感,不过没关系,我会一一地演示这些指令,让你在看完本文后有一个基本的调试能力💪

  • 首先我们进入到gdb,然后它会等待我们输入指令

image.png

⌨ 行号显示

l(list) 行号/函数名 —— 显示对应的code,每次10行

  • 首先若是直接【L】的话便会随机显示出该源文件中的随机10行内容,这不是我们想要的

image.png

  • 若是【L 0】或者是【L 1】的话那就是从第一行开始往下列10行的内容
  • 注意这里的L是小写,而且与数字之间要有一个空格

image.png

  • 接下去若是想要看到我们所写的全部代码,只需要多Enter几次就可以了,gdb会自动记忆你上次敲入的指令

image.png

⌨ 断点设置

b + 行号 —— 在那一行打断点

image.pngb 源文件:函数名 —— 在该函数的第一行打上断点

image.png

b 源文件:行号 —— 在该源文件中的这行加上一个断点

image.png

⌨ 查看断点信息

info b —— 查看断点的信息

  • 若是直接执行【info】的话,出来的就是所有的调试信息

image.png

  • 但若是我们只想查看一下所打的断点的信息,那就在后面加个b/breakpoint

image.png来简要介绍一下断点的一些字段信息

  • Num —— 编号
  • Type —— 类型
  • Disp —— 状态
  • Enb —— 是否可用
  • Address —— 地址
  • What —— 在此文件的哪个函数的第几行

image.png

  • 最后的话就是每个断点信息的下面这块breakpoint already hit 1 time即此断点被命中1次

⌨ 删除断点

d + 当前要删除断点的编号 —— 删除一个断点【不可以d + 行号】

image.pngd + breakpoints —— 删除所有的断点

image.png

  • 此时若继续将这个20行的断点打上时,就可以发现其编号为【4】,而并不是从1开始,这是因为我们没有退出过gdb,所以会持续上一次的编号继续往下

image.png

⌨ 开启 / 禁用断点

disable b(breakpoints) —— 使所有断点无效【默认缺省】

image.pngenable b(breakpoints) —— 使所有断点有效【默认缺省】

image.pngdisable b(breakpoint) + 编号 —— 使一个断点无效【禁用断点】

image.pngenable b(breakpoint) + 编号 —— 使一个断点有效【开启断点】

image.png

其实对于禁用断点和启用断点,VS中也是有的,它叫做【空断点】。我们一起来看看

image.pngimage.png


相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
16小时前
|
NoSQL Linux 编译器
【Linux工具篇】调试器gdb
【Linux工具篇】调试器gdb
5 0
|
4天前
|
弹性计算 安全 Linux
阿里云ECS Linux系统漏洞修复详细教程
阿里云ECS Linux系统漏洞修复详细教程
|
8天前
|
域名解析 运维 网络协议
Linux命令行全景指南:从入门到实践,掌握命令行的力量
Linux命令行全景指南:从入门到实践,掌握命令行的力量
68 0
|
10天前
|
弹性计算 Ubuntu Linux
2024年幻兽帕鲁/palworld云主机开服教程(Linux/Centos)
在帕鲁的世界中,与神奇的生物共度悠闲时光是一种无与伦比的乐趣。然而,有时官方服务器的不稳定性可能会给游戏体验带来延迟和卡顿。 为了告别这些问题,部署自己的幻兽帕鲁服务器成为了一个不错的选择。通过搭建专属的游戏服务器(Dedicated Server),和小伙伴们获得一个专属的服务空间,获得顺畅流畅的游戏体验。 在本文中,我们将介绍如何使用自己的服务器来部署属于自己的幻兽帕鲁服务器,与小伙伴们共同展开一场精彩的冒险之旅。
|
10天前
|
弹性计算 Ubuntu Linux
2024年Windows/Linux搭建幻兽帕鲁主机教程(超详细图文)
幻兽帕鲁作为一款热门多人在线游戏,为了给玩家提供稳定、流畅的联机体验,阿里云提供了高效便捷的快速部署解决方案,本文将为大家介绍阿里云一键部署幻兽帕鲁联机服务器详细教程。
|
17天前
|
弹性计算 Linux 数据安全/隐私保护
1分钟幻兽帕鲁社区服务器搭建架设开服教程(Linux)
1分钟幻兽帕鲁社区服务器搭建架设开服教程(Linux)玩转幻兽帕鲁服务器,幻兽帕鲁Palworld多人游戏专用服务器一键部署教程,阿里云推出新手0基础一键部署幻兽帕鲁服务器教程,傻瓜式一键部署,3分钟即可成功创建一台Palworld专属服务器,成本仅需26元,阿里云百科分享2024年新版基于阿里云搭建幻兽帕鲁服务器教程
41 3
|
19天前
|
Ubuntu Java Linux
百度搜索:蓝易云【java环境搭建Ubuntu Linux教程】
现在你已成功在Ubuntu Linux上搭建了Java环境,可以开始开发Java应用了。
26 6
|
20天前
|
Ubuntu Linux
百度搜索:蓝易云【Linux平台下构建TigerVNC项目教程】
至此,你已经成功在Linux平台下构建并安装了TigerVNC项目。现在你可以启动VNC服务器并通过VNC客户端连接到远程桌面。请注意,上述步骤仅适用于一般情况,具体的构建步骤可能会因为不同的系统环境和版本而有所不同。在实际操作中,可能还需要根据实际情况进行一些调整。
25 1
|
20天前
|
NoSQL Linux
Linux下的系统编程——gdb调试工具(三)
Linux下的系统编程——gdb调试工具(三)
39 0
Linux下的系统编程——gdb调试工具(三)
|
27天前
|
NoSQL 编译器 Linux
Linux——编译器gcc/g++、调试器gdb以及自动化构建工具makefile&&make详解
Linux——编译器gcc/g++、调试器gdb以及自动化构建工具makefile&&make详解

相关产品

  • 云迁移中心