【Linux】Linux下的调试器-gdb的使用

我们平常调试C/C++代码大多实在Windows平台下的VS中,在LInux中,我们通常使用gdb来调试代码,虽然我们很少在LInux上对代码进行调试,gdb在实际的使用中用的较少,但我们必须要懂它,以面对各种环境。

本文目的:能够进行基本的掌握单进程程序的调试,即使用VS 2019、VS 2022的基本调试功能,都在Linux上使用gdb实现。

本文会在Linux环境下使用到vim编辑器make/Makefilegcc/g++,如果对这三个工具不熟悉,可点击下面的链接,结合本文一起学习。
vim编辑器
make/Makefile
gcc/g++

1.debug和release

在学习Linux下使用gdb调试之前,我们需要掌握以下三个有关debug和release模式的铺垫知识

  1. 程序的发布方式有两种,debug模式和release模式

    debug模式:该模式是程序员编写程序和调试代码的模式,该模式下生成的可执行程序含有调试信息体积要大于release模式生成的可执行程序

    release模式:没有调试信息,对程序做出优化,减小了程序的体积,更适合用户使用。该模式下生成的可执行程序是公司最终要推向市场的,由公司内测试人员测试是否完善,测试通过后推向市场。

    • 注意: debug模式下可以调试,release模式下无法调试。

    下图是VS 2019下,两种模式的选择图,需要那种模式选择那种模式即可
    在这里插入图片描述
    那在Linux下如何进行两个模式的转换呢?

  2. Linux下,gcc/g++出来的二进制可执行程序,默认是release模式

    • 在Linux下,使用常规的指令生成可执行程序为release模式,无法进行调试
    //常规生成
    gcc -o 可执行文件名 源代码文件
    g++ -o 可执行文件名 源代码文件
    
  3. 要使用gdb调试,必须在使用gcc/g++生成二进制程序时,加上-g选项

    gcc -o 可执行文件名 源代码文件 -g
    g++ -o 可执行文件名 源代码文件 -g
    

下面我们在如下test.c文件下编辑测试代码,进行测试
在这里插入图片描述
注意: 第7行代码,在for循环内定义变量i,这种写法是在c99中开始支持的,我使用的gcc/g++编辑器不支持这种写法,需要在执行命令后添加-std=c99

Makefile文件如下:
在这里插入图片描述
若不会使用Makefile文件,可直接使用如下两条指令测试

gcc -o MyTest-debug test.c -g -std=c99     //生成debug模式的可执行文件
gcc -o MyTest-release test.c -std=c99     //生成release模式的可执行文件

首先,测试release模式下,是否可以调试
在这里插入图片描述
如上图显示,红色框内,表示没有找到调试符号,无法进行调试。

其次,测试debug模式下,是否可以调试

在这里插入图片描述
没有显示错误信息,可以正常调试

最后: 观察两个可执行文件的体积,明显debug要大于release
在这里插入图片描述

拓展

我们可以使用readlef指令查看两个可执行文件下的信息,如下:

在这里插入图片描述
我们可以通过该指令,查看两个文件下的debug信息,如下(grep 指令为查找字符串指令):
在这里插入图片描述
MyTest-debug文件下找到了debug信息,MyTest-release什么都没有。

2.如何使用gdb调试

调试器的核心工作:定位问题

