debugger launch

eric pouech eric.pouech at wanadoo.fr
Sat Aug 11 14:18:50 CDT 2001


the current code, when several exception occur on different
threads of the same process, allows to try to launch a debugger for
each one of the threads...
this patch prevents this and makes the debugger launch an atomic
operation

A+
-- 
---------------
Eric Pouech (http://perso.wanadoo.fr/eric.pouech/)
"The future will be better tomorrow", Vice President Dan Quayle
-------------- next part --------------
Name: dbg_launch
ChangeLog: modified the debugger launching code so that only one instance of the debugger is created per process
GenDate: 2001/08/11 19:16:25 UTC
ModifiedFiles: win32/except.c
AddedFiles: 
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/win32/except.c,v
retrieving revision 1.45
diff -u -u -r1.45 except.c
--- win32/except.c	2001/07/19 00:39:11	1.45
+++ win32/except.c	2001/08/11 19:11:54
@@ -186,50 +186,22 @@
     return ret;
 }
 
-
-/*******************************************************************
- *         UnhandledExceptionFilter   (KERNEL32.@)
+/******************************************************************
+ *		start_debugger
+ *
+ * Does the effective debugger startup according to 'format'
  */
-DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
+static BOOL	start_debugger(PEXCEPTION_POINTERS epointers, HANDLE hEvent)
 {
-    char 		format[256];
-    char 		buffer[256];
     HKEY		hDbgConf;
     DWORD		bAuto = FALSE;
-    DWORD		ret = EXCEPTION_EXECUTE_HANDLER;
-    int status;
-
-    /* send a last chance event to the debugger */
-    status = send_debug_event( epointers->ExceptionRecord, FALSE, epointers->ContextRecord );
-    switch (status)
-    {
-    case DBG_CONTINUE: 
-        return EXCEPTION_CONTINUE_EXECUTION;
-    case DBG_EXCEPTION_NOT_HANDLED: 
-        TerminateProcess( GetCurrentProcess(), epointers->ExceptionRecord->ExceptionCode );
-        break; /* not reached */
-    case 0: /* no debugger is present */
-        if (epointers->ExceptionRecord->ExceptionCode == CONTROL_C_EXIT)
-        {
-            /* do not launch the debugger on ^C, simply terminate the process */
-            TerminateProcess( GetCurrentProcess(), 1 );
-        }
-        break;
-    default: 	
-        FIXME("Unsupported yet debug continue value %d (please report)\n", status);
-    }
-
-    if (top_filter)
-    {
-        DWORD ret = top_filter( epointers );
-        if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
-    }
-
-    /* FIXME: Should check the current error mode */
+    PROCESS_INFORMATION	info;
+    STARTUPINFOA	startup;
+    char		buffer[256];
+    char 		format[256];
 
     if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, 
-		     "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", 
-		     &hDbgConf)) {
+		     "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", &hDbgConf)) {
        DWORD 	type;
        DWORD 	count;
 
@@ -249,61 +221,150 @@
        }
        RegCloseKey(hDbgConf);
     } else {
-       /* format[0] = 0; */
-       strcpy(format, "debugger/winedbg %ld %ld");
+	/* try a default setup... */
+	strcpy( format, "debugger/winedbg %ld %ld" );
     }
 
     if (!bAuto)
     {
-        HMODULE mod = GetModuleHandleA( "user32.dll" );
-        MessageBoxA_funcptr pMessageBoxA = NULL;
-        if (mod) pMessageBoxA = (MessageBoxA_funcptr)GetProcAddress( mod, "MessageBoxA" );
-        if (pMessageBoxA)
-        {
-            format_exception_msg( epointers, buffer, sizeof(buffer) );
-            if (pMessageBoxA( 0, buffer, "Exception raised", MB_YESNO | MB_ICONHAND ) == IDNO)
-            {
-                TRACE("Killing process\n");
-                return EXCEPTION_EXECUTE_HANDLER;
-            }
-        }
+	HMODULE			mod = GetModuleHandleA( "user32.dll" );
+	MessageBoxA_funcptr	pMessageBoxA = NULL;
+
+	if (mod) pMessageBoxA = (MessageBoxA_funcptr)GetProcAddress( mod, "MessageBoxA" );
+	if (pMessageBoxA)
+	{
+	    format_exception_msg( epointers, buffer, sizeof(buffer) );
+	    if (pMessageBoxA( 0, buffer, "Exception raised", MB_YESNO | MB_ICONHAND ) == IDNO)
+	    {
+		TRACE("Killing process\n");
+		return FALSE;
+	    }
+	}
     }
 
