# 概述

众所周知,我们的 xv6 操作系统是运行在 QEMU 上的。因此,想使用 GDB 调试就离不开 QEMU 的支持。幸运的是,QEMU 确实为我们提供了一个接口:
通过在 QEMU 的运行命令中指定 -S -gdb tcp:xxx,即可在对应的 TCP 端口上开启一个 GDB 调试服务器的进程。
之后,通过自己的 GDB 远程连接到该 Server 上即可远程调试。

考虑到每个人的环境不同,本文将讨论三种方案:

  1. 只建立 QEMU 的 GDB 的调试服务。这样,您可以根据自己的情况,用比如命令行等手段,只要能把自己的 GDB 连接到调试服务上即可,然后手动使用 b 加断点等调试指令或使用其他的工具。请只阅读第一部分即可。
  2. 在虚拟机上使用 CLion。优点是可以在 IDE 中图形化的断点与调试。缺点是虚拟机的性能和分辨率往往不太行,开发体验较差。这种方法只是比使用物理机少了一些准备的工作,不需要配置共享文件夹、SSH 和端口转发等,但是 CLion 中的配置方法与物理机很类似,请直接参考那部分的内容。
  3. 在物理机上使用 CLion。整体体验较好,但是配置相对麻烦一点。请阅读全部的部分。

如果在过程中遇到问题,可以联系作者:starrah@foxmail.com。

# 以远程 GDB 调试服务器的方式运行 QEMU

为了获得更好的体验,我编写了 gdbhelper.py 脚本。其内的原理是调用 make qemu-gdb,但增加了更多的选项和做了更好的封装。
(提示:QEMU 的 GDB 服务始终在 tcp 25000 端口上运行。这是在 Makefile 中的 $(GDBPORT) 变量中配置的。)

在虚拟机上打开终端,切换到代码所在目录(gdbhelper.py、Makefile 等所在的目录)运行:

script
python3 gdbhelper.py

即可打开一个新窗口,但是这个窗口不会出现任何内容。这是因为使用 GDB 的情况下,qemu 在启动后不会自动运行 xv6 的系统镜像,
需要等待用户 GDB 接入到调试服务器上后手动使用 r 运行。

上述命令是会打开一个新的 QEMU 的窗口的,因此无法在没有 SDL 图形界面接口的情况下运行。因此如果希望打开一个没有图形界面、直接在控制台上输入输出的 QEMU(这样就可以使用 SSH 运行),请改为使用:

script
python3 gdbhelper.py -n

注:脚本的功能是先检查并尝试杀死已经存在调试进程,(以免端口被占用导致新的进程无法打开),然后运行 make qemu-gdbmake qemu-nox-gdb 。如果只想杀死现存的调试进程,不需要运行新的,请使用 python3 gdbhelper.py -k
通过 python3 gdbhelper.py -h 可以查看该脚本的使用帮助。

至此,GDB 的调试服务进程已经构建。如果您不打算使用 CLion,则后面的部分可以不看。

# 配置物理机上 CLion 的远程调试

需要先做一些准备。这些内容都可以在网上搜索到相关教程,本文不再赘述:

  1. 建议配置一个虚拟机和物理机之间的共享文件夹。如果不这么做的话,那之后可能就得每次修改代码并重新 make 后,手动把编译结果的 kernel 文件同步到物理机上,否则由于符号不对应调试会出问题。如果把代码直接放在物理机和虚拟机之间的共享文件夹里就很方便。
    配置方法是在 VirtualBox 的设置 - 共享文件夹,例如下图;相关教程可以自行上网查阅。
  2. 虚拟机上配置 SSH 远程登录,请自行查看网上教程。(我印象中,从 tuna 的 ubuntu-release 上下载下来的系统镜像是自带了 openssh-server 的,应该不用特别配置)。
    之后,需要在 VirtualBox 中做一个 NAT 端口映射,使得物理机中可以访问到虚拟机的 SSH22 端口。打开虚拟机的设置,参见下图做配置:

    这样,在物理机上通过 localhost:9022 而不是 22 端口来访问虚拟机的 SSH,并在之后通过 25000 端口可以直接调试到虚拟机中的 GDB。
  3. Windows 系统下建议安装 MinGW 并配置到 CLion 中作为工具链,以获得更好的代码补全的支持。本人在个人的服务器上提供了一个 MinGW64 的压缩包, 点击这里可以下载 (不保证链接永远有效)。
    用法是解压放置在硬盘任意位置,然后把其中的 bin 目录添加到环境变量 PATH 即可。在 CLion 中要配置工具链,方法可以自行上网查询。
  4. 踩坑记录:Windows 上,最好控制台运行一下 git config --global core.autocrlf input ,之后把项目重新 clone 一遍,不然如果文件是 CRLF 行尾的话在 Linux 上没法过编译!

