Linux——gdb调试手册

前言:

这篇文章只介绍到日常够用的一些gdb命令,如果想了解更多可以直接翻看文章末尾的链接。

gdb调试

gdb是什么?

gdb全称“GNU symbolic debugger”,诞生于GUN计划(跟之前讲的gcc是表兄弟关系),是linux下常用的程序调试器

在这里插入图片描述

当下的 GDB 支持调试多种编程语言编写的程序,包括 C、C++、Go、Objective-C、OpenCL、Ada 等。实际场景中,GDB 更常用来调试 C 和 C++ 程序。

Windows 操作系统中,人们更习惯使用一些已经集成好的开发环境(IDE),如 VS、VC、Dev-C++ 等,它们的内部已经嵌套了相应的调试器。

gdb有什么用

总的来说,借助 GDB 调试器可以实现以下几个功能:

程序启动时,可以按照我们自定义的要求运行程序,例如设置参数和环境变量;
使被调试程序在指定代码处暂停运行,并查看当前程序的运行状态;
程序执行过程中,可以改变某个变量的值,还可以改变代码的执行顺序,从而尝试修改程序中出现的逻辑错误。

如何启动gdb

生成gdb用的可执行文件

gdb调试器需要特殊的可执行文件。可以在编译时用gcc -c main.c -g命令生成debug版本。

或者用gcc -o main main.c -g生成也可以。

启动gdb

然后用命令gdb main.exe启动gdb调试器。
会出现以下信息:

GNU gdb (GDB) 8.0.1
Copyright © 2017 Free Software Foundation, Inc.

(gdb)

屏蔽免责条款

这个时候会打印出一堆免责条款。可以通过添加--slient | -q | --quiet来屏蔽掉这些信息。

在这里插入图片描述

gdb main.exe --silent

会出现以下信息:

Reading symbols from main.exe…(no debugging symbols found)…done.
(gdb)

gdb常用调试指令

调试指令作用
b(break) 行号在源代码指定的某一行设置断点,其中行号用于指定具体打断点的位置。
r(run)执行被调试的程序,其会自动在第一个断点处暂停执行。
n(next)令程序一行代码一行代码的执行。
p(print) 变量名打印指定变量的值
l(list)显示源程序代码的内容,包括各行代码所在的行号。
q(quit)终止调试。

启动程序指令

根据不同场景的需要,GDB 调试器提供了多种方式来启动目标程序,其中最常用的就是 run 指令,其次为 start 指令。也就是说,run 和 start 指令都可以用来在 GDB 调试器中启动程序
但是他们还是有区别的!
在这里插入图片描述

run: 默认情况下,run 指令会一直执行程序,直到执行结束。如果程序中手动设置有断点,则 run 指令会执行程序至第一个断点处;
start: start 指令会执行程序至 main() 主函数的起始位置,即在 main() 函数的第一行语句处停止执行(该行代码尚未执行)。

问:是不是启用gdb就可以直接使用run或者start呢?

我们来看一个例子:

# gdb

以下是打印的信息:

GNU gdb (GDB) 8.0.1
Copyright © 2017 Free Software Foundation, Inc.
… <-- 省略部分输出信息
Type “apropos word” to search for commands related to “word”.
(gdb)

我们都没有指定目标文件,拿什么来进行调试!

在启动对文件的调试之前,不仅需要目标文件,还需要一些其他的必要的准备工作

  • 如果启动 GDB 调试器时未指定要调试的目标程序,或者由于各种原因 GDB 调试器并为找到所指定的目标程序,这种情况下就需要再次手动指定;
  • 有些 C 或者 C++ 程序的执行,需要接收一些参数(程序中用 argc 和 argv[] 接收);
    目标程序在执行过程中,可能需要临时设置 PATH 环境变量;
  • 默认情况下,GDB 调试器将启动时所在的目录作为工作目录,但很多情况下,该目录并不符合要求,需要在启动程序手动为 GDB 调试器指定工作目录
  • 默认情况下,GDB 调试器启动程序后,会接收键盘临时输入的数据,并将执行结果会打印在屏幕上。但 GDB 调试器允许对执行程序的输入和输出进行重定向,使其从文件或其它终端接收输入,或者将执行结果输出到文件或其它终端。
如何指定目标文件程序

首先对于已经启动的gdb调试器,我们可以通过l验证其是否找到目标程序文件。

(gdb) l

如果没有的话会打印一下信息:

No symbol table is loaded. Use the “file” command.

这个时候我们就需要手动去指定要调试的目标程序。

(gdb) file 路径/目标文件
如何传递文件

总的来说,为 GDB 调试器指定的目标程序传递参数,常用的方法有 3 种。

  • 启动 GDB 调试器时,可以在指定目标调试程序的同时,使用 --args 选项指定需要传递给该程序的数据。
# gdb --args main.exe a.txt
  • GDB 调试器启动后,可以借助 set args 命令指定目标调试程序启动所需要的数据。
(gdb) set args a.txt
  • 除此之外,还可以使用 run 或者 start 启动目标程序时,指定其所需要的数据。
(gdb) run a.txt
(gdb) start a.txt
如何切换工作目录

默认情况下,GDB 调试器的工作目录为启动时所使用的目录。例如在 ~ 路径下启动的 GDB 调试器,其工作目录就为 ~(当前用户的 home 目录)。当然,GDB 调试器提供有修改工作目录的指令,即 cd 指令。

