使用 vscode 的 debug 调试功能来进行南大 PA

gdb 是我们进行大型项目开发必不可少的调试工具,但是它原生是运行在命令行中的,对于已经有了图形界面的我们来说,完全可以使用 vscode 的 debug 功能来启动 gdb 从而更方便地进行调试。

vscode 的 debug 功能提供了一套 gui 来显示 gdb 的各种信息、观察点,比直接用命令行方便多了,非常直观。此外还提供了 console 来让你可以使用命令行的方式控制 gdb,可以说是各取所长,两全其美。

gdb 已经在讲义的 PA0 步骤中安装好了。在命令行中输入指令 gdb -v 如果能够显示 gdb 的版本就代表 gdb 已经安装上了。

而启动项目的调试信息,则在讲义的“为 NEMU 编译时添加 GDB 调试信息”中,也已经让我们配置好了。这一设置的作用是让 gcc 在编译 NEMU 的时候生成额外生成调试所需要的一些信息,gdb 利用这些信息才能够实现定位代码等功能。

vscode 的 debug 功能在侧边栏的第四个。刚点进来会显示如下界面:

./pics/image.png

这代表我们现在还没有配置任何调试项目,vscode 并不知道该如何调试。此时点击“Run and Debug”按钮,vscode 会生成一个模板项目来让我们进行配置,不过我们不需要这么做。

配置调试项目相关的文件是 .vscode/tasks.json.vscode/launch.json,前者的作用是进行项目的编译,后者是启动调试。在项目根目录下建立 .vscode 文件夹后,将以下内容分别复制进去。

tasks.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "clean",
            "command": "make",
            "args": ["clean"],
            "type": "shell"
        },
        {
            "label": "run",
            "command": "make",
            "args": ["run"],
            "type": "shell"
        },
        {
            "label": "make",
            "command": "make",
            "args": [],
            "type": "shell"
        }
    ]
}

"version" 代表 task 的版本,默认 "2.0.0" 就好。"tasks" 则是你定义的各个编译任务,由一个数组传入。

这里我们配置了三个任务,分别用于执行 make cleanmakemake run 指令。

在每一个任务中,"lable" 是这个任务的名字,需要唯一,后续需要用这个来标识该任务。"command""args" 分别是执行这个任务的指令和参数,vscode 会将他们安装顺序拼接成字符串,传入命令行并执行。显然 "args" 是一个数组,因为参数可能不止一个。

举一个例子,"command" 的值为 "make""args" 的值为 ["run", "-j8"],则最终传入命令行的指令就是 make run -j8

额外提一句
既然 vscode 会将 "command""args" 拼接在一起,那么其实直接把所有的指令都写到 "command" 里也可以,因为本质都是字符串。例如上面提到的例子,其实也可以写成 "command": "make run -j8"

最后一个 "type" 有两个值可以选,分别为 "shell""process",代表该任务是启动一个命令行来执行还是创建一个线程来执行。创建线程的话我们就没法看到执行的过程了,因此这里选择 "shell"

launch.json:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/riscv32-nemu-interpreter",
            "args": [],
            "cwd": "${workspaceFolder}",
            "MIMode": "gdb",
            "preLaunchTask": "make",
        }
    ]
}

"version""configurations" 不用说了。"name" 就是名字,会显示在选择框中。"type" 代表使用的 debug 工具是什么,这里我们用的就是 gdb,另一常见的是 lldb。

"cppdbg"不受支持
如果出现 "cppdbg" 不收支持的错误,是因为没有安装/启动 C/C++ 插件。安装并启动就好了。

"program" 是我们需要调试的程序。我们使用 make 指令会将 NEMU 编译成一个可执行文件,其路径是 build/$(ISA)-nemu-interpreter。而当我们在 make 的时候加入 run 参数,也就是执行 make run 的时候,其实就是在编译生成该可执行文件后自动执行。

更改 "program" 路径
我提供的 "program" 参数是我自己使用的路径,ISA 架构是 riscv32,如果你选择了别的 ISA,需要修改为对应的文件。

"cwd" 是执行 gdb 时候所在的目录,这里我们设置成项目根目录就好了。"preLaunchTask" 是在启动调试之前需要执行的任务,这里我们设置成前面配置好了的“编译”任务,其 label 是 "make",这样在每次启动调试之前,vscode 就会自动执行编译任务,生成最新的项目了。

以上都配置好后,回到 vscode 的调试选项卡就会显示成下图这样:

./pics/image-1.png

如果配置了多个调试项目,可以在左上方的下拉框中选择。点击绿色三角形就可以启动调试:

./pics/image-2.png

点击代码行左侧出现红色圆点就是添加断点。左侧的面板用于显示信息,例如变量值等。上方的控制板可以控制 gdb 继续、进入、跳出等。切换到 DEBUG CONSOLE 栏还可以以命令行的方式执行 gdb 指令:

./pics/image-3.png

享受 PA 吧。