Re: [patch 2/2] x86 NMI-safe INT3 and Page Fault

Maciej W. Rozycki
2010-07-14T20:36:35Z

On Wed, 14 Jul 2010, Mathieu Desnoyers wrote:

> It tests it too. When it detects that the return path is about to return to a
> NMI handler, it checks if the TF flag is set. If it is set, then "iret" is
> really needed, because TF can only single-step an instruction when set by
> "iret". The popf/ret scheme would otherwise trap at the "ret" instruction that
> follows popf. Anyway, single-stepping is really discouraged in nmi handlers,
> because there is no way to go around the iret.

Hmm, with Pentium Pro and more recent processors there is actually a
nasty hack that will let you get away with POPF/RET and TF set. ;) You
can try it if you like and can arrange for an appropriate scenario.

> In the case of temporary bypass, the int3 is only there to divert the
> instruction execution flow to somewhere else, and we come back to the original
> code at the address following the instruction which has the breakpoint. So
> basically, we never come back to the original instruction, ever. We might as
> well just clear the RF flag from the EFLAGS image before popf.

Yes, if you return to elsewhere, then that's actually quite desirable
IMHO.

This RF flag is quite complicated to handle and there are some errata
involved too. If I understand it correctly, all fault-class exception
handlers are expected to set it manually in the image to be restored if
they return to the original faulting instruction (that includes the debug
exception handler if it was invoked as a fault, i.e. in response to an
instruction breakpoint). Then all trap-class exception handlers are
expected to clear the flag (and that includes the debug exception handler
if it was invoked as a trap, e.g. in response to a data breakpoint or a
single step). I haven't checked if Linux gets these bits right, but it
may be worth doing so.

For the record -- GDB hardly cares, because it removes any instruction
breakpoints before it is asked to resume execution of an instruction that
has a breakpoint set at, single-steps the instruction with all the other
threads locked out and then reinserts the breakpoints so that they can hit
again. Then it proceeds with whatever should be done next to fulfil the
execution request.

Maciej