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
Monday, March 27, 2006, 7:58:38 AM, Petr Tesarik wrote:
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.
[skip]
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.
[skip]
If you need a program that uses DR6 for copy protection and will brake if you touch anything in it look here: http://bugs.winehq.org/show_bug.cgi?id=4036 It's using hardware breakpoints for lots of nasty things. And depends on the _exact_ content of the DR* registers when exception handler is called. Also it sets those registers only once. So if you alter any of the DR* registers in any way, this copy protection will brake.
Please don't forget here that we are not inventing something new. We can not deviate from what native does, or it will brake some applications. If you have a test case that shows that windows does what you trying to do - I would like to see it. Or you could write your own test to test this on windows.
Vitaliy.
Dne 03/27/06 v 08:13:23 (-0700), Vitaliy Margolen napsal(a):
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.
[skip]
Please don't forget here that we are not inventing something new. We can not deviate from what native does, or it will brake some applications. If you have a test case that shows that windows does what you trying to do - I would like to see it. Or you could write your own test to test this on windows.
Maybe, you're missing my point. I'm trying to avoid DR6 altogether. And I can do it on some platforms. However, some Unixes seem to be crippled and I'm trying to provide a reasonable fallback for them.
BTW if we forbid sending SIGTRAP to a Wine process, there will be more such platforms. AFAIK SIGTRAP is only sent internally by wineserver for DebugBreakProcess(). I'll have a look at it.
Petr Tesarik
Petr Tesarik hat@tesarici.cz writes:
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.
Sure, I'm not saying you did this for no reason. I just have the feeling you are changing a lot of things that don't need to be changed. This is a sensitive area of the code that a lot of apps depend on, and we have to be very careful about making changes.
[...] Pretty long, huh?
The thing is that all of this is necessary because you want to handle a SIGTRAP sent with kill(). But obviously no Windows application is going to send us a SIGTRAP; the only way this will happen is when we do it ourselves in DebugBreakProcess, and there's nothing that says that we can't use a different mechanism here if it works better. I'd say that somehow reusing the existing SIGUSR1 support is probably a better choice.