ntdll: Fix SIGTRAP handling

Petr Tesarik hat at tesarici.cz
Mon Mar 27 08:58:38 CST 2006

Dne 03/27/06 v 16:05:15 (+0200), Alexandre Julliard napsal(a):
> Petr Tesarik <hat at tesarici.cz> writes:
> > No, Windows need not do things like that, because the Windows kernel
> > knows very well, whether it got INT1 or INT3... Some UNIX kernels do
> > not give us that information reliably.
> I'm afraid it's not acceptable to do things differently, especially
> not things like the checking of the previous instruction that may
> cause extra exceptions. Also stuff like the clearing of DR6 needs a
> test case, that's something that's visible from the application.

Oh, I forgot to mention another thing.  I didn't start all this for
nothing.  I made my changes to raise_trap_exception() to make an
existing application (Kindler Lexikon) work.

Now, the copy protection mechanism in Kindler Lexikon uses a DOS
application (no kidding!), so if you accept the VM86-related stuff
that I posted earlier, so that raise_trap_exception() is not used for
VM86-generated debug traps, it would probably be enough.

However, as a side effect I noticed that the code does not work well,
so I fixed it.  If my fix is not good enough, well, then the UNIX ABI
is not good enough, because:

1. A SIGTRAP can be delivered as a result of:

   a. INT 1 (single step or hardware breakpoint)
   b. INT 3 (INT3 or INT 03)
   c. kill() or tgkill() on the process

2. sc_trapno in sigcontext is set correctly by Linux only for 1a and
   1b.  The value of sc_trapno for 1c is undefined (and it may be even
   1 or 3; I can provide a test case if needed).

3. Since you want to raise a BREAKPOINT exception for 1c, a BREAKPOINT
   exception with ExceptionAddress decremented by 1 for 1b and a
   SINGLE_STEP exception for 1a, you have to distinguish between those
   three cases.

4. You can tell the 1c case from 1b or 1c from the si_code in siginfo.
   However, this field might not be available.  Things are even worse,
   because even TRAP_sig might be unavailable on some platforms!

5. Since the kernel does not provide enough information to distinguish
   between 1a, 1b and 1c, you have to investigate the reason

   There is no other way to detect a hardware breakpoint than to look
   at DR6.  Additionally, since the bits would get stuck for all
   subsequent SIGTRAPs, we need to clear them.

   There is no other way to detect an INT3 breakpoint than to look at
   the code that immediately precedes the exception address.  However,
   there is no guarantee that this address is mapped at all (a
   hardware breakpoint may occur anywhere, even at the first opcode of
   a page).  Since native Windows won't crash in such cases, neither
   should we.  That's why the whole thing is in a TRY block.

Pretty long, huh?

Petr Tesarik

More information about the wine-devel mailing list