bochs 中文文档 下载 App

单步执行与继续——step、next、fin 和控制流

四条控制命令

命令含义类比 GDB行为
s(或 step)单步si(step instruction)执行一条指令,停住
n(或 next)单步跳过ni(next instruction)执行一条指令,但如果是 CALL/INT 就跳过整个被调过程
fin(或 step out)跳出finish从当前 CALL 中返回
c(或 continue)继续c一直跑到下一个断点或 Ctrl+C

单步 vs 单步跳过:区别在哪

假设你在调试一个 Bootloader,里面有一个 call print_msg:

用 s(step)

bochs:1> s
# 进入 print_msg 的第一条指令
bochs:2> u
0000000000007c50: push bp
0000000000007c51: mov bp, sp
...

你会一步一步跟随 CALL 进入被调函数内部,可以调试被调函数里的每一步。

用 n(next)

bochs:1> n
# 直接跨过 call,停在 call 后面那条指令
bochs:2> u
0000000000007c40: mov ax, 0x7c00
0000000000007c43: ret

call 里面的代码被完整执行完了(包括 print_msg 的 push/mov/pop/ret),但你停在 call 返回后的位置。适合"我不想进这个被调函数,只想看 call 返回后发生了什么"。

类比

场景用
想深入理解某个函数内部做了什么s 跟踪进入
不想进某个库函数(比如 BIOS interrupt)n 跳过
调试中断处理s(因为 int 不能被 n 跳过)

fin:跳出当前函数

当你用 s 跟踪进入一个 CALL 后,如果想快速返回到 CALL 发起者那里:

bochs:1> fin
# Bochs 会在栈上找返回地址,执行完当前函数后停住

fin 的实现原理:Bochs 会在当前栈帧的返回地址处设一个临时断点,然后 continue。当被调函数执行 ret 时,返回地址就是断点位置——自动停住并删除临时断点。

Ctrl+C:随时打断执行

c 继续执行时,按 Ctrl+C 可以随时中断执行、回到调试器提示:

bochs:1> c
# ... Bochs 正在运行内核 ...
# Ctrl+C
bochs:2>

Bochs 会在当前指令执行完后停住(不是在指令中间)。你可以用 u 看看刚才 CPU 在跑什么,用 info registers 看看当时的状态。

如果 Bochs 不响应 Ctrl+C(模拟卡死掉了),关闭模拟窗口是终极手段——bochsrc 里设了 panic: action=ask 的话,panic 事件也会自动进入调试器。

单步陷阱(TF 标志位)

CPU 的 TF(Trap Flag,EFLAGS bit 8)= 1 时,每条指令执行完后都会自动触发一个 #DB(Debug Exception)。Bochs 调试器用这个机制实现了单步功能——s 命令本质上是设置 TF 后 continue,#DB 异常触发时停住。

OS 内核也可能用 TF 标志做自己的事情——比如调试子系统、性能分析。如果内核启动后 TF 被设置,每条指令都会触发异常,Bochs 单步会"每次跑一条异常"。这种情况:

bochs:1> info flags
 iopl=0         nv up ei pl nz na po nc
                ↑ TF 位为 1
bochs:2> set $tf = 0        # 关掉 TF

一条经典的单步调试流程

OS 开发者调试 Bootloader 的标准流程:

bochs:1> pb 0x7c00            # 在引导扇区入口下断点
bochs:2> c                    # 继续执行,BOIS 加载引导扇区后跳转
# 断点触发:
bochs:3> u                    # 反汇编看看是什么指令
bochs:4> info registers       # 看 CS/IP/SS/SP/FLAGS 是否符合预期
bochs:5> s                    # 单步执行第一条指令
bochs:6> s                    # 再单步... 逐步理解 Bootloader 逻辑
bochs:7> ...
# 遇到 int 0x10(BIOS 中断)时,用 s 还是 n?
bochs:20> n                   # 用 n 跳过 BIOS 内部(BIOS 内部几千行指令,不关心)

这条流程让你能逐步"看到"Bootloader 从第一条 jmp 到最后的进入内核,每一步 CPU 寄存器、内存的变化都在你眼前——这是 OS 课程实验的核心。

小结

想做什么命令
跑起来到下一个断点c
执行一条指令(进入 CALL)s
执行一条指令(跳过 CALL)n
从当前 CALL 返回fin
随时中断Ctrl+C