在`Vscode`中简单使用`gdb`

gdb很好用.

## 生成调试文件: 为了方便调试,编译生成可执行文件的时候可以选择生成 **调试版本 (debug build)**。比如使用 `g++` 编译的时候添加参数 `-g`,使用 `cmake` 编译的时候添加参数 ...这些行为实际上保留了原始代码的结构(相当于增加了调试信息),方便进行逐行调试。

以下是一些常见的生成调试文件的方式:

  • g++ / gcc / clang:编译时增加 -g 选项即可。
  • cmake:编译时输入 cmake -DCMAKE_BUILD_TYPE=Debug .,这一步指定了构建类型为调试类型,实质上改变的是 build 文件结构。
  • makefileCXXFLAGS += -g

使用gdb:#

有了生成的调试文件,我们就可以使用 gdb 对我们的文件进行调试。这里先对 gdb 的基本运行方式做简单的介绍:

gdb 是一个调试工具(CI),功能很强大,可以实现各种各样的调试,并且允许自己编写简单的调试脚本。一般安装了 gcc 都会自带一个 gdb ,和 gcc 处在同一个 bin 文件夹下。

在终端中输入 gdb 以进入 gdb 调试工具内部。

要想使用 gdb 对调试文件进行调试,可以有以下方式:

  • 在打开 gdb 的时候,将调试文件路径作为参数传给 gdb,此时会自动将调试文件路径添加到 gdb 的目标文件表中。
  • 打开 gdb 之后,可以使用 file 命令添加待测试文件,这里可以使用相对路径或者是绝对路径,相对路径是相对于你在什么位置打开的 gdb 而言的,例如你在 D:\ 中打开了 gdb,那么 .\vscode\ 就是 D:\vscode\
    • 注意,多次使用 file,会将之前的指定文件覆盖为新的指定文件。

以下是一些常见的gdb命令(“()”内为缩写):

  • run:运行当前已绑定的目标文件。
  • break (b) Line:在第 Line 行添加一个断点。相应的,使用 clear line 删除掉第 line 行的断点;
    • 还可以使用 break function_name 来为函数添加断点,这样在该函数被调用的时候可以暂停。
  • step (s):单步调试,并且进入函数等。
  • next (n):一次性执行到下一行代码。
  • continue:执行到下一次断点触发。
  • exit:退出 gdb
  • kill:终止当前正在调试的程序。
  • backtrace (bt):显示调用栈;
  • info:显示信息,根据参数不同显示不同信息
    • info locals:显示当前函数的局部变量和值;
    • info args:显示当前函数的参数及其值;
    • info functions:列出当前文件中定义的所有函数;
  • list (l):显示当前执行点周围的源代码(上下几行);

除了以上简单命令,gdb为我们还提供了其他很有用的命令,推荐大家阅读文档进行学习。

创建自己的命令:#

gdb允许你使用简单的脚本语言将一些重复的调试操作抽象化成为本地命令,若这些命令是在gdb运行时编写的,那么他们在gdb退出后即无法使用,需要重新编写,以下是一个简单的例子:

1
2
3
4
5
6
(gdb) define repeat
> set $i=0
> while $i<$arg0
> continue
> end
> end

这里使用 define 命令抽象化了一个允许任意次数 continue 的操作 repeat。可以看到,在 gdb 脚本中,set 用来声明变量,$ 开头表示这是一个变量,在使用这个变量的时候也要这样使用,arg0 是一个保留的变量名称,这个变量是在调用 repeat 时给入的,例如以下调用:

1
(gdb) repeat 3

将会设置 arg0 为 3 。

如果 define 的过程中打错了字,只能重复 end 然后重新输入。不过我们有另外一个更重要的解决方案,那就是,**gdb 可以运行已经编写好的脚本文件!**

这是一个非常强大的功能,很多重复性的工作不再需要人来完成,而是交由机器代行。这就是生产力的飞跃, 我们接下来就来看看具体的操作。

  • 脚本文件的创建:这很简单,只需要将后缀保留为 .gdb 即可。我们在其中可以编写任意脚本。
  • 脚本文件的运行:未启动 gdb 时,使用 gdb -x script.gdb 运行脚本文件(脚本文件内部可以添加一行 file exec.exe 来加载一个可执行文件作为调试对象);启动 gdb 时,使用 source path_to_your_script.gdb 来运行脚本文件。这里的参数都是文件路径。