接下来简绍在Linux下如何使用gdb进行调试,该段落为分步骤讲解,将gdb下的命令总结放在了下一段落。
如果大家对gdb并不属性,按步骤操作即可

  1. 进入调试

    使用gdb file指令进入调试模式,如下图
    在这里插入图片描述

  2. 显示要调试的代码

    • l/list 行号:显示文件源代码,从输入的行号起,向下列出十行。一般我们在开始调试时,从l 1开始查看,接着输入lEnter键,即可获得上次查找位置往下的代码
      在这里插入图片描述
      注意: 输入gdb的指令后,Enter键就会记录。即,输入指令后,接着输Enter键会重复上面的动作。下面的指令也遵循这个规则。
    • 在刚进入gdb模式后,单独使用l进行查看,显示的代码为随机的
      在这里插入图片描述
  3. 设置断点

    • break/b 行号:在某一行设置断点

      如下图,在19行设置断点

    • break/b 函数名:在某个函数开头设置断点

      如下图,在addTestTop函数处设置断点

      在这里插入图片描述

      5是addTestTop函数内第一行代码的行号。

    • break/b 文件名:函数名:多文件时,可使用该方法设置断点

    • info break/b:查看断点信息

      在这里插入图片描述

      当程序运行后,会在断点处停下,在次查看断点,会显示在该断点处停下的次数。

      在这里插入图片描述

    注意: 在gdb中断点的序号是增长的,每次使用后会不断增长,直到关闭在开启后,重新从1开始

  4. 运行程序

    • r/run:运行程序

      • 有断点的情况,运行到断点处停止
        在这里插入图片描述
      • 无断点的情况,直接运行完 在这里插入图片描述
    • 注意: 一次运行是在全部main函数内全部代码运行完后结束,中途遇到断点停下后,进行其他查看指令不会影响此次调试

  5. 有断点,运行后,逐语句执行

    • s/step:遇到函数,进入函数内部

      在这里插入图片描述

    注意: 进入其他函数后,会产生调用链,即一个函数调用另一个函数,接着再去调用其他函数。

    可通过bt指令查看

    在这里插入图片描述

  6. 有断点,运行后,逐过程运行

    • n/next即遇到函数不进入函数,直接执行下一条指令

    在这里插入图片描述

    • 还记得上面说的按Enter键,执行上次执行的指令吗?如果需要调试的的内容过多,按一次sn后接着按Enter键即可
  7. 删除断点

    • delete/d breakpoints:删除所有断点

      在这里插入图片描述

    • delete/d n:删除序号为n的断点

      在这里插入图片描述

  8. 打开和关闭断点

    当我们不想使用一个断点,也不想删除该断点时使用

    • disable breakpoint 断点序号:关闭断点

      在这里插入图片描述

    • enable breakpoint 断点序号:打开断点

      在这里插入图片描述

  9. 查看变量

    • p 变量名:这个指令是需要查看的时候输入,不会影响调试,如下我在调试进入addTestTop函数后,执行了几段语句后,查看sum变量的结果,此时sum为6.

      在这里插入图片描述

    • 这样查看的效率太低,我们在VS中使用调试时,是执行一次相对应的变量随之变化,可以直接查看,该方法需要用户自己调用,不方便,我们可以使用以下的方法

  10. 跟踪查看变量

    • display 变量名:执行后,该变量在每执行一个语句后,都会显示出来

      在这里插入图片描述

    • 可以显示内置类型、结构体等自定义类型、stl

  11. 取消对断点的跟踪

    • undisplay 序号:不想跟踪某变量时使用

      在这里插入图片描述

  12. 跳转至指定行

    • until 行号:跳转至X行,在我们上面的代码中有一个循环,我们可以使用该指令跳转出循环
      在这里插入图片描述
  13. 将整个函数跑完

    • finash:进入一个函数后执行,只执行该函数,执行完后停下

    在这里插入图片描述

  14. 从一个断点,到下一个断点

    • continue/c:直接运行到下一个断点处

      在这里插入图片描述

    • util、finish、continue结合后,可实现基本的调试功能

  15. 退出gdb

    • q/quit:如果正在调试,会提示是否需要退出

    在这里插入图片描述

3.指令集

gdb binFile 退出: ctrl + dquit/q 调试命令:

  • list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
  • list/l 函数名:列出某个函数的源代码。
  • r或run:运行程序。
  • n 或 next:单条执行。
  • s或step:进入函数调用
  • break(b) 行号:在某一行设置断点
  • break 函数名:在某个函数开头设置断点
  • info break :查看断点信息。
  • finish:执行到当前函数返回,然后挺下来等待命令
  • print§:打印表达式的值,通过表达式可以修改变量的值或者调用函数
  • p 变量:打印变量值。
  • set var:修改变量的值
  • continue(或c):从当前位置开始连续而非单步执行程序
  • run(或r):从开始连续而非单步执行程序
  • delete breakpoints:删除所有断点
  • delete breakpoints n:删除序号为n的断点
  • disable breakpoints:禁用断点
  • enable breakpoints:启用断点
  • info(或i) breakpoints:参看当前设置了哪些断点
  • display 变量名:跟踪查看一个变量,每次停下来都显示它的值
  • undisplay:取消对先前设置的那些变量的跟踪
  • until X行号:跳至X行
  • breaktrace(或bt):查看各级函数调用及参数
  • info(i) locals:查看当前栈帧局部变量的值
  • quit:退出gdb

猜你喜欢

转载自blog.csdn.net/m0_52094687/article/details/128748413