如何在没有无限循环的情况下在硬件断点后恢复执行?

How is execution resumed after a hardware breakpoint without an infinite loop?

据我所知,软件断点的工作方式如下:

BP 设置的指令被 int/trap 指令取代,比陷阱在陷阱处理程序中处理,继续陷阱被原始指令替换,指令被单次执行步进模式,现在 PC 指向下一条指令,原始指令再次被 int/trap 指令替换。

HW Breakpoints根据我的理解工作如下:

BP设置的指令地址写入HW-BP寄存器。如果分别命中指令,则 PC 与 HW-BP 寄存器中的地址相匹配,CPU 引发中断,该中断也由陷阱处理程序处理。现在,如果程序 returns 到原始指令,HW BP 仍然处于活动状态并且一个陷入无限循环。

这个问题是怎么处理的?

HW BP在继续之前是否被禁用,原始指令是否也在单步模式下执行?还是原来的指令在trap handler进入之前执行,让trap handlerreturns到原来指令之后的指令?还是有其他机制?

对于 Intel 64 和 IA-32(“x64/x86”)架构,这是 恢复标志 (RF) 第 16 位的任务在 EFLAGS 中。 (其他支持硬件断点的处理器架构可能也有类似的机制。)

请参阅 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3B 中的第 18.3.1.1 节:

Because the debug exception for an instruction breakpoint is generated before the instruction is executed, if the instruction breakpoint is not removed by the exception handler; the processor will detect the instruction breakpoint again when the instruction is restarted and generate another debug exception. To prevent looping on an instruction breakpoint, the Intel 64 and IA-32 architectures provide the RF flag (resume flag) in the EFLAGS register (see Section 2.3, “System Flags and Fields in the EFLAGS Register,” in the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A). When the RF flag is set, the processor ignores instruction breakpoints.

[...]

The RF Flag is cleared at the start of the instruction after the check for code breakpoint, CS limit violation and FP exceptions.

[...]

If the RF flag in the EFLAGS image is set when the processor returns from the exception handler, it is copied into the RF flag in the EFLAGS register by IRETD/IRETQ or a task switch that causes the return. The processor then ignores instruction breakpoints for the duration of the next instruction. (Note that the POPF, POPFD, and IRET instructions do not transfer the RF image into the EFLAGS register.) Setting the RF flag does not prevent other types of debug-exception conditions (such as, I/O or data breakpoints) from being detected, nor does it prevent non-debug exceptions from being generated.

(强调我的。)

因此,调试器将在从异常处理程序返回之前设置 RF,以便指令断点对于一条指令“静音”,之后处理器自动清除该标志。

请注意,在数据断点的情况下这不是问题,因为这些将在触发 read/write 操作的指令之后触发


建议:我发现the slides of "Intermediate x86 Part 4" by Xeno Kovah有助于理解这些东西。他在那里谈论各种话题,但从调试开始。这些信息尤其可以在幻灯片 12-13 中找到:

图片来源:Xeno Kovah,CC BY-SA 3.0