Re: ptrace single-stepping change breaks Wine

From: Eric Pouech
Date: Mon Nov 22 2004 - 16:26:46 EST


Jesse Allen a écrit :
On Fri, Nov 19, 2004 at 01:53:38PM -0800, Linus Torvalds wrote:


On Fri, 19 Nov 2004, Daniel Jacobowitz wrote:

I'm getting the feeling that the question of whether to step into
signal handlers is orthogonal to single-stepping; maybe it should be a
separate ptrace operation.

I really don't see why. If a controlling process is asking for single-stepping, then it damn well should get it. It it doesn't want to single-step through a signal handler, then it could decide to just put a breakpoint on the return point (possibly by modifying the signal handler save area).

It's not like single-stepping into the signal handler in any way removes any information (while _not_ single-stepping into it clearly does).

With the patch I just posted (assuming it works for people), Wine should at least have the choice. The behaviour now should be:

- if the app sets TF on its own, it will cause a SIGTRAP which it can catch.
- if the debugger sets TF with SINGLESTEP, it will single-step into a signal handler.
- it the app sets TF _and_ you ptrace it, you the ptracer will see the debug event and catch it. However, doing a "continue" at that point
will remove the TF flag (and always has), the app will normally then
never see the trap. You can do a "signal SIGTRAP" to actually force
the trap handler to tun, but that one won't actually single-step (it's a "continue" in all other senses).

It sounds like the third case is what wine wants.

Linus



So an app running through wine could set TF on it's own? It would be a good idea to find out what it is doing in the first place. There has to be
a reason why War3 is so picky after the original change was introduced and
a reason why the latest changes don't seem to fix it.

I've built a kernel 2.6.10-rc2 with the new ptrace patch. The program still
says "please insert disc". I haven't been able to get winedbg to tell me anything useful -- the program never crashes anyways. So I went ahead and I captured a debug log.

the command:
WINEDEBUG=+all wine war3/Warcraft\ III.exe -opengl >& war3_and_2.6.10-rc2.log

I scanned for the part right before it calls up to display the error. I found
that after loading advapi32.dll, the thread 000c creates a mutex and wakes up
000a. Then 000c gets killed and right after that starts calling up the resources for the "insert disc" message box. I put the log up on my ftp, and the interesting part in a seperate file:
ftp://resnet.dnip.net/

Any clue on what may be happening here? Or maybe another idea on where else to search?


Jesse



For the linux folks, here a small comparison of what happens in the working (old) case and in the non-working (new) case:

In both case

- Wine gets a first SIGTRAP (in it's sig_trap handler)
+ Wine converts it into a Windows exception (w-exception in short).
This includes creating a context for the generic CPU registers
+ This w-exception is sent to the w-exception handler the program
installed (this one can modifiy the all registers)
o this handler touches one of the i386 debug registers
+ as we need to update the debug registers values (and we don't do in
the signal handler return), this task is delegated to the Wine server
(our central process, which is in charge of synchronisation...)
> the Wine server ptrace-attach:es to the process which handled
the SIGTRAP.
> Wine server wait4:s on the SIGSTOP (after ptrace:attach)
> modify (with ptrace) the debug registers
> and resumes excution (ptrace: cont)
+ wine terminates the sig trap handler and resumes the execution with
the modified basic registers (from the saved context), and the
modified debug registers (from the Wine server round trip)
- a second sig trap is generated
> since the wine server is still ptrace:attached, it gets the signal.

What differs then in both execution:
- in the working case, the sig trap handler is called on the client side, whereas it's never called in the non-working case. We do have a couple of protection (to avoid some misbehaving apps), but none of them get triggered. So it seems like the trap handler is not called (ugh).

A couple of notes:
- as the program tested is copy protected, and as it seems that the copy protection is what causes the harm, it can be interesting to know that the programe seems to set the TF flag (some copy protection schemes directly do an "int 1", but given the exception code we get, this isn't the case).
- in Windows trap handling, the TF is explictly reset before calling the windows exception handler (which is what Wine does, before calling the window exception handler). Of course the handler can set it back if it wants to continue single stepping.

HTH
A+

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/