如何调试操作系统

2020-01-22 23:08:12   最后更新: 2020-07-01 16:36:26   访问数量:295




上一篇文章中,我们介绍了如何创建一个简单的引导扇区,触发 BIOS 中断,从而在计算机屏幕上显示出一行我们想要的字符串

计算机是如何启动的?如何制作自己的操作系统

 

那么,作为一个程序员,首先想到的问题就是,如何去调试这段汇编代码呢?怎么能够知道程序执行的每一步计算机各个寄存器中的数据是否如我们预期呢?

别急,本节我们就来详细解答

 

最基本的调试方式就是反汇编,通过将二进制文件反汇编成不带有伪指令的汇编代码,可以看到每一步操作做了什么

下面的命令将二进制程序反汇编成为 NASM 的汇编源码:

ndisasm -o 0x7c00 boot.bin >> disboot.asm

 

我们最为希望得到的是一个具备断点调试以及随时查看、关注变量或寄存器的值的功能的调试工具

开源的虚拟机 bochs 就具备这些强大的调试功能:

http://bochs.sourceforge.net/

 

 

bochs 的安装

你可以通过源码编译安装,也可以通过包管理工具进行安装,如果你通过包管理工具安装,需要安装 bochs、bochs-x

同时,bochs 是一个跨平台的虚拟机,支持 windows、mac 等多个平台,甚至在安卓、IOS 等平台下也可以进行安装,这里不赘述安装过程了,windows、mac 用户可以直接官网下载可执行文件进行安装

如果你是通过源码编译进行安装,一定要在 configure 执行时添加参数 --enable-debugger 和 --enable-disasm 用以添加调试功能

 

bochs 配置

安装好后,bochs 启动需要至少进行以下配置:

  1. BIOS 映像文件,例如安装包中已经提供的 BIOS-bochs-latest
  2. VGA BIOS 映像文件,例如安装包中已经提供的 VGABIOS-lgpl-latest
  3. 至少一个引导启动磁盘映像文件

 

下面是我在当前最新的 2.6.11 版本所使用的一个配置:

############################################################### # Configuration file for Bochs ############################################################### # how much memory the emulated machine will have megs: 32 # filename of ROM images romimage: file=$BXSHARE/BIOS-bochs-latest vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest # what disk images will be used floppya: 1_44=c:/Debin/Workspace/code/oranges/boot.img, status=inserted # choose the boot disk. boot: floppy # where do we send log messages? # log: bochsout.txt # disable the mouse mouse: enabled=0 # enable key mapping, using US layout as default. keyboard: keymap=$BXSHARE/keymaps/x11-pc-us.map # change mouse capture hotkey mouse: enabled=1 mouse: type=imps2, enabled=1 mouse: type=serial, enabled=1 mouse: enabled=0, toggle=ctrl+f10

 

 

启动 bochs

unix 环境

在 linux 或 mac 环境下,执行下面的命令就可以启动 bochs 了:

bochs -f bochsrc

 

bochsrc 是我们上面编写的配置文件

执行后,显示出下面的界面:

 

 

输入 6,回车,就可以开始调试、运行了

 

windows 环境

在 windows 环境下,安装路径中有两个可执行文件:bochs.exe 和 bochsdbg.exe

顾名思义,bochs.exe 是虚拟机的直接执行文件,而 bochsdbg.exe 则用于对系统的调试

 

bochs 和我们熟悉的 gdb 界面非常像,可以通过命令进行系统的调试工作

输入 help 可以看到支持的调试命令

 

断点

  • vbreak seg:off 或 vb seg:off -- 为虚拟地址设置断点
  • lbreak addr 或 lb addr -- 为线性地址设置断点
  • pbreak [*] addr 或 pb [*] addr 或 break [*] addr 或 b [*] addr -- 为物理地址设置断点,[*] 表示 * 是可选的
  • info break -- 显示当前断点信息
  • bpd n -- 将 n 号断点设置为失效
  • bpe n -- 将 n 号断点设置为生效
  • delete n 或 del n 或 d n -- 删除 n 号断点

 

上面的 seg、off、addr 都支持十六进制、十进制或八进制,但支持支下面三种格式:

  1. 十六进制 -- 0xcdef0123
  2. 十进制 -- 123456789
  3. 八进制 -- 01234567

 

所有的添加断点指令都支持条件触发,条件需要被双引号括起来并放到 if 关键字后,例如:

break 0x123cff if "ax = 0"

 

执行控制

  • c 或  cont 或 continue -- 运行到下一断点
  • s [cpu] [count] 或 step [cpu] [count] -- 在指定 CPU 上单步执行 count 步,cpu 和 count 都是可选的,默认在当前断点中断的 CPU 上执行,如果 cpu 为 all 则在所有 CPU 上执行,默认执行 1 步
  • q 或 quit 或 exit -- 退出执行

 

