XP debugging features

Eric Pouech eric.pouech at wanadoo.fr
Sat Feb 23 15:58:34 CST 2002


XP adds a few new debugging APIs. The most interesting is used to
detach the debugger from its debuggee(s) without actually killing the
debuggee. 
this patch implements this (as well as two other untested features)

A+
-------------- next part --------------
Name: xp_dbg
ChangeLog: new XP debugging APIs:
	\timplemented DebugActiveProcessStop, DebugSetProcessKillOnExit, DebugBreakProcess)
GenDate: 2002/02/23 21:32:29 UTC
ModifiedFiles: include/winbase.h dlls/kernel/kernel32.spec dlls/kernel/debugger.c server/protocol.def server/debugger.c server/process.c server/process.h
AddedFiles: 
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/include/winbase.h,v
retrieving revision 1.134
diff -u -u -r1.134 winbase.h
--- include/winbase.h	31 Jan 2002 23:22:08 -0000	1.134
+++ include/winbase.h	1 Feb 2002 06:11:24 -0000
@@ -1135,7 +1135,10 @@
 HANDLE      WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES,BOOL,LPCWSTR);
 #define     CreateWaitableTimer WINELIB_NAME_AW(CreateWaitableTimer)
 BOOL        WINAPI DebugActiveProcess(DWORD);
+BOOL        WINAPI DebugActiveProcessStop(DWORD);
 void        WINAPI DebugBreak(void);
+BOOL        WINAPI DebugBreakProcess(HANDLE);
+BOOL        WINAPI DebugSetProcessKillOnExit(BOOL);
 BOOL        WINAPI DeregisterEventSource(HANDLE);
 BOOL        WINAPI DeviceIoControl(HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPOVERLAPPED);
 BOOL        WINAPI DisableThreadLibraryCalls(HMODULE);
Index: dlls/kernel/kernel32.spec
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/dlls/kernel/kernel32.spec,v
retrieving revision 1.46
diff -u -u -r1.46 kernel32.spec
--- dlls/kernel/kernel32.spec	29 Jan 2002 18:15:11 -0000	1.46
+++ dlls/kernel/kernel32.spec	29 Jan 2002 20:50:16 -0000
@@ -970,6 +970,11 @@
 @ stdcall SetCalendarInfoA(long long long str) SetCalendarInfoA
 @ stdcall SetCalendarInfoW(long long long wstr) SetCalendarInfoW
 
+# XP extensions
+@ stdcall DebugActiveProcessStop(long) DebugActiveProcessStop
+@ stdcall DebugBreakProcess(long) DebugBreakProcess
+@ stdcall DebugSetProcessKillOnExit(long) DebugSetProcessKillOnExit
+
 ################################################################
 # Wine extensions: Win16 functions that are needed by other dlls
 #
Index: dlls/kernel/debugger.c
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/dlls/kernel/debugger.c,v
retrieving revision 1.17
diff -u -u -r1.17 debugger.c
--- dlls/kernel/debugger.c	30 Nov 2001 18:46:43 -0000	1.17
+++ dlls/kernel/debugger.c	21 Feb 2002 21:40:15 -0000
@@ -6,6 +6,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <signal.h>
 
 #include "winerror.h"
 #include "wine/winbase16.h"
@@ -150,7 +151,7 @@
 /**********************************************************************
  *           DebugActiveProcess   (KERNEL32.@)
  *
- *  Attempts to attach the dugger to a process.
+ *  Attempts to attach the debugger to a process.
  *
  * RETURNS
  *
@@ -163,6 +164,30 @@
     SERVER_START_REQ( debug_process )
     {
         req->pid = (void *)pid;
+        req->attach = 1;
+        ret = !wine_server_call_err( req );
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+/**********************************************************************
+ *           DebugActiveProcessStop   (KERNEL32.@)
+ *
+ *  Attempts to detach the debugger from a process.
+ *
+ * RETURNS
+ *
+ *  True if the debugger was detached from the process.
+ */
+BOOL WINAPI DebugActiveProcessStop(
+    DWORD pid) /* [in] The process to be detached. */
+{
+    BOOL ret;
+    SERVER_START_REQ( debug_process )
+    {
+        req->pid = (void *)pid;
+        req->attach = 0;
         ret = !wine_server_call_err( req );
     }
     SERVER_END_REQ;
@@ -236,6 +261,29 @@
     DbgBreakPoint();
 }
 
