操作系统GDB调试方法

概述

众所周知,我们的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
1
python3 gdbhelper.py

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

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

script
1
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了。