Dne 03/27/06 v 16:05:15 (+0200), Alexandre Julliard napsal(a):
Petr Tesarik hat@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 yourself.
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