Linux 调试器 gdb

2023年 10月 11日 75.8k 0

一. 程序的两种发布方式

debug & release

  • debug 版本 : 程序本身会被加入更多的调试信息, 以便于调试.

  • release 版本 : 不会添加任何调试信息, 不可调试.

gdb [可执行文件名] 进入调试页面.

但是我们发现 Linux 会发出 no debugging symbols found (没有找到调试符号) 的信息.

image.png

这是因为在 Linux 下 gcc 默认生成的可执行程序是 release 版本的, 是不可被调试的. 如果想生成 debug 版本, 就需要在使用 gcc 生成可执行程序时加上 -g 选项, 生成 debug 版本.

image.png

通过 ll 指令可以看到, 对同一份源代码分别生成其 release 版本和 debug 版本的可执行程序, debug 版本发布的可执行程序的大小比 release 版本发布的可执行程序的大小要大一点, 其原因就是以debug 版本发布的可执行程序当中包含了更多的调试信息.

image.png

readelf 指令

Linux 有一个很不错的工具叫 readelf, 它是专门针对 ELF 文件格式的解析器, gdb 所调试的可执行文件就是 ELF 文件, readelf -S [ELF格式文件] 查看 ELF 文件的段表 (Section Table).

readelf -S hello-debug | grep debug 查看可执行文件 hello-debug 中与调试信息有关的段.

image.png

readelf -S hello-debug 显示 hello-debug 文件段表.

其中C语言编译过程后执行语句编译所形成的机器代码存放在 .text 段, 已初始化的全局变量和局部静态变量存放在 .data 段, 未初始化的全局变量和局部静态变量存放在 .bss 段.

image.png

下图列举了 ELF 的一些其他常见段.

image.png

二. gdb 命令汇总

进入gdb & 退出gdb

进入 gdb

  • gdb [可执行文件] - 进入gdb

image.png

退出 gdb

  • q(quit) - 退出gdb

image.png

显示

行号显示

  • l(list) 行号 - 显示所调试可执行文件对应的源文件代码, 每次显示10行

若是直接 l, 会随机显示出可执行文件对应源文件中的随机 10 行内容.

image.png

l 1, 会从源文件首行开始显示 10 行内容.

image.png

多次 Enterl 后即可显示源文件全部内容, 因为 gdb 会记忆上次输入的指令, 且若未给出行号则默认从上次的位置往下显示.

image.png

  • l(list) 函数名 - 显示所调试可执行文件对应的源文件代码, 每次显示10行

l Add, 显示对应的 10 行内容.

image.png

打印变量

  • p(print) 变量名 - 打印变量值

image.png

继续单步调试代码, 再打印变量 isum 的值, 发生了改变.

image.png

但是每次打印显示非常麻烦, 于是我们使用跟踪变量的方式.

跟踪 & 取消跟踪变量

  • display 变量名 - 跟踪查看一个变量, 每次单步调试都显示变量的值

image.png

先 display 的变量在下面, 模拟的是一个压栈的过程.

  • undisplay 变量名编号 - 取消对先前设置的那些变量的跟踪

image.png

查看函数调用 & 栈帧

  • bt - 查看各级函数调用及参数

image.png

  • i(info) locals: 查看当前栈帧当中局部变量的值.

image.png

断点

设置断点

  • b(break) 行号 - 在对应行号处打断点

image.png

  • b(break) 函数名 - 在对应函数函数体第一行处打断点

image.png

查看断点信息

  • info(i) b(break) - 查看断点的信息

image.png

如下为显示断点信息的具体含义.

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

提示: 若是在调试过程中命中过断点, 则还会显示断点被命中的次数.

image.png

删除断点

  • d 要删除断点的NUM (不可以 d 要删除断点的行号)

image.png

  • d(delete) break - 删除所有的断点

image.png

此时若继续设置断点, 就可以发现其编号为 4, 而并不是从 1 开始, 这是因为我们没有退出过 gdb, 所以新断点的编号会接着上一次的最大编号继续往下.

image.png

开启 & 禁用断点

  • disable b(breakpoints) - 使所有断点无效

image.png

  • enable b(breakpoints) - 使所有断点有效

image.png

  • disable b(breakpoint) NUM - 使指定断点无效

image.png

  • enable b(breakpoint) NUM - 使指定断点有效

image.png

调试

运行 & 调试

  • r(run) - 无断点直接运行; 有断点从第一个断点处开始运行

无断点, 使用 r 指令运行, 直接运行到程序结束.

image.png

有断点, 使用 r 指令运行, 会在设置断点处停下来.

image.png

逐过程 & 逐语句

  • n(next) - 逐过程调试

逐语句调试, 碰到断点停止, 不进入函数内部.

image.png

  • s(step) - 逐语句调试, 一次走一行代码, 会进入函数内部

进入函数内部, 逐行调试.

image.png

修改变量的值

  • set var 表达式 - 修改变量的值

image.png

指定行号跳转

  • until 行号 - 进行指定位置跳转, 执行完区间代码

image.png

强制执行函数

  • finish - 在一个函数内部, 执行到当前函数返回

image.png

获取到返回值后, 继续打印.

image.png

跳转至下一断点

  • c(continue) - 从一个断点处, 直接运行至下一个断点处

image.png

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论