Modified the debugger launching code so that only one instance of the

debugger is created per process.
This commit is contained in:
Eric Pouech 2001-08-15 17:34:07 +00:00 committed by Alexandre Julliard
parent 20bc491dc7
commit c04f405172

View file

@ -186,50 +186,22 @@ static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *c
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 @@ DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
}
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;
}