信息查看

  • r 或 reg 或 regs 或 registers -- 列出所有 CPU 整数寄存器列表及存储内容
  • fp 或 fpu -- 列出所有 FPU 寄存器及存储内容
  • mmx -- 列出所有 MMX 寄存器及存储内容
  • sse 或 xmm -- 列出所有 SSE 寄存器及存储内容
  • ymm -- 列出所有 AVX 寄存器及存储内容
  • sreg -- 显示段寄存器及内容
  • dreg -- 显示调试寄存器及内容
  • creg -- 显示控制寄存器及内容
  • set reg = expr -- 将 CPU 寄存器改为 expr 的值,只支持通用寄存器和指令指针,EFLAGES、段寄存器、浮点指针、SIMD 寄存器不支持修改
  • info cpu -- 列出所有 CPU 寄存器及内容
  • info eflags -- 显示已解码的 EFLAGS 寄存器
  • info break -- 显示所有断点信息
  • info tab -- 显示分页地址转换信息
  • info device -- 列出支持的设备,在后面加设备参数则显示对应设备状态

 

操作内存

  • x /nuf addr -- 查看线性地址 addr 的内存
  • xp /nuf addr -- 查看物理地址 addr 的内存
  • setpmem addr datasize val -- 将物理地址 addr 中 datasize 大小的值设置到变量 val 中
  • writemem -- 内存转储
  • crc addr1 addr2 -- 显示物理内存范围 addr1 到 addr2 的 CRC32

 

参数取值

上述操作中,参数 /nuf 是可选的,其中 n 表示显示多少个单位,默认为 1,u 表示单位大小,默认为字节,f 表示打印格式,默认为16进制方式打印

 

单位大小取值

u 可以取值:

  • b -- 字节单位
  • h -- 半字单位(2 字节)
  • w -- 字单位(4 字节)
  • g -- 巨字单位(8 字节)

 

打印方式取值

f 可以取值:

  • x -- 16 进制
  • d -- 十进制
  • u -- 无符号十进制
  • o -- 八进制
  • t -- 二进制

 

内存监控

  • watch read addr 或 watch r addr -- 在物理地址 addr 处加一个读监视点
  • watch write addr 或 watch w addr -- 在物理地址 addr 处加一个写监视点
  • watch -- 在当前内存位置加一个监视点
  • watch stop -- 当遇到监视点时停止模拟(默认动作)
  • watch continue -- 当遇到监视点时不停止模拟
  • unwatch addr -- 取消监视点
  • unwatch -- 取消全部监视点
  • trace-mem on/off -- 启用/禁用内存地址访问跟踪

 

反汇编

u/disasm/disassemble start end -- 反汇编给定线性地址范围的指令。也可以是 u /10 反汇编从当前地址开始的 10 条指令

 

在 DOS 系统中,原生具备了调试功能,但我们要让程序从 DOS 规范中规定的内存起始地址 0100h 开始加载

因此我们需要将代码第一行的“org 07c00h” 改为“org 0100h”,并执行汇编操作生成 COM 文件:

nasm boot.asm –o boot.com

 

然后下载并安装 DOSBox:https://www.dosbox.com/download.php?main=1

打开 DOSBox,执行 debug 命令即可进行调试

 

DOS 调试指令

DOS 中所有的数字都是十六进制的,所以你不能指定进制转换及如何显示

下表是 DOS 的全部调试指令

DOS 调试指令
指令简称参数说明
assembleA[address]从 CS:0100 地址开始编写汇编代码,不支持宏指令或标签
compareCrange address比较两个内存块,如果没有差异,则显示 -
dumpD[range] [length]dump 内存范围,如 d c000:0010
enterEaddress [list]将数据或指令(作为机器代码)直接输入到内存位置,例如 e ffcb d2 将内存 ffcb 位置修改为 d2
fillFrange list用连续重复的值填充内存范围,例如 f 100 12f 'BUFFER' 将地址 100 到 12f 之间的区域循环用 BUFFER 填充
goG[=address] [addresses]运行直到断点或指定的内存地址
hexHvalue1 value2十六进制加法操作
inputIport进行 IO 操作
loadL[address] [drive] [firstsector] [number]加载指定内存地址、驱动器、扇区 number 数量的值到内存中
moveMrange address将指定范围内的所有字节复制到新地址,例如 m 7c00 7cff 600 将内存 7c00 到 7cff 范围内的信息复制到内存地址 600 起始的位置
nameN[pathname] [arglist]加载指定的 com 文件
outputOport byte进行 IO 操作
proceedP[=address] [number]单步执行,但跳过函数
quitQ 退出调试
registerR[register]显示所有寄存器及存储的内容
searchSrange list在内存范围内查询一个或多个字节值,例如 s fe00:0 ffff "BIOS" 命令在 fe00:0 ffff 范围内查找了 BIOS 字符串
traceT[=address] [number]单步执行,进入函数
unassembleU[range]反汇编指定内存范围内的指令,默认从 0010 开始进行反汇编 32 字节
writeW[address] [drive] [firstsector] [number]将程序从 DEBUG 中保存到硬盘

 