+/***********************************************************************
+ *           DebugBreakProcess   (KERNEL32.@)
+ *
+ *  Raises an exception so that a debugger (if attached)
+ *  can take some action. Same as DebugBreak, but applies to any process.
+ */
+BOOL WINAPI DebugBreakProcess(HANDLE hProc)
+{
+    int res;
+    int pid;
+
+    TRACE("(%08lx)\n", (DWORD)hProc);
+
+    SERVER_START_REQ( get_process_info )
+    {
+        req->handle = hProc;
+        res = wine_server_call_err( req );
+        pid = (int)reply->pid;
+    }
+    SERVER_END_REQ;
+    return !res && kill(pid, SIGINT) == 0;
+}
+
 
 /***********************************************************************
  *           DebugBreak   (KERNEL.203)
@@ -309,3 +357,23 @@
     /* Output */
     FIXME("%s %04x %s\n", caller, flags, debugstr_a(MapSL(spec)) );
 }
+
+/***********************************************************************
+ *           DebugSetProcessKillOnExit                    (KERNEL.328)
+ *
+ * Let a debugger decide wether a debuggee will be killed upon debugger
+ * termination
+ */
+BOOL        WINAPI DebugSetProcessKillOnExit(BOOL kill)
+{
+    BOOL ret = FALSE;
+
+    SERVER_START_REQ( set_debugger_kill_on_exit )
+    {
+        req->kill_on_exit = kill;
+        ret = !wine_server_call_err( req );
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
Index: server/protocol.def
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/server/protocol.def,v
retrieving revision 1.24
diff -u -u -r1.24 protocol.def
--- server/protocol.def	9 Jan 2002 21:16:24 -0000	1.24
+++ server/protocol.def	21 Feb 2002 20:54:46 -0000
@@ -1117,11 +1119,17 @@
 @END
 
 
-/* Start debugging an existing process */
+/* Start/Stop debugging an existing process */
 @REQ(debug_process)
     void*        pid;          /* id of the process to debug */
+    int          attach;       /* 1=attaching / 0=detaching from the process */
 @END
 
+
+/* Set debugging features */
+ at REQ(set_debugger_kill_on_exit)
+    unsigned int kill_on_exit;  /* 0=detach/1=kill debuggee when debugger dies */
+ at END
 
 /* Read data from a process address space */
 @REQ(read_process_memory)
Index: server/debugger.c
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/server/debugger.c,v
retrieving revision 1.35
diff -u -u -r1.35 debugger.c
--- server/debugger.c	20 Dec 2001 00:07:08 -0000	1.35
+++ server/debugger.c	21 Feb 2002 21:44:00 -0000
@@ -38,6 +38,7 @@
     struct object        obj;         /* object header */
     struct debug_event  *event_head;  /* head of pending events queue */
     struct debug_event  *event_tail;  /* tail of pending events queue */
+    int                  kill_on_exit;/* kill debuggees on debugger exit ? */
 };
 
 
@@ -422,11 +423,13 @@
 
     /* we must have been able to attach all threads */
     for (thread = process->thread_list; thread; thread = thread->proc_next)
+    {
         if (!thread->attached)
         {
             resume_process( process );
             goto error;
         }
+    }
 
     if (set_process_debugger( process, debugger )) return 1;
     resume_process( process );
@@ -437,6 +440,66 @@
     return 0;
 }
 
+/* detach a process from a debugger thread (and resume it ?) */
+int debugger_detach( struct process *process, struct thread *debugger )
+{
+    struct thread *thread;
+    struct debug_event *event;
+    struct debug_ctx *debug_ctx;
+
+    if (!process->debugger || process->debugger != debugger)
+        goto error;  /* not currently debugged, or debugged by another debugger */
+    if (!debugger->debug_ctx ) goto error; /* should be a debugger */
+    /* init should be done, otherwise wouldn't be attached */
+    assert(!process->init_event);
+
+    suspend_process( process );
+    /* send continue indication for all events */
+    debug_ctx = debugger->debug_ctx;
+
+    /* find the event in the queue
+     * FIXME: could loop on process' threads and look the debug_event field */
+    for (event = debug_ctx->event_head; event; event = event->next)
+    {
+        if (event->state != EVENT_QUEUED) continue;
+        
+        if (event->sender->process == process)
+        {
+            assert( event->sender->debug_event == event );
+            event->status = DBG_CONTINUE;
+            event->state  = EVENT_CONTINUED;
+            wake_up( &event->obj, 0 );
+            
+            unlink_event( debug_ctx, event );
+            
+            /* from queued debug event */
+            resume_process( process );
+        }
+    }
+
+    /* remove relationships between process and its debugger */
+    process->debugger = NULL;
+    release_object( debugger->debug_ctx );
+    debugger->debug_ctx = NULL;
+    
+    /* now detach all the threads */
+    for (thread = process->thread_list; thread; thread = thread->proc_next)
+    {
+        if (thread->attached)
+        {
+            detach_thread( thread, 0 );
+        }
+    }
+
+    /* from this function */
+    resume_process( process );
+    return 0;
+
+ error:
+    set_error( STATUS_ACCESS_DENIED );
+    return 0;
+}
+
 /* generate all startup events of a given process */
 void generate_startup_debug_events( struct process *process, void *entry )
 {
@@ -470,6 +533,7 @@
         if (!(debug_ctx = alloc_object( &debug_ctx_ops, -1 ))) return 0;
         debug_ctx->event_head = NULL;
         debug_ctx->event_tail = NULL;
+        debug_ctx->kill_on_exit = 1;
         debugger->debug_ctx = debug_ctx;
     }
     process->debugger = debugger;
