【Linux】调试器 - gdb 的使用

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

一、背景知识

二、debug 与 release

1、生成两种版本的可执行程序

2、debug 与 release 的区别

三、gdb 的使用

1、调试指令与指令集

2、源代码显示、运行与退出调试

3、断点操作

4、逐语句与逐过程

5、调试过程中的数据监视

6、调试过程中快速定位问题


一、背景知识

我们在Linux上编写代码后也希望能够同 vs 上一样可以进行代码调试这时我们就需要一个调试工具名为 gdb

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

二、debug 与 release

1、生成两种版本的可执行程序

我们首先编写一个简单的累加程序

补充知识因为老版的 c89 或 c90 标准的C语言语法不支持在 for 语句的括号内定义变量因此我们需要在 Makefile 中的依赖方法里增加一个选项 -std=c99

 程序编写完成后我们使用 gcc/g++ 编译出的可执行程序默认是 release 版本的。为了方便区分我们先把第一次编译出的可执行程序重命名为 mytest-release


gcc/g++ debug 方式编译程序

gcc -g 

我们修改一下 Makefile 

此时我们再次编译出的可执行程序就是 debug 版本的了。为了方便区分我们把第二次编译出的可执行程序重命名为 mytest-debug

debug版本和release版本的可执行程序都是能够正常执行的。

2、debug 与 release 的区别

为什么 debug 版本的程序可以调试而 release 版本的不可以呢

这是因为以 release 版本发布的软件是给客户使用的而客户不需要调试信息。如果在程序里增加了大量的调试信息不仅该程序的体积会变大而且运行速度也会变慢给客户的使用体验不好。

而 debug 版本是给程序员使用的程序员需要通过调试信息来调试程序。所以在程序里增加调试信息是非常有必要的。


读取可执行程序的二进制构成的指令

readelf -S [可执行程序]

搜索调试信息的指令

readelf -S [可执行程序] | grep debug

查看 mytest-debug 的调试信息 

查看 mytest-release 的调试信息

 可以非常直观的看到 debug 版本的可执行程序里包含调试信息而 release 版本的可执行程序里没有包含。

三、gdb 的使用

1、调试指令与指令集

gdb [debug版本可执行程序]

 当出现如上字样时gdb调试的准备工作就已经完成。

指令集

  • list / l 行号显示可执行程序源代码接着上次的位置往下列每次列10行。
  • list / l 函数名列出某个函数的源代码。
  • r / run运行程序。
  • n / next单条执行。
  • s / step进入函数调用
  • break(b) 行号在某一行设置断点
  • break 函数名在某个函数开头设置断点
  • info break 查看断点信息。
  • finish执行到当前函数返回然后挺下来等待命令
  • print(p)打印表达式的值通过表达式可以修改变量的值或者调用函数
  • 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)查看各级函数调用及参数
  • infoi) locals查看当前栈帧局部变量的值
  • quit退出gdb

gdb会记住最近一次执行的指令。比如当我们使用指令 l 来查阅下面 10 行代码后只需要再按 enter 键就可以继续执行 l 指令的功能。


2、源代码显示、运行与退出调试

list / l 行号显示源代码


 r / run运行程序

 因为没有设置断点所以程序正常执行正常退出。

 quit 退出调试


3、断点操作

break(b) 行号在某一行设置断点

break(b) 函数名在某个函数开头设置断点

 info b查看断点

 在屏幕上显示断点信息从左到右依次为

  • Num断点编号。从 1 开始依次递增
  • Enb断点使能。y 为打开 n 为关闭
  • what说明这个断点的位置等信息

 这时我们再输入命令 r 运行程序程序就会在断点处停下

 同时显示断点已经被命中了一次。

disable breakpoint [断点编号]关闭断点使能

 enable breakpoint [断点编号]打开断点使能

 关闭断点使能在不删除断点的条件下使断点不生效。

 d [断点编号] 删除指定断点

 编号为 1 的断点被删除。

 d break 删除所有断点


4、逐语句与逐过程

 n / next 逐过程。类比到 vs 中的 F10 一步可以走过一个函数。

 直接执行完 addToTop 函数并且该函数中的内容也被打印出来。执行完毕后显示当前行号及当前行内容。

 s / step 逐语句。类比到 vs 中的 F11逐条语句调试遇到函数会跳转到函数内。

 跳转到 addToTop 函数内的第一行语句显示当前行号及当前行内容。

因为在一个程序中可能会出现 A 函数调用 B 函数B 函数调用 C 函数的情况。所以我们有时希望看到当前程序中函数的调用链。

 bt 查看当前的调用链

 因为函数调用是一个压栈的过程所以我们可以看到 addToTop 函数被压栈到了 main 函数之上。


5、调试过程中的数据监视

 p [变量名/地址] 暂时查询变量

 可以查看当前时刻变量的内容及地址等信息。在显示时会给 被显示变量 一个编号编号以 $ 开头从 1 开始递增。 p 命令每使用一次就打印一次变量信息。

 display [变量名/地址] 常显示变量内置类型 结构体等自定义类型stl

 只需要设置一次接下来每次操作都会显示 已设置变量 的当前时刻的信息。

 undisplay [编号] 取消常显示

 被取消常显示的变量在接下来执行程序时不再被显示。


6、调试过程中快速定位问题

 until [行号] 在函数内进行指定行位置跳转执行完区间代码

 直接执行完了程序 12 行之前的所有代码并且停留在第 12 行。

 finish 进入一个函数只执行完该函数就停下来

当已经进入一个函数后该函数中没有任何断点。就跑完当前函数停下来等待命令。

 执行完函数后返回结果。

 continue / c 从一个断点处直接运行至下一个断点处

 直接运行至下一个断点处并把运行过程打印了出来。


 set var n=XXX设置某一个变量为特定的值

 直接把 i 的值设为了 90。


以上就是Linux调试器 gdb 的全部内容同学们要多上手边操作边学习。本章的内容就讲到这里希望同学们多多支持如果有不对的地方欢迎大佬指正谢谢

 

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: linux

“【Linux】调试器 - gdb 的使用” 的相关文章