CLion 中配置方法:(本 IDE 是中文的,英文请自行对应意思,或者去 File-Settings-Plugins-Market 搜索 "Chinese" 后安装中文语言包)

  1. 需要先建立一个 SSH 的配置。文件 - 设置 - 工具 - SSH 配置,加号新建,填写入全部的信息,例如下图填好后可以点下测试连接,出现成功连接即为配置好了,点击确定回到主界面。
  2. 右上角添加配置,加号,自定义构建应用程序
  3. 建立一个空白的自定义构建目标,用于占位,它不做任何操作,但是不能没有。
    点击界面上的 “配置自定义构建目标” 加号新建一个。名字随便起,比如 “无操作”,点击构建右侧省略号,弹出外部工具的窗口,加号新建一个。
    名字随便起,下面的程序、参数全部留空。按照图中配置好。
  4. 一路确定回到开始的配置页面,按照下图中配置好。其中名称随便取,目标选刚才新建的。可执行文件其实也是不需要的、因为我们的核心在于一会要配置的远程外部工具,但这里还是不能不填,所以要随便写一个运行起来没什么意义的程序用作占位。
    比如可以选择 C:\Windows\System32\cmd.exe,程序参数写成 "/c",这样就可以打开一个 cmd 但是不做任何操作。
    工作目录要选成项目所在的目录。
  5. 点击 "执行前" 右侧的加号,Run Remote External Tool,然后点击加号。弹出外部工具窗口,点击加号弹出创建工具窗口,里面要先点击下面的 SSH configuration 按钮,下拉菜单中选择刚刚在第 1 步创建的 SSH 配置。
    之后,名字随便起比如 "QEMU-GDB",程序选择 /usr/bin/python3(就是你的虚拟机上 python 实际的安装目录,如果不确定可以使用 which python3 查看,如果没有 python3 请先安装),
    参数输入 "gdbhelper.py -n"(-n 表示以 QEMU 的 - nographic 模式运行,因为我们是 SSH,无法开启独立窗口,只能直接利用 shell 本身进行)。
    工作目录选择代码在虚拟机上所在的位置(比如通过共享文件夹方式,那么就去找到共享文件夹的挂载点下,找到代码目录)。
    完整配置可参考下图。

    一路确定,最终的运行配置如下图。
  6. 再次点击左上角加号,GDB 远程调试,名字随便起,GDB 的话如果装了 MinGW 并配好了工具链建议用 MinGW,否则用 Bundled GDB 应该也可以(我没测试)。
    target remote 填 "tcp:localhost:25000",符号文件选择自己所在目录下的 kernel 文件(如果找不到这个文件的话不要紧,是因为没有 make 过,直接手动写上就可以,之后 make 的时候会自动构建出来)。
    路径映射点击右侧加号新建一行,本地填本地的项目路径,远程填虚拟机上对应的路径。完整配置例如下图。

到此,CLion 的配置完成。接下来介绍每次的运行方法:

  1. 右上角运行配置的下拉菜单切换到上面第一个建立的配置(我这里的名字叫 "运行 QEMU-GDB"),点击绿色箭头运行。静待编译运行,直到控制台倒数第二行出现 "gdb server is running" 的提示,如下图。
  2. 右上角运行配置切换到上面第二个建立的配置(我这里的名字叫 "调试"),点击虫子的标志即可。
    这步之前可以先去 main.c 里的 main 函数加个断点再进行。发现断点命中了,大功告成!
  3. 结束调试,点击右上角的停止按钮,全部停止。注意这时 QEMU-GDB 有可能不会马上退出,可能会延迟三五秒,出现 Process finished 的字样才表明真的退出了。

  4. 之后每次进行调试,都需要依次重复步骤 1-2 的方法,先运行 QEMU-GDB 的调试服务器,再运行本地的 GDB 连接到上面。
    此外,如果需要在操作系统的 shell 中进行输入输出的话,只要在下方切换到 "Run" 菜单就可以看见操作系统的 shell 了。
更新于