(gdb) cd /tmp/demo
如何改变PATH环境变量
(gdb) path 路径

注意,此修改方式只是临时的,退出 GDB 调试后会失效。

设置断点

默认情况下,程序不会进入调试模式,代码会瞬间从开头执行到末尾。 要想观察程序运行的内部细节,可以借助 GDB 调试器在程序中的某个地方设置断点,这样当程序执行到这个地方时就会停下来。

break命令设置断点

gdb中的break命令就是用来设置断点的,主要有两种格式。

(gdb) break location      // b 位置
(gdb) break ... if cond   // b 表达式
  • 在第一种格式中,location 用于指定打断点的具体位置,其表示方式有多种。
location 的值含 义
linenumlinenum 是一个整数,表示要打断点处代码的行号。
filename:linenumfilename 表示源程序文件名;linenum 为整数,表示具体行数。整体的意思是在指令文件 filename 中的第 linenum 行打断点。
+ offsetoffset 为整数,+offset 表示以当前程序暂停位置为准,向后数 offset 行处打断点
- offsetoffset 为整数,-offset 表示以当前程序暂停位置为准,向前数 offset 行处打断点
functionfunction 表示程序中包含的函数的函数名,即 break 命令会在该函数内部的开头位置打断点,程序会执行到该函数第一行代码处暂停。
filename:functionfilename 表示远程文件名;function 表示程序中函数的函数名。整体的意思是在指定文件 filename 中 function 函数的开头位置打断点。
  • 第二种格式中,cond 为某个表达式。整体的含义为:每次程序执行到 … 位置时都计算 cond 的值,如果为 True,则程序在该位置暂停;反之,程序继续执行。
(gdb) b 7 if num>10     // 如果 num>10 在第 7 行打断点
tbreak命令设置断点

tbreak 命令可以看到是 break 命令的另一个版本,tbreak 和 break 命令的用法和功能都非常相似,唯一的不同在于,使用 tbreak 命令打的断点仅会作用 1 次,即使程序暂停之后,该断点就会自动消失。

其他都和break的用法一样,这里就不多介绍了。

rbreak命令设置断点

break 和 tbreak 命令不同,rbreak 命令的作用对象是 C、C++ 程序中的函数,它会在指定函数的开头位置打断点。

(gdb) tbreak 表达式		//例如(gdb) rbreak rb_*       <--匹配所有以 rb_ 开头的函数

监控变量值指令

在这里,主要介绍的就是watch命令,其用来监控某个变量或者表达式的值,通过值的变化情况判断程序的执行过程是否存在异常或者 Bug。
在这里插入图片描述
GDB 调试器支持在程序中打 3 种断点,分别为普通断点、观察断点和捕捉断点。其中 break 命令打的就是普通断点,而 watch 命令打的为观察断点。

(gdb) watch cond 	//conde 指的就是要监控的变量或表达式

watch 命令的功能是:只有当被监控变量(表达式)的值发生改变,程序才会停止运行。

建立捕捉断点指令

刚刚我们提到了gdb调试中三种断点中的两种。现在就来说说最后一种。

首先我们要认识三种断点的区别

普通断点作用于程序中的某一行,当程序运行至此行时停止执行,观察断点作用于某一变量或表达式,当该变量(表达式)的值发生改变时,程序暂停。而捕捉断点的作用是,监控程序中某一事件的发生,例如程序发生某种异常时、某一动态库被加载时等等,一旦目标时间发生,则程序停止执行。

(gdb) catch event		//event 参数表示要监控的具体事件
event事件含义
throw [exception]当程序中抛出 exception 指定类型异常时,程序停止执行。如果不指定异常类型(即省略 exception),则表示只要程序发生异常,程序就停止执行。
catch [exception]当程序中捕获到 exception 异常时,程序停止执行。exception 参数也可以省略,表示无论程序中捕获到哪种异常,程序都暂停执行。
load [regexp]regexp 表示目标动态库的名称,load 命令表示当 regexp 动态库加载时程序停止执行;regexp 参数也可以省略,此时只要程序中某一动态库被加载或卸载,程序就会暂停执行。
unload [regexp]unload 命令表示当 regexp 动态库被卸载时,程序暂停执行。

查看变量指令

对于在调试期间查看某个变量或表达式的值,GDB 调试器提供有 2 种方法,即使用 print 命令或者 display 命令。

print指令

print 命令可以缩写为 p,最常用的语法格式(基本够用)如下所示:

(gdb) print num		//参数 num 用来代指要查看或者修改的目标变量或者表达式
(gdb) p num

其完整语法如下:

(gdb) print [options --] [/fmt] expr

各个参数的意义:

options:表示该命令所支持的选项,这些选项可以控制 print 命令输出指定内容的变量或者表达式的值;
fmt:指定输出变量或表达式值时所采用的格式;
expr:指定要查看的变量或表达式。

options参数详情:
在这里插入图片描述

display指令

和 print 命令一样,display 命令也用于调试阶段查看某个变量或表达式的值,它们的区别是,使用 display 命令查看变量或表达式的值,每当程序暂停执行时,GDB 调试器都会自动帮我们打印出来,而 print 命令则不会。

(gdb) display expr			//expr 表示要查看的目标变量或表达式
(gdb) display/fmt expr		//参数 fmt 用于指定输出变量或表达式的格式

常用fmt参数:
在这里插入图片描述

参考文献

[1] GDB调试教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shenmingik

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值