-    if (format[0]) {
-       HANDLE			hEvent;
-       PROCESS_INFORMATION	info;
-       STARTUPINFOA		startup;
-       OBJECT_ATTRIBUTES	attr;
-
-       attr.Length                   = sizeof(attr);
-       attr.RootDirectory            = 0;
-       attr.Attributes               = OBJ_INHERIT;
-       attr.ObjectName               = NULL;
-       attr.SecurityDescriptor       = NULL;
-       attr.SecurityQualityOfService = NULL;
-
-       TRACE("Starting debugger (fmt=%s)\n", format);
-       NtCreateEvent( &hEvent, EVENT_ALL_ACCESS, &attr, FALSE, FALSE );
-       sprintf(buffer, format, GetCurrentProcessId(), hEvent);
-       memset(&startup, 0, sizeof(startup));
-       startup.cb = sizeof(startup);
-       startup.dwFlags = STARTF_USESHOWWINDOW;
-       startup.wShowWindow = SW_SHOWNORMAL;
-       if (CreateProcessA(NULL, buffer, NULL, NULL, 
-			  TRUE, 0, NULL, NULL, &startup, &info)) {
-	  WaitForSingleObject(hEvent, INFINITE);
-	  ret = EXCEPTION_CONTINUE_SEARCH;
-       } else {
-           ERR("Couldn't start debugger (%s) (%ld)\n"
-               "Read the Wine Developers Guide on how to set up winedbg or another debugger\n",
-               buffer, GetLastError());
-       }
-       CloseHandle(hEvent);
-    } else {
-       ERR("No standard debugger defined in the registry => no debugging session\n");
+    TRACE("Starting debugger (fmt=%s)\n", format);
+    sprintf(buffer, format, GetCurrentProcessId(), hEvent);
+    memset(&startup, 0, sizeof(startup));
+    startup.cb = sizeof(startup);
+    startup.dwFlags = STARTF_USESHOWWINDOW;
+    startup.wShowWindow = SW_SHOWNORMAL;
+    if (CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info)) {
+	/* wait for debugger to come up... */
+	WaitForSingleObject(hEvent, INFINITE);
+	return TRUE;
     }
-    
-    return ret;
+    ERR("Couldn't start debugger (%s) (%ld)\n"
+	"Read the Wine Developers Guide on how to set up winedbg or another debugger\n",
+	buffer, GetLastError());
+    return FALSE;
+}
+
+/******************************************************************
+ *		start_debugger_atomic
+ *
+ * starts the debugger is an atomic way:
+ *	- either the debugger is not started and it is started
+ *	- either the debugger has already been started by an other thread
+ *	- either the debugger couldn't be started
+ *
+ * returns TRUE for the two first condition, FALSE for the last
+ */
+static	int	start_debugger_atomic(PEXCEPTION_POINTERS epointers)
+{
+    static HANDLE	hRunOnce /* = 0 */;
+
+    if (hRunOnce == 0)
+    {
+	OBJECT_ATTRIBUTES	attr;
+	HANDLE			hEvent;
+
+	attr.Length                   = sizeof(attr);
+	attr.RootDirectory            = 0;
+	attr.Attributes               = OBJ_INHERIT;
+	attr.ObjectName               = NULL;
+	attr.SecurityDescriptor       = NULL;
+	attr.SecurityQualityOfService = NULL;
+
+	/* ask for manual reset, so that once the debugger is started, every thread will be
+	 * know it
+	 */
+	NtCreateEvent( &hEvent, EVENT_ALL_ACCESS, &attr, TRUE, FALSE );
+	if (InterlockedCompareExchange( (LPLONG)&hRunOnce, hEvent, 0 ) == 0)
+	{
+	    /* ok, our event has been set... we're the winning thread */
+	    BOOL	ret = start_debugger( epointers, hRunOnce );
+	    DWORD	tmp;
+
+	    if (!ret)
+	    {
+		/* so that the other threads won't be stuck */
+		NtSetEvent( hRunOnce, &tmp );
+	    }
+	    return ret;
+	}
+	
+	/* someone beat us here... */
+	CloseHandle( hEvent );
+    }
+	
+    /* and wait for the winner to have actually created the debugger */
+    WaitForSingleObject( hRunOnce, INFINITE );
+    /* in fact, here, we only know that someone has tried to start the debugger, we'll know
+     * by reposting the exception if it has actually attached to the current process
+     */
+    return TRUE;
+}
+
+
+/*******************************************************************
+ *         UnhandledExceptionFilter   (KERNEL32.@)
+ */
+DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
+{
+    int 		status;
+    int			loop = 0;
+
+    for (loop = 0; loop <= 1; loop++)
+    {
+	/* send a last chance event to the debugger */
+	status = send_debug_event( epointers->ExceptionRecord, FALSE, epointers->ContextRecord );
+	switch (status)
+	{
+	case DBG_CONTINUE: 
+	    return EXCEPTION_CONTINUE_EXECUTION;
+	case DBG_EXCEPTION_NOT_HANDLED: 
+	    TerminateProcess( GetCurrentProcess(), epointers->ExceptionRecord->ExceptionCode );
+	    break; /* not reached */
+	case 0: /* no debugger is present */
+	    if (epointers->ExceptionRecord->ExceptionCode == CONTROL_C_EXIT)
+	    {
+		/* do not launch the debugger on ^C, simply terminate the process */
+		TerminateProcess( GetCurrentProcess(), 1 );
+	    }
+	    /* second try, the debugger isn't present... */
+	    if (loop == 1) return EXCEPTION_EXECUTE_HANDLER;
+	    break;
+	default: 	
+	    FIXME("Unsupported yet debug continue value %d (please report)\n", status);
+	    return EXCEPTION_EXECUTE_HANDLER;
+	}
+
+	/* should only be there when loop == 0 */
+
+	if (top_filter)
+	{
+	    DWORD ret = top_filter( epointers );
+	    if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
+	}
+	
+	/* FIXME: Should check the current error mode */
+	
+	if (!start_debugger_atomic( epointers ))
+	    return EXCEPTION_EXECUTE_HANDLER;
+	/* now that we should have a debugger attached, try to resend event */
+    }	
+	
+    return EXCEPTION_EXECUTE_HANDLER;
 }
 
 


More information about the wine-patches mailing list