http://bugs.winehq.org/show_bug.cgi?id=10249
Summary: Battlefield2/SafeDisc 4.x and Punkbuster services cause lockup: child processes debugging misconception Product: Wine Version: CVS/GIT Platform: PC OS/Version: Linux Status: UNCONFIRMED Severity: major Priority: P2 Component: wine-kernel AssignedTo: wine-bugs@winehq.org ReportedBy: focht@gmx.net
Created an attachment (id=8876) --> (http://bugs.winehq.org/attachment.cgi?id=8876) WINEDEBUG=-all,+server,+tid,+loaddll,+seh wine ./BF2.exe +fullscreen 0 +szx 800 +szy 600 &>/tmp/debug_pipe
Hello,
while testing some PunkBuster stuff on popular games, I came across Battlefield 2 which employs SafeDisc 4.x It seems there is a problem with debuggers in chained child processes.
Consider following scenario:
--- snip process list --- pid threads parent executable (all id:s are in hex) 0000001b 1 00000008 'PnkBstrA.exe' 0000000c 2 00000008 'explorer.exe' 0000000a 2 00000008 '~e5.0001' 00000008 4 00000000 'BF2.exe' --- snip process list ---
--- snip thread list --- process tid prio (all id:s are in hex) 0000001b 0000001c 0 0000000c 00000010 0 0000000d 0 0000000a 00000012 0 0000000b 0 00000008 0000001a 1 00000014 15 00000013 0 00000009 0 --- snip thread list ---
"BF2.exe" = parent (game) "~e5.0001" = 1st child = SafeDisc 4.x process = "debugger" "PnkBstrA.exe" = 2nd child = PunkBuster Update Service
The 1st child acts as debugger for the parent "BF2.exe" and receives all debug events (process, thread creation, dll load/unload...) There are lots of breakpoint events triggered from parent. This is part of SafeDisc 4.x and used for on-the-fly decryption of code sections (child decrypts code of father).
When PunkBuster is initialized (loading of pbcl = client, pbag = agent), the following services should get started: PnkBstrA.exe, PnkBstrB.exe and finally the kmode driver PnkBstrK.exe The service process "PnkBstrA.exe" is started from main process "BF2.exe" (which is a debuggee itself). No debug flags (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS) are specified in process creation flags. The debugger (child of parent, receives the process creation event) does not make debugger_attach() to the newly created child process.
The child process seems to inherit the state of being a "debuggee": wine server -> new_process -> set_process_debugger( process, parent->debugger ); The parent got its process->debugger from debugger_attach().
This leads to a problem in child process startup code: "dlls/kernel32/process.c:start_process()" checks the PEB->BeingDebugged field and if set, a system breakpoint is encountered before the entry code is called. This breakpoint results in debug event - seen by debugger. Unfortunately this event is _not_ expected by debugger because it didn't expect another debuggee (child) to be created.
Ok, long story short solution: If you debug a process by attaching to an already created process, you _must_ treat default debugging flags as if the process has been created with DEBUG_ONLY_THIS_PROCESS, meaning that all childs created by debuggee will NOT automagically become debuggees.
Short and (hopefully) acceptable patch snippet:
--- snip ---
diff --git a/server/debugger.c b/server/debugger.c index a64a17a..c59f3a0 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -444,6 +444,7 @@ static int debugger_attach( struct process *process, struct thread *debugger ) resume_process( process ); return 0; } + process->create_flags |= DEBUG_ONLY_THIS_PROCESS; return 1;
error:
--- snip ---
And yes, the patch (snippet) works as intended (tm) ;-)
Attached for sake of completeness is relevant server trace. Search for "001c:trace:seh:raise_exception code=80000003 flags=0 addr=0x7b870ed8 " to the point where the entry system breakpoint is triggered.
Regards