QEMU Exception Handling
我在测试一些会产生保护错误的代码时遇到了一个错误。我设置了异常处理程序,以便它期望 EIP 和堆栈不会改变,这是本机 CPU 上的标准行为。但是在 QEMU 上,ESP 和 EIP 在故障生成时都发生了变化。
操作系统是32位的,所以错误情况与跳出CS段有关。
深入研究 QEMU 代码,似乎在 helper_ret_protected 中调用 raise_exception_error 之后设置了 EIP 和 ESP。所以,我不明白为什么我在客人身上看到了不同的行为。
我不明白 QEMU 是如何产生异常的,在调用 ret_protected 方法之后是否还有另一个步骤?
出现异常时,CPU 将在跨越特权级别边界时切换堆栈。
因此,TSS 包含每个级别的 SS 和 ESP 条目。如果触发故障的代码恰好在用户模式代码中,则堆栈将被更改。
SS:ESP 值从 TSS 的 ss0 和 ebp0 字段中读取。
我不太清楚你所说的"期望 EIP 不会改变"是什么意思。
如果你能提供更多关于你的问题的细节可能有助于找到正确的答案...
- 代码分配一个大的 CS,然后执行一个 Ret 将它放在 CS 之外。这会触发一般保护故障,因为代码已超过 CS 限制。在原生 CPU 中,当 GPF 被触发时,EIP 将指向 CS 中的错误指令。因此,在异常处理程序中,您可以找到错误指令,在 QEMU 上,EIP 在 CS 之外并且不指向错误指令。这更清楚吗?
-
@anandb 更清晰。谢谢!无论如何,您选择不使用扁平段是否有原因?你在裸机上测试过吗?调试(尤其是检查堆栈)怎么样?有问题的 ret 指令是否与切换到 PMode 相关?
-
顺便说一句,如果我没记错的话,异常堆栈上的 EIP 不会指向将控制权移出 CS 的 ret,而是指向实际的错误地址 - 不在 CS 中,所以除非我误解了你,这种行为对我来说似乎是正确的。
-
故障地址不是在 CS 中产生故障的指令之一吗?
-
@anandb 我认为它是异常实际发生的地址,即在 CS 之外 - 这就是触发异常的原因。如果您可以访问带有软盘驱动器和软盘的机器,那么很容易找到:从(平面)软盘启动您的代码并在 GPF 上打印堆栈。我认为它会在 CS 之外打印地址。抱歉不确定,我很久以前就做过这些事情......