FreeDos 的开启

bochs 如何模拟 dos 环境,加载我们的程序呢?

我们可以下载 bochs 官方提供的 FreeDos 镜像:http://bochs.sourceforge.net/guestos/freedos-img.tar.gz

解压后,得到 FreeDos 的软盘镜像:a.img,将该文件路径配置到 bochsrc 的 floppya 配置项中,就可以打开 Dos 系统了

为了区分,我们将 a.img 重命名为 freedos.img

 

Dos 程序加载

可是在虚拟机中的 FreeDos 系统,我们要如何才能加载宿主机上我们要调试的系统呢?

只要把需要调试的系统烧录到另一个软盘镜像上,作为 bochs 另一个盘启动,位于 floppya 中的 FreeDos 系统就可以找到这个文件了

 

生成软盘镜像

首先我们需要创建一个软盘镜像

bochs 提供了 bximage 命令, 用来生成磁盘镜像文件:

 

 

格式化软盘

a.img 是一个镜像文件,我们需要将这个镜像装载为软盘,才能够完成镜像的格式化,并拷入我们需要的程序文件

这就需要使用 Linux 中的 loop 设备,类似于 Windows 的虚拟光驱

如果你是在 windows 环境下使用 WSL,那么很遗憾,当前版本 wsl 不支持 loop 设备,你可以下载虚拟软驱加载 a.img 完成这些操作

在 Linux 环境下,依次执行下列命令格式化我们生成的软盘镜像:

dd if=/dev/null of=a.img bs=512 count=1 conv=notrunc # 写入空白内容

sudo losetup /dev/loop0 a.img # 将 a.img 更改为 loop device

sudo mkfs.msdos /dev/loop0 # 格式化为 DOS 文件系统格式

sudo fsck.msdos /dev/loop0 # 检视文件系统

sudo losetup -d /dev/loop0 # 删除临时 loop device

 

执行 file a.img,可以看到下面的信息,说明已经格式化完成:

a.img: DOS floppy 1440k, x86 hard disk boot sector

 

汇编程序

我们需要按照上面说的,将代码第一行的“org 07c00h”改为“org 0100h”,并执行汇编操作生成 COM 文件:

nasm boot.asm –o boot.com

 

将 boot.com 复制到软盘

然后执行下面命令将 boot.com 复制到软盘 a.img 中:

sudo mkdir /mnt/floppy                             # 创建挂载点

sudo mount -o loop a.img /mnt/floppy      # 挂载 loop 设备 a.img

sudo cp boot.com /mnt/floppy                  # 将 boot.com 复制到 a.img

sudo umount /mnt/floppy                          # 接触挂载

 

配置 bochsrc

############################################################### # Configuration file for Bochs ############################################################### # how much memory the emulated machine will have megs: 32 # filename of ROM images #romimage: file=/usr/local/share/bochs/BIOS-bochs-latest romimage: file=$BXSHARE/BIOS-bochs-latest #vgaromimage: /usr/local/share/vgabios/vgabios.bin vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest # what disk images will be used floppya: 1_44=C:\Debin\Workspace\code\oranges\freedos\freedos.img, status=inserted floppyb: 1_44=C:\Debin\Workspace\code\oranges\freedos\a.img, status=inserted # choose the boot disk. boot: floppy # where do we send log messages? # log: bochsout.txt # disable the mouse mouse: enabled=0 # enable key mapping, using US layout as default. keyboard: keymap=$BXSHARE/keymaps/x11-pc-us.map mouse: enabled=1 mouse: type=imps2, enabled=1 mouse: type=serial, enabled=1 mouse: enabled=0, toggle=ctrl+f10

 

 

执行程序

运行 bochs,即可打开 Dos 系统,执行 b:\boot.com

 

 

上述的调试方法有一个问题,那就是 DOS 的 debug32 工具无法调试保护模式内的程序,这在我们调试操作系统的时候会产生巨大的难题

有没有办法用 bochs 调试 freedos 里运行的程序呢?

既然 freedos 也是运行在 bochs 下的,那答案当然是有的,bochs 提供了更为通用的 magic break 功能

只需要在 bochs 配置文件末尾添加:

magic_break: enabled=1

 

然后在希望加断点的地方写入:

xchg bx, bx

 

 

就可以加入断点了

 

 

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

 

 

http://bochs.sourceforge.net/

http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html

https://www.dosbox.com/

https://www.gsp.com/cgi-bin/man.cgi?section=5&topic=bochsrc

https://montcs.bloomu.edu/Information/LowLevel/DOS-Debug.html

 






操作系统      os      虚拟机      调试      bochs      dos      dosbox      debug     


京ICP备15018585号