@@ -481,8 +545,15 @@
 {
     if (thread->debug_ctx)  /* this thread is a debugger */
     {
-        /* kill all debugged processes */
-        kill_debugged_processes( thread, thread->exit_code );
+        if (thread->debug_ctx->kill_on_exit)
+        {
+            /* kill all debugged processes */
+            kill_debugged_processes( thread, thread->exit_code );
+        }
+        else
+        {
+            detach_debugged_processes( thread );
+        }
         release_object( thread->debug_ctx );
         thread->debug_ctx = NULL;
     }
@@ -538,12 +609,17 @@
 /* Start debugging an existing process */
 DECL_HANDLER(debug_process)
 {
-    struct debug_event_exception data;
     struct process *process = get_process_from_id( req->pid );
     if (!process) return;
 
-    if (debugger_attach( process, current ))
+    if (!req->attach)
+    {
+        debugger_detach( process, current );
+    }
+    else if (debugger_attach( process, current ))
     {
+        struct debug_event_exception data;
+
         generate_startup_debug_events( process, NULL );
         resume_process( process );
 
@@ -621,4 +697,14 @@
     data.unicode = req->unicode;
     data.length  = req->length;
     generate_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, &data );
+}
+
+DECL_HANDLER(set_debugger_kill_on_exit)
+{
+    if (!current->debug_ctx)
+    {
+        set_error( STATUS_ACCESS_DENIED );
+        return;
+    }
+    current->debug_ctx->kill_on_exit = req->kill_on_exit;
 }
Index: server/process.c
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/server/process.c,v
retrieving revision 1.76
diff -u -u -r1.76 process.c
--- server/process.c	20 Dec 2001 00:07:09 -0000	1.76
+++ server/process.c	23 Feb 2002 21:24:53 -0000
18 a debugger from all its debuggees */
+void detach_debugged_processes( struct thread *debugger )
+{
+    struct process *process;
+    for (process = first_process; process; process = process->next)
+    {
+        if (process->debugger == debugger && process->running_threads)
+        {
+            debugger_detach( process, debugger );
+        }
+    }
+}
+
+
 /* get all information about a process */
 static void get_process_info( struct process *process, struct get_process_info_reply *reply )
 {
Index: server/process.h
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/server/process.h,v
retrieving revision 1.24
diff -u -u -r1.24 process.h
--- server/process.h	4 Dec 2001 20:17:44 -0000	1.24
+++ server/process.h	21 Feb 2002 20:46:16 -0000
@@ -71,6 +73,8 @@
 extern struct process *get_process_from_id( void *id );
 extern struct process *get_process_from_handle( handle_t handle, unsigned int access );
 extern int process_set_debugger( struct process *process, struct thread *thread );
+extern int debugger_detach( struct process* process, struct thread* debugger );
+
 extern void add_process_thread( struct process *process,
                                 struct thread *thread );
 extern void remove_process_thread( struct process *process,
@@ -80,6 +84,7 @@
 extern void kill_process( struct process *process, struct thread *skip, int exit_code );
 extern void kill_console_processes( struct thread *renderer, int exit_code );
 extern void kill_debugged_processes( struct thread *debugger, int exit_code );
+extern void detach_debugged_processes( struct thread *debugger );
 extern struct process_snapshot *process_snap( int *count );
 extern struct module_snapshot *module_snap( struct process *process, int *count );
 


More information about the wine-patches mailing list