Bochs是一个x86硬件平台的开源模拟器。它可以模拟各种硬件的配置。Bochs模拟的是整个PC平台,包括I/O设备、内存和BIOS。更为有趣的是,甚至可以不使用PC硬件来运行Bochs。事实上,它可以在任何编译运行Bochs的平台上模拟x86硬件。通过改变配置,可以指定使用的CPU(386、486或者586),以及内存大小等。
GDB是一个强大的命令行调试工具。大家知道命令行的强大就是在于,其可以形成执行序列,形成脚本。UNⅨ下的软件全是命令行的,这给程序开发提代供了极大的便利,命令行软件的优势在于,它们可以非常容易的集成在一起,使用几个简单的已有工具的命令,就可以做出一个非常强大的功能。
我们可以使用Bochs模拟x86平台来运行操作系统内核,但同时Bochs可以使用GDB的远程调试功能,与其无缝衔接。这样,我们就可以使用GDB在C语言源代码层面对操作系统内核进行调试。
一、Bochs
1.1、下载Bochs
因为Bochs的更新非常频繁,在短短几天内就会更新一个版本,这也说明Bochs是一个很成熟的模拟器,自由社区对Bochs的支持力度也很大。所以,我们可能需要经常下载Bochs的源代码,通过编译安装来解决当前版本中存在的问题。因为Bochs项目组提供其源代码时在URL中存在了版本信息,故本文在此只能提供其下载页面:
Bochs下载页面
在这个下载页面中,我们可以找到下载连接,如下图所示:
1.2、编译Bochs
Bochs有三种模式:
- 模拟器。其功能与VMware、VirtualBox这些重量级模拟器重叠,并且后两者功能更为强大。通常我们不采用这种模式。
- 使用自带的反汇编器进行CPU指令级调试。在这种模式下,不论操作系统内核是否存在调试信息,我们都可以对其进行逆向分析来了解内核的运行机制,但这对我们的能力要求非常高。
- 提供模拟器功能,并开放端口以供GDB远程调试。
虽然操作内核的大量使用C语言实现,但是在个别情况下,我们需要在CPU指令级对内核进行调试,故我们需要同时编译第二种和第三种模式。为了编译方便,我们编写了如下的shell脚本程序:
#!/bin/bash
echo "安装 bochs 和 bochsdbg ..."
./configure --enable-debugger --enable-readline
make -j8
sudo make install
sudo mv `which bochs` `which bochs`dbg
./configure --enable-gdb-stub
make -j8
sudo make install
- 使用
--enable-debugger
参数,Bochs使用内置的反汇编器进行调试; - 使用
--enable-gdb-stub
参数,Bochs开放端口供GDB远程调试; - 使用
--enable-readline
参数,可以让我们在使用Bochs内置调试器时使用readline库提供的自动补全和历史命令功能。 - 将使用
--enable-debugger
参数编译得到的bochs
程序文件名更名为bochsdbg
,是为了与使用--enable-gdb-stub
参数得到程序文件相区别。这样,通常情况下我们使用bochs
,指令级调试时我们使用bochsdbg
。也可以将文件更改为其他的文件名,但使用Bochs项目自带卸载功能时会将bochsdbg
文件一并删除,即便该文件不存在。
当我们将这个脚本程序放置在解压后的项目源代码顶级目录下并成功执行后,系统就会安装好我们需要的Bochs了。
1.3、配置Bochs
通常情况下,Bochs会自动读取当前目录下的已编辑好的bochsrc
配置文件,我们也可以通过命令行参数要求Bochs读取指定的配置文件:
bochs -f <Bochs配置文件>
对于Bochs配置文件,我们可以手动进行编辑,而网上大量传播了此类教程。但在此,强烈建议大家通过Bochs程序自动生成此配置文件。因为手动输入错误,或是Bochs版本更新的缘故,会带来很多莫名其妙的问题,所以,自动生成配置文件才能让我们不会把有限的经历花费在这种极度低级的错误上。
我们运行bochs
命令即可进入其命令菜单,如下所示:
就像界面中提示的,我们可以在命令行中指定-q
参数来跳过这个菜单界面。
当我们进入编辑菜单后,会出现上图所示的子级菜单项。在这些配置选项中,我们通常比较关心的是“磁盘与启动选项”和“其他选项”。
- 在“磁盘与启动选项”中,我们可以配置挂载的磁盘映像文件,并设置启动设备。
- 在“其他选项”中,我们可以设置提供给GDB的调试端口(
--enable-gdb-stub
参数模式下)。
设置好相关选项后要记得保存为配置文件。
1.4、启动Bochs
当使用GDB远程调试Bochs时,需要在一个控制台窗口启动Bochs并等待GDB连接,之后还需要打开另一个控制台窗口启动GDB以供我们调试使用。在进行频繁的调试工作时,这个过程很容易让人恼火。我们可以编辑以下脚本程序来自动化此过程:
#!/bin/bash
gnome-terminal -t "Bochs" -- bochs -q
gnome-terminal -t "GDB" -- gdb <内核程序文件>
此脚本程序适用于Ubuntu20.04,如果是其他Linux发行版本,可能需要更换为对应的脚本。
二、GDB
1、远程调试
启动GDB后,我们需要连接远程调试接口:
target remote localhost:1234
示例中的端口1234是Bochs配置中开启GDB Stub
功能后默认设置的端口,也可以在Bochs配置中修改为其他未被占用的端口并在此使用新端口。连接成功后,如下图所示:
2、.gdbinit文件
GDB在调试程序前,可以首先读取当前目录下的.gdbinit文件,并执行里面的GDB命令,这样我们可以把一部分工作进一步自动化。但默认情况下,GDB是不允许我们这么做的,GDB会认为这样不是很安全。如下图所时:
如图中中所示的,为了执行.gdbinit中的GDB命令,我们需要进行如下操作:
- 1、创建上图中指定的.gdbinit文件,如上图红框中的
/home/hy/.gdbinit
。 - 2、编辑此.gdbinit文件,在其中添加
add-auto-load-safe-path
指令,如上图红框中的add-auto-load-safe-path /home/hy/workspace/native/multiboot2/.gdbinit
。