• 使用Bochs调试操作系统代码


    最近在写一个玩具操作系统,在编写过程中,经常需要进行代码调试。平常我们在Windows或者Linux下编写应用程序时,可以使用像VS,GDB等等这些调试工具进行调试,但是现在要调试的不是应用程序,而是操作系统本身。那要怎么调试操作系统的代码呢?笔者就以自己编写玩具操作系统时的经历,介绍一下如何调试操作系统的代码。

    在开发操作系统的过程中,一般是先在模拟器或者虚拟机中运行调试,没什么大问题了,再在实体机上运行。常见的模拟器如Bochs、Qemu等,常见的虚拟机如VMWare、VirtualBox、Virtual PC等。

    本文就以Windows下的Bochs介绍一下如何使用Bochs模拟器来调试操作系统代码,文中有使用MinGW环境下的命令。

    一、Bochs内置调试器

    Bochs本身内置的调试器,是汇编级的调试器,对于调试像boot或者loader这样的16位汇编代码时,还是非常有用的,Bochs的调试命令还是非常丰富的,而且与GDB的调试命令也比较相似。下面列一些常用的调试命令:

    命令功能示例示例说明
    b打断点b 0x7c00在0x7c00处设置断点
    c继续执行c继续执行
    n单步执行,不会进入函数调用n执行一条语句,如果遇到CALL指令,不会进入函数
    s单步执行,并且会进入函数调用s执行一条语句,如果遇到CALL指令,则进入函数
    x显示指定线性地址开始的内存信息x /32bc 0x7c00以字符的形式显示线性地址0x7c00开始的32个字节
    xp显示指定物理地址开始的内存信息x /32bc 0x7c00以字符的形式显示物理地址0x7c00开始的32个字节
    r显示各通用寄存器的值r显示各通用寄存器的值
    sreg显示各段寄存器的值sreg显示各段寄存器的值
    blist显示所有断点信息blist显示所有断点信息
    del删除断点del 1删除1号断点,几号断点是由blist列出
    help显示帮助helphelp没有参数则显示命令概览,如果想要查看具体命令的帮助信息,则后面跟上命令即可,比如help info则是查看info命令的帮助信息
    q退出q退出调试控制台
    ldsym装载调试符号ldsym global “loader.sym”从装载loader.sym文件中装载调试符号,并且作为全局符号

    更多的调试命令可以通过help查看。

    1.直接运行

    在Windows下编写好bxrc文件,则可以在直接双击运行。下图是笔者写的Loader执行完成,准备进入内核的输出画面:

    在这里插入图片描述

    2.调试

    在bxrc文件右键弹出菜单中有一个debugger命令,执行它即可进入下面的开始对话框界面,默认是使用的bxrc文件中的配置,如果想要临时修改配置,也可以双击“Edit Options”列表框中的分类进行编辑,完成后执行“start”即开始调试。

    在这里插入图片描述

    此时会暂停在f000:fff0处,如下图所示:

    在这里插入图片描述

    这里就是Bochs的内置调试控制台了,可以在此输入各种调试命令。

    下图是笔者调试刚进入Loader的情况:

    在这里插入图片描述

    可以看到,全部是汇编代码,没有任何符号信息,调试起来是相当的费劲,如果不对照源码,根本就难以定位源码。笔者在刚开始写Loader时就是在没有任何调试信息的情况下来调试Loader的,非常费时费力。后面随着代码越来越多(笔者是使用大量的C语言来写Loader的),这种调试方式更是费时费力,其实Bochs是可以加载调试符号的,虽然相对GDB的调试信息,比较简陋,但是还是要方便很多。

    Bochs的符号文件格式为“%x %s”,即前面是地址,后面是符号,比如:

    00003182 memcpy
    
    • 1

    表示地址0x00003182为memcpy的入口地址。

    使用如下的命令生成调试符号文件:

    nm loader.elf | grep -i ' T ' | awk '{ print $1" "$3 }' > loader.sym
    
    • 1

    可以在CMakeLists.txt中使用:

    nm ${CMAKE_BINARY_DIR}/loader/loader.elf | grep -i ' T ' | awk '{ print $$1" "$$3 }' > ${CMAKE_CURRENT_SOURCE_DIR}/loader.sym
    
    • 1

    生成符号后,就可以使用ldsym来装载调试符号了,如下所示:

    在这里插入图片描述

    可以从图中看到已经有符号信息显示了,调试起来就方便多了。

    如果每次调试时都手动输入ldsym来装载调试信息还是比较繁琐,可以直接配置在bxrc文件中,添加下面一行配置即可:

    debug_symbols: file="loader.sym", offset=0x8000
    
    • 1

    本文链接地址:https://blog.csdn.net/witton/article/details/126414601?spm=1001.2014.3001.5501

    二、Bochs+GDB调试

    由于Bochs内置的调试器是汇编级的,在操作系统进入内核后,将会有大量的C代码,如果还是使用汇编级的调试还是相当麻烦的,这就需要有源码级的调试了,GDB将成为首选源码级调试器。如果还是Bochs模拟器的话,可以使用GDB连接到Bochs来进行源码级调试。

    Windows下的Bochs默认安装文件是不支持GDB调试的,需要自己重新编译Bochs源码,编译时需要添加参数--enable-gdb-stub,下面是笔者在MinGW下编译Bochs的参数:

    ../bochs-2.7/configure --enable-all-optimizations --enable-long-phy-address --enable-alignment-check --enable-pci --enable-cdrom --enable-gameport --enable-large-ramfile --enable-show-ips --with-all-libs --enable-usb --enable-usb-ohci --enable-usb-ehci --enable-usb-xhci --enable-logging --enable-fpu --enable-3dnow --enable-busmouse --enable-iodebug --enable-sb16 --enable-ne2000 --enable-clgd54xx --enable-voodoo --enable-es1370 --enable-e1000 --with-rfb --enable-x86-debugger --enable-debugger-gui --enable-gdb-stub --with-win32
    
    • 1

    然后在bxrc文件中,添加下面一行配置:

    gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0
    
    • 1

    输入命令(注意一定要使用自己编译的Bochs,不能像前面那样在右键菜单中使用Debugger了):

    ./bochs -f bochsrc.bxrc -q
    
    • 1

    即可看到Bochs控制台中输出:

    Waiting for gdb connection on port 1234
    
    • 1

    这是在等待GDB的连接,这里的连接端口为1234

    在这里插入图片描述

    在MinGW控制台输入如下命令启动交叉编译的GDB:

    x86_64-elf-gdb -ex "file build/kernel/kernel" -ex "target remote :1234" -ex "b kmain"
    
    • 1
    • -ex “file build/kernel/kernel”
      让GDB自动装载build/kernel/kernel文件中的调试信息

    • -ex “target remote :1234”
      远程连接本机的1234端口

    • -ex “b kmain”
      在kmain函数入口设置断点

    这样就可以开启GDB的源码级调试了,如下图所示:

    在这里插入图片描述

    使用命令行方式手动输入GDB命令来调试还是麻烦了点,可以直接使用Visual Studio来可视化调试,目前新版本的Visual Studio已经支持使用GDB来调试GCC生成的C/C++程序了,可以参见笔者前面的博文:Visual Studio 2022使用MinGW来编译调试C/C++程序

    下图为笔者使用VS 2022调试Kernel的情况,可以看到借助VS IDE的强大功能,调试起来是非常方便,与调试VC的普通应用程序体验高度一致:

    在这里插入图片描述

    由于Bochs是完全使用软件的方式来模拟,使用它调试运行内核,是相当慢的,后面笔者将介绍使用Qemu来运行调试操作系统,Qemu的运行效率比Bochs快很多,参见后文:使用QEMU+GDB调试操作系统代码

    希望此文能帮助到喜欢研究、编写操作系统的读者,更希望有朝一日看到国人能够写出完全自主的操作系统并流行起来!哈哈!

  • 相关阅读:
    uni-app学习(1)
    什么是 Kubernetes HPA
    k8s持久化存储PV、PVC
    Debiased Contrastive Learning of Unsupervised Sentence Representations 论文阅读
    Plato Farm全新玩法,套利ePLATO稳获超高收益
    设计模式之抽象工厂
    JOSEF电流继电器 DL-33 整定范围0.5-2A 柜内安装板前接线
    手把手教你在Ubuntu22.04 上安装 Vivado、HLS、Vitis 2022.2版本
    【正点原子STM32连载】 第五十七章 DSP FFT实验(Julia分形)实验 摘自【正点原子】APM32F407最小系统板使用指南
    原生js 之 (DOM操作)
  • 原文地址:https://blog.csdn.net/witton/article/details/126414601