diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index c8426b2a1a8..b36fff9c08d 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -13,9 +13,10 @@ #include "wine/exception.h" #include "stackframe.h" #include "miscemu.h" +#include "server.h" #include "debugtools.h" -DEFAULT_DEBUG_CHANNEL(seh) +DEFAULT_DEBUG_CHANNEL(seh); /* Exception record for handling exceptions happening inside exception handlers */ typedef struct @@ -84,6 +85,22 @@ static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, } +/********************************************************************** + * EXC_SendEvent + * + * Send an EXCEPTION_DEBUG_EVENT event to the debugger. + */ +static inline int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context ) +{ + struct exception_event_request *req = get_req_buffer(); + req->record = *rec; + req->first = first_chance; + req->context = *context; + if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *context = req->context; + return req->status; +} + + /******************************************************************* * EXC_DefaultHandling * @@ -91,8 +108,7 @@ static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, */ static void EXC_DefaultHandling( EXCEPTION_RECORD *rec, CONTEXT *context ) { - if (DEBUG_SendExceptionEvent( rec, FALSE, context ) == DBG_CONTINUE) - return; /* continue execution */ + if (send_debug_event( rec, FALSE, context ) == DBG_CONTINUE) return; /* continue execution */ if (rec->ExceptionFlags & EH_STACK_INVALID) ERR("Exception frame is not in stack limits => unable to dispatch exception.\n"); @@ -117,8 +133,7 @@ void WINAPI EXC_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context ) TRACE( "code=%lx flags=%lx\n", rec->ExceptionCode, rec->ExceptionFlags ); - if (DEBUG_SendExceptionEvent( rec, TRUE, context ) == DBG_CONTINUE) - return; /* continue execution */ + if (send_debug_event( rec, TRUE, context ) == DBG_CONTINUE) return; /* continue execution */ frame = NtCurrentTeb()->except; nested_frame = NULL; diff --git a/include/server.h b/include/server.h index ee70bd19363..ffb014bf2e2 100644 --- a/include/server.h +++ b/include/server.h @@ -31,14 +31,8 @@ typedef WCHAR path_t[MAX_PATH+1]; /* definitions of the event data depending on the event code */ struct debug_event_exception { - int code; /* exception code */ - int flags; /* exception flags */ - void *record; /* exception record ptr */ - void *addr; /* exception address */ - int nb_params; /* exceptions parameters */ - int params[15]; - int first_chance; /* first chance to handle it? */ - CONTEXT context; /* thread context */ + EXCEPTION_RECORD record; /* exception record */ + int first; /* first chance exception? */ }; struct debug_event_create_thread { @@ -813,11 +807,22 @@ struct wait_debug_event_request }; -/* Send a debug event */ -struct send_debug_event_request +/* Send an exception event */ +struct exception_event_request { - OUT int status; /* event continuation status */ - IN debug_event_t event; /* debug event data */ + IN EXCEPTION_RECORD record; /* exception record */ + IN int first; /* first chance exception? */ + IN CONTEXT context; /* thread context */ + OUT int status; /* event continuation status */ +}; + + +/* Send an output string to the debugger */ +struct output_debug_string_request +{ + IN void* string; /* string to display (in debugged process address space) */ + IN int unicode; /* is it Unicode? */ + IN int length; /* string length */ }; @@ -1164,7 +1169,8 @@ enum request REQ_CREATE_SNAPSHOT, REQ_NEXT_PROCESS, REQ_WAIT_DEBUG_EVENT, - REQ_SEND_DEBUG_EVENT, + REQ_EXCEPTION_EVENT, + REQ_OUTPUT_DEBUG_STRING, REQ_CONTINUE_DEBUG_EVENT, REQ_DEBUG_PROCESS, REQ_READ_PROCESS_MEMORY, @@ -1196,7 +1202,7 @@ enum request REQ_NB_REQUESTS }; -#define SERVER_PROTOCOL_VERSION 2 +#define SERVER_PROTOCOL_VERSION 3 /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */ diff --git a/scheduler/debugger.c b/scheduler/debugger.c index d11a0d7552e..1d3ba436c79 100644 --- a/scheduler/debugger.c +++ b/scheduler/debugger.c @@ -7,39 +7,12 @@ #include #include "winerror.h" -#include "process.h" #include "server.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(debugstr); -/********************************************************************** - * DEBUG_SendExceptionEvent - * - * Send an EXCEPTION_DEBUG_EVENT event to the current process debugger. - */ -DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEXT *context ) -{ - int i; - struct send_debug_event_request *req = get_req_buffer(); - - req->event.code = EXCEPTION_DEBUG_EVENT; - req->event.info.exception.code = rec->ExceptionCode; - req->event.info.exception.flags = rec->ExceptionFlags; - req->event.info.exception.record = rec->ExceptionRecord; - req->event.info.exception.addr = rec->ExceptionAddress; - req->event.info.exception.nb_params = rec->NumberParameters; - req->event.info.exception.first_chance = first_chance; - req->event.info.exception.context = *context; - for (i = 0; i < req->event.info.exception.nb_params; i++) - req->event.info.exception.params[i] = rec->ExceptionInformation[i]; - if (!server_call_noerr( REQ_SEND_DEBUG_EVENT )) - *context = req->event.info.exception.context; - return req->status; -} - - /****************************************************************************** * WaitForDebugEvent (KERNEL32.720) * @@ -54,7 +27,6 @@ DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEX BOOL WINAPI WaitForDebugEvent( LPDEBUG_EVENT event, DWORD timeout ) { struct wait_debug_event_request *req = get_req_buffer(); - int i; req->timeout = timeout; if (server_call( REQ_WAIT_DEBUG_EVENT )) return FALSE; @@ -70,14 +42,8 @@ BOOL WINAPI WaitForDebugEvent( LPDEBUG_EVENT event, DWORD timeout ) SetLastError( ERROR_SEM_TIMEOUT ); return FALSE; case EXCEPTION_DEBUG_EVENT: - event->u.Exception.ExceptionRecord.ExceptionCode = req->event.info.exception.code; - event->u.Exception.ExceptionRecord.ExceptionFlags = req->event.info.exception.flags; - event->u.Exception.ExceptionRecord.ExceptionRecord = req->event.info.exception.record; - event->u.Exception.ExceptionRecord.ExceptionAddress = req->event.info.exception.addr; - event->u.Exception.ExceptionRecord.NumberParameters = req->event.info.exception.nb_params; - for (i = 0; i < req->event.info.exception.nb_params; i++) - event->u.Exception.ExceptionRecord.ExceptionInformation[i] = req->event.info.exception.params[i]; - event->u.Exception.dwFirstChance = req->event.info.exception.first_chance; + event->u.Exception.ExceptionRecord = req->event.info.exception.record; + event->u.Exception.dwFirstChance = req->event.info.exception.first; break; case CREATE_THREAD_DEBUG_EVENT: event->u.CreateThread.hThread = req->event.info.create_thread.handle; @@ -158,12 +124,11 @@ BOOL WINAPI DebugActiveProcess( DWORD pid ) */ void WINAPI OutputDebugStringA( LPCSTR str ) { - struct send_debug_event_request *req = get_req_buffer(); - req->event.code = OUTPUT_DEBUG_STRING_EVENT; - req->event.info.output_string.string = (void *)str; - req->event.info.output_string.unicode = 0; - req->event.info.output_string.length = strlen(str) + 1; - server_call_noerr( REQ_SEND_DEBUG_EVENT ); + struct output_debug_string_request *req = get_req_buffer(); + req->string = (void *)str; + req->unicode = 0; + req->length = strlen(str) + 1; + server_call_noerr( REQ_OUTPUT_DEBUG_STRING ); TRACE("%s\n", str); } @@ -173,12 +138,11 @@ void WINAPI OutputDebugStringA( LPCSTR str ) */ void WINAPI OutputDebugStringW( LPCWSTR str ) { - struct send_debug_event_request *req = get_req_buffer(); - req->event.code = OUTPUT_DEBUG_STRING_EVENT; - req->event.info.output_string.string = (void *)str; - req->event.info.output_string.unicode = 1; - req->event.info.output_string.length = (lstrlenW(str) + 1) * sizeof(WCHAR); - server_call_noerr( REQ_SEND_DEBUG_EVENT ); + struct output_debug_string_request *req = get_req_buffer(); + req->string = (void *)str; + req->unicode = 1; + req->length = (lstrlenW(str) + 1) * sizeof(WCHAR); + server_call_noerr( REQ_OUTPUT_DEBUG_STRING ); TRACE("%s\n", debugstr_w(str)); } diff --git a/server/context_i386.c b/server/context_i386.c index 9b65e250252..787192c69e9 100644 --- a/server/context_i386.c +++ b/server/context_i386.c @@ -457,13 +457,12 @@ static void copy_context( CONTEXT *to, CONTEXT *from, int flags ) DECL_HANDLER(get_thread_context) { struct thread *thread; - CONTEXT *context; if ((thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) { - if ((context = get_debug_context( thread ))) /* thread is inside an exception event */ + if (thread->context) /* thread is inside an exception event */ { - copy_context( &req->context, context, req->flags ); + copy_context( &req->context, thread->context, req->flags ); } else { @@ -481,13 +480,12 @@ DECL_HANDLER(get_thread_context) DECL_HANDLER(set_thread_context) { struct thread *thread; - CONTEXT *context; if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT ))) { - if ((context = get_debug_context( thread ))) /* thread is inside an exception event */ + if (thread->context) /* thread is inside an exception event */ { - copy_context( context, &req->context, req->flags ); + copy_context( thread->context, &req->context, req->flags ); } else { diff --git a/server/debugger.c b/server/debugger.c index 7b7b9b40ea0..20a545258c2 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -83,93 +83,132 @@ static const struct object_ops debug_ctx_ops = }; -/* initialise the fields that do not need to be filled by the client */ -static int fill_debug_event( struct debug_event *event, void *arg ) +/* routines to build an event according to its type */ + +static int fill_exception_event( struct debug_event *event, void *arg ) { - struct process *debugger = event->debugger->process; - struct process *process; - struct thread *thread; - struct process_dll *dll; - int handle; - - /* some events need special handling */ - switch(event->data.code) - { - case CREATE_THREAD_DEBUG_EVENT: - thread = arg; - /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ - if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1) - return 0; - event->data.info.create_thread.handle = handle; - event->data.info.create_thread.teb = thread->teb; - event->data.info.create_thread.start = thread->entry; - break; - case CREATE_PROCESS_DEBUG_EVENT: - process = arg; - thread = process->thread_list; - /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */ - if ((handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, FALSE )) == -1) - return 0; - event->data.info.create_process.process = handle; - - /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ - if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1) - { - close_handle( debugger, event->data.info.create_process.process ); - return 0; - } - event->data.info.create_process.thread = handle; - - handle = -1; - if (process->exe.file && - /* the doc says write access too, but this doesn't seem a good idea */ - ((handle = alloc_handle( debugger, process->exe.file, GENERIC_READ, FALSE )) == -1)) - { - close_handle( debugger, event->data.info.create_process.process ); - close_handle( debugger, event->data.info.create_process.thread ); - return 0; - } - event->data.info.create_process.file = handle; - event->data.info.create_process.teb = thread->teb; - event->data.info.create_process.base = process->exe.base; - event->data.info.create_process.start = thread->entry; - event->data.info.create_process.dbg_offset = process->exe.dbg_offset; - event->data.info.create_process.dbg_size = process->exe.dbg_size; - event->data.info.create_process.name = 0; - event->data.info.create_process.unicode = 0; - break; - case LOAD_DLL_DEBUG_EVENT: - dll = arg; - handle = -1; - if (dll->file && - (handle = alloc_handle( debugger, dll->file, GENERIC_READ, FALSE )) == -1) - return 0; - event->data.info.load_dll.handle = handle; - event->data.info.load_dll.base = dll->base; - event->data.info.load_dll.dbg_offset = dll->dbg_offset; - event->data.info.load_dll.dbg_size = dll->dbg_size; - event->data.info.load_dll.name = dll->name; - event->data.info.load_dll.unicode = 0; - break; - case EXIT_PROCESS_DEBUG_EVENT: - process = arg; - event->data.info.exit.exit_code = process->exit_code; - break; - case EXIT_THREAD_DEBUG_EVENT: - thread = arg; - event->data.info.exit.exit_code = thread->exit_code; - break; - case UNLOAD_DLL_DEBUG_EVENT: - event->data.info.unload_dll.base = arg; - break; - case EXCEPTION_DEBUG_EVENT: - case OUTPUT_DEBUG_STRING_EVENT: - case RIP_EVENT: - break; - } + memcpy( &event->data.info.exception, arg, sizeof(event->data.info.exception) ); return 1; } +static int fill_create_thread_event( struct debug_event *event, void *arg ) +{ + struct process *debugger = event->debugger->process; + struct thread *thread = arg; + int handle; + + /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ + if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1) + return 0; + event->data.info.create_thread.handle = handle; + event->data.info.create_thread.teb = thread->teb; + event->data.info.create_thread.start = thread->entry; + return 1; +} + +static int fill_create_process_event( struct debug_event *event, void *arg ) +{ + struct process *debugger = event->debugger->process; + struct process *process = arg; + struct thread *thread = process->thread_list; + int handle; + + /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */ + if ((handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, FALSE )) == -1) + return 0; + event->data.info.create_process.process = handle; + + /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ + if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1) + { + close_handle( debugger, event->data.info.create_process.process ); + return 0; + } + event->data.info.create_process.thread = handle; + + handle = -1; + if (process->exe.file && + /* the doc says write access too, but this doesn't seem a good idea */ + ((handle = alloc_handle( debugger, process->exe.file, GENERIC_READ, FALSE )) == -1)) + { + close_handle( debugger, event->data.info.create_process.process ); + close_handle( debugger, event->data.info.create_process.thread ); + return 0; + } + event->data.info.create_process.file = handle; + event->data.info.create_process.teb = thread->teb; + event->data.info.create_process.base = process->exe.base; + event->data.info.create_process.start = thread->entry; + event->data.info.create_process.dbg_offset = process->exe.dbg_offset; + event->data.info.create_process.dbg_size = process->exe.dbg_size; + event->data.info.create_process.name = 0; + event->data.info.create_process.unicode = 0; + return 1; +} + +static int fill_exit_thread_event( struct debug_event *event, void *arg ) +{ + struct thread *thread = arg; + event->data.info.exit.exit_code = thread->exit_code; + return 1; +} + +static int fill_exit_process_event( struct debug_event *event, void *arg ) +{ + struct process *process = arg; + event->data.info.exit.exit_code = process->exit_code; + return 1; +} + +static int fill_load_dll_event( struct debug_event *event, void *arg ) +{ + struct process *debugger = event->debugger->process; + struct process_dll *dll = arg; + int handle = -1; + + if (dll->file && (handle = alloc_handle( debugger, dll->file, GENERIC_READ, FALSE )) == -1) + return 0; + event->data.info.load_dll.handle = handle; + event->data.info.load_dll.base = dll->base; + event->data.info.load_dll.dbg_offset = dll->dbg_offset; + event->data.info.load_dll.dbg_size = dll->dbg_size; + event->data.info.load_dll.name = dll->name; + event->data.info.load_dll.unicode = 0; + return 1; +} + +static int fill_unload_dll_event( struct debug_event *event, void *arg ) +{ + event->data.info.unload_dll.base = arg; + return 1; +} + +static int fill_output_debug_string_event( struct debug_event *event, void *arg ) +{ + struct output_debug_string_request *req = arg; + event->data.info.output_string.string = req->string; + event->data.info.output_string.unicode = req->unicode; + event->data.info.output_string.length = req->length; + return 1; +} + +typedef int (*fill_event_func)( struct debug_event *event, void *arg ); + +#define NB_DEBUG_EVENTS OUTPUT_DEBUG_STRING_EVENT /* RIP_EVENT not supported */ + +static const fill_event_func fill_debug_event[NB_DEBUG_EVENTS] = +{ + fill_exception_event, /* EXCEPTION_DEBUG_EVENT */ + fill_create_thread_event, /* CREATE_THREAD_DEBUG_EVENT */ + fill_create_process_event, /* CREATE_PROCESS_DEBUG_EVENT */ + fill_exit_thread_event, /* EXIT_THREAD_DEBUG_EVENT */ + fill_exit_process_event, /* EXIT_PROCESS_DEBUG_EVENT */ + fill_load_dll_event, /* LOAD_DLL_DEBUG_EVENT */ + fill_unload_dll_event, /* UNLOAD_DLL_DEBUG_EVENT */ + fill_output_debug_string_event /* OUTPUT_DEBUG_STRING_EVENT */ +}; + + /* unlink the first event from the queue */ static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event ) { @@ -228,18 +267,13 @@ static void build_wait_debug_reply( struct thread *thread, struct object *obj, i } /* build a reply for the send_event request */ -static void build_send_event_reply( struct thread *thread, struct object *obj, int signaled ) +static void build_exception_event_reply( struct thread *thread, struct object *obj, int signaled ) { - struct send_debug_event_request *req = get_req_ptr( thread ); + struct exception_event_request *req = get_req_ptr( thread ); struct debug_event *event = (struct debug_event *)obj; assert( obj->ops == &debug_event_ops ); - req->status = event->status; - /* copy the context into the reply */ - if (event->data.code == EXCEPTION_DEBUG_EVENT) - memcpy( &req->event.info.exception.context, - &event->data.info.exception.context, - sizeof(req->event.info.exception.context) ); + thread->context = NULL; } static void debug_event_dump( struct object *obj, int verbose ) @@ -363,28 +397,27 @@ static int continue_debug_event( struct process *process, struct thread *thread, } /* queue a debug event for a debugger */ -static struct debug_event *queue_debug_event( struct thread *thread, int code, void *arg, - debug_event_t *data ) +static struct debug_event *queue_debug_event( struct thread *thread, int code, void *arg ) { struct thread *debugger = thread->process->debugger; struct debug_ctx *debug_ctx = debugger->debug_ctx; struct debug_event *event; + assert( code > 0 && code <= NB_DEBUG_EVENTS ); assert( debug_ctx ); /* cannot queue a debug event for myself */ assert( debugger->process != thread->process ); /* build the event */ if (!(event = alloc_object( &debug_event_ops, -1 ))) return NULL; - event->next = NULL; - event->prev = NULL; - event->state = EVENT_QUEUED; - event->sender = (struct thread *)grab_object( thread ); - event->debugger = (struct thread *)grab_object( debugger ); - if (data) memcpy( &event->data, data, sizeof(event->data) ); + event->next = NULL; + event->prev = NULL; + event->state = EVENT_QUEUED; + event->sender = (struct thread *)grab_object( thread ); + event->debugger = (struct thread *)grab_object( debugger ); event->data.code = code; - if (!fill_debug_event( event, arg )) + if (!fill_debug_event[code-1]( event, arg )) { event->data.code = -1; /* make sure we don't attempt to close handles */ release_object( event ); @@ -401,11 +434,43 @@ void generate_debug_event( struct thread *thread, int code, void *arg ) { if (thread->process->debugger) { - struct debug_event *event = queue_debug_event( thread, code, arg, NULL ); + struct debug_event *event = queue_debug_event( thread, code, arg ); if (event) release_object( event ); } } +/* attach a process to a debugger thread and suspend it */ +static int debugger_attach( struct process *process, struct thread *debugger ) +{ + struct thread *thread; + + if (process->debugger) goto error; /* already being debugged */ + if (process->init_event) goto error; /* still starting up */ + + /* make sure we don't create a debugging loop */ + for (thread = debugger; thread; thread = thread->process->debugger) + if (thread->process == process) goto error; + + suspend_process( process ); + + /* we must have been able to attach all threads */ + for (thread = process->thread_list; thread; thread = thread->proc_next) + if (!thread->attached) + { + fprintf( stderr, "%p not attached\n", thread ); + resume_process( process ); + goto error; + } + + if (set_process_debugger( process, debugger )) return 1; + 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 ) { @@ -426,40 +491,12 @@ void generate_startup_debug_events( struct process *process ) } } -/* return a pointer to the context in case the thread is inside an exception event */ -CONTEXT *get_debug_context( struct thread *thread ) -{ - struct debug_event *event; - struct thread *debugger = thread->process->debugger; - - if (!debugger) return NULL; /* not being debugged */ - assert( debugger->debug_ctx ); - - /* find the exception event in the debugger's queue */ - for (event = debugger->debug_ctx->event_head; event; event = event->next) - if (event->sender == thread && (event->data.code == EXCEPTION_DEBUG_EVENT)) - return &event->data.info.exception.context; - return NULL; -} - -/* attach a process to a debugger thread */ -int debugger_attach( struct process *process, struct thread *debugger ) +/* set the debugger of a given process */ +int set_process_debugger( struct process *process, struct thread *debugger ) { struct debug_ctx *debug_ctx; - struct thread *thread; - if (process->debugger) /* already being debugged */ - { - set_error( STATUS_ACCESS_DENIED ); - return 0; - } - /* make sure we don't create a debugging loop */ - for (thread = debugger; thread; thread = thread->process->debugger) - if (thread->process == process) - { - set_error( STATUS_ACCESS_DENIED ); - return 0; - } + assert( !process->debugger ); if (!debugger->debug_ctx) /* need to allocate a context */ { @@ -515,34 +552,54 @@ DECL_HANDLER(continue_debug_event) /* Start debugging an existing process */ DECL_HANDLER(debug_process) { + struct debug_event_exception data; + struct debug_event *event; struct process *process = get_process_from_id( req->pid ); if (!process) return; + if (debugger_attach( process, current )) { generate_startup_debug_events( process ); - /* FIXME: breakpoint exception event */ + resume_process( process ); + + data.record.ExceptionCode = EXCEPTION_BREAKPOINT; + data.record.ExceptionFlags = EXCEPTION_CONTINUABLE; + data.record.ExceptionRecord = NULL; + data.record.ExceptionAddress = process->thread_list->entry; /* FIXME */ + data.record.NumberParameters = 0; + data.first = 1; + if ((event = queue_debug_event( process->thread_list, EXCEPTION_DEBUG_EVENT, &data ))) + release_object( event ); } release_object( process ); } -/* Send a debug event */ -DECL_HANDLER(send_debug_event) +/* send an exception event */ +DECL_HANDLER(exception_event) { - struct debug_event *event; - int code = req->event.code; + if (current->process->debugger) + { + struct debug_event_exception data; + struct debug_event *event; - if ((code <= 0) || (code > RIP_EVENT)) - { - fatal_protocol_error( current, "send_debug_event: bad code %d\n", code ); - return; - } - req->status = 0; - if (current->process->debugger && ((event = queue_debug_event( current, code, - NULL, &req->event )))) - { - /* wait for continue_debug_event */ - struct object *obj = &event->obj; - sleep_on( 1, &obj, 0, -1, build_send_event_reply ); - release_object( event ); + data.record = req->record; + data.first = req->first; + if ((event = queue_debug_event( current, EXCEPTION_DEBUG_EVENT, &data ))) + { + struct object *obj = &event->obj; + current->context = &req->context; + sleep_on( 1, &obj, 0, -1, build_exception_event_reply ); + release_object( event ); + } + } +} + +/* send an output string to the debugger */ +DECL_HANDLER(output_debug_string) +{ + if (current->process->debugger) + { + struct debug_event *event = queue_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, req ); + if (event) release_object( event ); } } diff --git a/server/file.c b/server/file.c index 70e12c8e69a..e5b514ae7c5 100644 --- a/server/file.c +++ b/server/file.c @@ -468,15 +468,17 @@ DECL_HANDLER(alloc_file_handle) struct file *file; req->handle = -1; - if ((fd = dup(fd)) != -1) + if (current->pass_fd != -1) { - if ((file = create_file_for_fd( fd, req->access, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 ))) + if ((file = create_file_for_fd( current->pass_fd, req->access, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0 ))) { req->handle = alloc_handle( current->process, file, req->access, 0 ); release_object( file ); } + current->pass_fd = -1; } - else file_set_error(); + else set_error( STATUS_INVALID_PARAMETER ); } /* get a Unix fd to read from a file */ diff --git a/server/main.c b/server/main.c index 50d667b93b8..e106fba0d61 100644 --- a/server/main.c +++ b/server/main.c @@ -60,7 +60,6 @@ static void sigterm_handler() /* initialize signal handling */ static void signal_init(void) { -#if 0 if (!debug_level) { switch(fork()) @@ -74,7 +73,6 @@ static void signal_init(void) exit(0); } } -#endif signal( SIGPIPE, SIG_IGN ); signal( SIGHUP, sigterm_handler ); signal( SIGINT, sigterm_handler ); diff --git a/server/object.h b/server/object.h index 6aa920d7558..2040ca4410a 100644 --- a/server/object.h +++ b/server/object.h @@ -153,11 +153,10 @@ extern int free_console( struct process *process ); /* debugger functions */ -extern int debugger_attach( struct process *process, struct thread *debugger ); +extern int set_process_debugger( struct process *process, struct thread *debugger ); extern void generate_debug_event( struct thread *thread, int code, void *arg ); extern void generate_startup_debug_events( struct process *process ); extern void debug_exit_thread( struct thread *thread ); -extern CONTEXT *get_debug_context( struct thread *thread ); /* mapping functions */ diff --git a/server/process.c b/server/process.c index 30a9bf5c053..297ef00a533 100644 --- a/server/process.c +++ b/server/process.c @@ -201,9 +201,9 @@ struct thread *create_process( int fd, struct process *parent, /* attach to the debugger if requested */ if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) - debugger_attach( process, current ); + set_process_debugger( process, current ); else if (parent && parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS)) - debugger_attach( process, parent->debugger ); + set_process_debugger( process, parent->debugger ); release_object( process ); return thread; diff --git a/server/request.c b/server/request.c index 7f67c1b24e0..582f83978f3 100644 --- a/server/request.c +++ b/server/request.c @@ -127,16 +127,16 @@ static void fatal_perror( const char *err, ... ) } /* call a request handler */ -static void call_req_handler( struct thread *thread, enum request req, int fd ) +static inline void call_req_handler( struct thread *thread, enum request req ) { current = thread; clear_error(); - if (debug_level) trace_request( req, fd ); + if (debug_level) trace_request( req ); if (req < REQ_NB_REQUESTS) { - req_handlers[req].handler( current->buffer, fd ); + req_handlers[req]( current->buffer ); if (current && !current->wait) send_reply( current ); current = NULL; return; @@ -186,10 +186,8 @@ void read_request( struct thread *thread ) if (ret == sizeof(req)) { - int pass_fd = thread->pass_fd; + call_req_handler( thread, req ); thread->pass_fd = -1; - call_req_handler( thread, req, pass_fd ); - if (pass_fd != -1) close( pass_fd ); return; } if (ret == -1) diff --git a/server/request.h b/server/request.h index 978b691d2d9..a907747f724 100644 --- a/server/request.h +++ b/server/request.h @@ -22,20 +22,26 @@ #define PROTOCOL_ERROR -3 /* request handler definition */ -#define DECL_HANDLER(name) void req_##name( struct name##_request *req, int fd ) +#define DECL_HANDLER(name) void req_##name( struct name##_request *req ) /* request functions */ +#ifdef __GNUC__ +extern void fatal_protocol_error( struct thread *thread, + const char *err, ... ) __attribute__((format (printf,2,3))); +#else +extern void fatal_protocol_error( struct thread *thread, const char *err, ... ); +#endif + extern void read_request( struct thread *thread ); extern int write_request( struct thread *thread ); -extern void fatal_protocol_error( struct thread *thread, const char *err, ... ); extern void set_reply_fd( struct thread *thread, int pass_fd ); extern void send_reply( struct thread *thread ); extern void open_master_socket(void); extern void close_master_socket(void); extern void lock_master_socket( int locked ); -extern void trace_request( enum request req, int fd ); +extern void trace_request( enum request req ); extern void trace_reply( struct thread *thread ); /* get the request buffer */ @@ -138,7 +144,8 @@ DECL_HANDLER(create_device); DECL_HANDLER(create_snapshot); DECL_HANDLER(next_process); DECL_HANDLER(wait_debug_event); -DECL_HANDLER(send_debug_event); +DECL_HANDLER(exception_event); +DECL_HANDLER(output_debug_string); DECL_HANDLER(continue_debug_event); DECL_HANDLER(debug_process); DECL_HANDLER(read_process_memory); @@ -170,108 +177,108 @@ DECL_HANDLER(get_atom_name); #ifdef WANT_REQUEST_HANDLERS -static const struct handler { - void (*handler)( void *req, int fd ); - unsigned int min_size; -} req_handlers[REQ_NB_REQUESTS] = { - { (void(*)())req_new_process, sizeof(struct new_process_request) }, - { (void(*)())req_new_thread, sizeof(struct new_thread_request) }, - { (void(*)())req_boot_done, sizeof(struct boot_done_request) }, - { (void(*)())req_init_process, sizeof(struct init_process_request) }, - { (void(*)())req_init_process_done, sizeof(struct init_process_done_request) }, - { (void(*)())req_init_thread, sizeof(struct init_thread_request) }, - { (void(*)())req_get_thread_buffer, sizeof(struct get_thread_buffer_request) }, - { (void(*)())req_terminate_process, sizeof(struct terminate_process_request) }, - { (void(*)())req_terminate_thread, sizeof(struct terminate_thread_request) }, - { (void(*)())req_get_process_info, sizeof(struct get_process_info_request) }, - { (void(*)())req_set_process_info, sizeof(struct set_process_info_request) }, - { (void(*)())req_get_thread_info, sizeof(struct get_thread_info_request) }, - { (void(*)())req_set_thread_info, sizeof(struct set_thread_info_request) }, - { (void(*)())req_suspend_thread, sizeof(struct suspend_thread_request) }, - { (void(*)())req_resume_thread, sizeof(struct resume_thread_request) }, - { (void(*)())req_load_dll, sizeof(struct load_dll_request) }, - { (void(*)())req_unload_dll, sizeof(struct unload_dll_request) }, - { (void(*)())req_queue_apc, sizeof(struct queue_apc_request) }, - { (void(*)())req_get_apcs, sizeof(struct get_apcs_request) }, - { (void(*)())req_close_handle, sizeof(struct close_handle_request) }, - { (void(*)())req_get_handle_info, sizeof(struct get_handle_info_request) }, - { (void(*)())req_set_handle_info, sizeof(struct set_handle_info_request) }, - { (void(*)())req_dup_handle, sizeof(struct dup_handle_request) }, - { (void(*)())req_open_process, sizeof(struct open_process_request) }, - { (void(*)())req_select, sizeof(struct select_request) }, - { (void(*)())req_create_event, sizeof(struct create_event_request) }, - { (void(*)())req_event_op, sizeof(struct event_op_request) }, - { (void(*)())req_open_event, sizeof(struct open_event_request) }, - { (void(*)())req_create_mutex, sizeof(struct create_mutex_request) }, - { (void(*)())req_release_mutex, sizeof(struct release_mutex_request) }, - { (void(*)())req_open_mutex, sizeof(struct open_mutex_request) }, - { (void(*)())req_create_semaphore, sizeof(struct create_semaphore_request) }, - { (void(*)())req_release_semaphore, sizeof(struct release_semaphore_request) }, - { (void(*)())req_open_semaphore, sizeof(struct open_semaphore_request) }, - { (void(*)())req_create_file, sizeof(struct create_file_request) }, - { (void(*)())req_alloc_file_handle, sizeof(struct alloc_file_handle_request) }, - { (void(*)())req_get_read_fd, sizeof(struct get_read_fd_request) }, - { (void(*)())req_get_write_fd, sizeof(struct get_write_fd_request) }, - { (void(*)())req_set_file_pointer, sizeof(struct set_file_pointer_request) }, - { (void(*)())req_truncate_file, sizeof(struct truncate_file_request) }, - { (void(*)())req_set_file_time, sizeof(struct set_file_time_request) }, - { (void(*)())req_flush_file, sizeof(struct flush_file_request) }, - { (void(*)())req_get_file_info, sizeof(struct get_file_info_request) }, - { (void(*)())req_lock_file, sizeof(struct lock_file_request) }, - { (void(*)())req_unlock_file, sizeof(struct unlock_file_request) }, - { (void(*)())req_create_pipe, sizeof(struct create_pipe_request) }, - { (void(*)())req_create_socket, sizeof(struct create_socket_request) }, - { (void(*)())req_accept_socket, sizeof(struct accept_socket_request) }, - { (void(*)())req_set_socket_event, sizeof(struct set_socket_event_request) }, - { (void(*)())req_get_socket_event, sizeof(struct get_socket_event_request) }, - { (void(*)())req_enable_socket_event, sizeof(struct enable_socket_event_request) }, - { (void(*)())req_alloc_console, sizeof(struct alloc_console_request) }, - { (void(*)())req_free_console, sizeof(struct free_console_request) }, - { (void(*)())req_open_console, sizeof(struct open_console_request) }, - { (void(*)())req_set_console_fd, sizeof(struct set_console_fd_request) }, - { (void(*)())req_get_console_mode, sizeof(struct get_console_mode_request) }, - { (void(*)())req_set_console_mode, sizeof(struct set_console_mode_request) }, - { (void(*)())req_set_console_info, sizeof(struct set_console_info_request) }, - { (void(*)())req_get_console_info, sizeof(struct get_console_info_request) }, - { (void(*)())req_write_console_input, sizeof(struct write_console_input_request) }, - { (void(*)())req_read_console_input, sizeof(struct read_console_input_request) }, - { (void(*)())req_create_change_notification, sizeof(struct create_change_notification_request) }, - { (void(*)())req_create_mapping, sizeof(struct create_mapping_request) }, - { (void(*)())req_open_mapping, sizeof(struct open_mapping_request) }, - { (void(*)())req_get_mapping_info, sizeof(struct get_mapping_info_request) }, - { (void(*)())req_create_device, sizeof(struct create_device_request) }, - { (void(*)())req_create_snapshot, sizeof(struct create_snapshot_request) }, - { (void(*)())req_next_process, sizeof(struct next_process_request) }, - { (void(*)())req_wait_debug_event, sizeof(struct wait_debug_event_request) }, - { (void(*)())req_send_debug_event, sizeof(struct send_debug_event_request) }, - { (void(*)())req_continue_debug_event, sizeof(struct continue_debug_event_request) }, - { (void(*)())req_debug_process, sizeof(struct debug_process_request) }, - { (void(*)())req_read_process_memory, sizeof(struct read_process_memory_request) }, - { (void(*)())req_write_process_memory, sizeof(struct write_process_memory_request) }, - { (void(*)())req_create_key, sizeof(struct create_key_request) }, - { (void(*)())req_open_key, sizeof(struct open_key_request) }, - { (void(*)())req_delete_key, sizeof(struct delete_key_request) }, - { (void(*)())req_close_key, sizeof(struct close_key_request) }, - { (void(*)())req_enum_key, sizeof(struct enum_key_request) }, - { (void(*)())req_query_key_info, sizeof(struct query_key_info_request) }, - { (void(*)())req_set_key_value, sizeof(struct set_key_value_request) }, - { (void(*)())req_get_key_value, sizeof(struct get_key_value_request) }, - { (void(*)())req_enum_key_value, sizeof(struct enum_key_value_request) }, - { (void(*)())req_delete_key_value, sizeof(struct delete_key_value_request) }, - { (void(*)())req_load_registry, sizeof(struct load_registry_request) }, - { (void(*)())req_save_registry, sizeof(struct save_registry_request) }, - { (void(*)())req_set_registry_levels, sizeof(struct set_registry_levels_request) }, - { (void(*)())req_create_timer, sizeof(struct create_timer_request) }, - { (void(*)())req_open_timer, sizeof(struct open_timer_request) }, - { (void(*)())req_set_timer, sizeof(struct set_timer_request) }, - { (void(*)())req_cancel_timer, sizeof(struct cancel_timer_request) }, - { (void(*)())req_get_thread_context, sizeof(struct get_thread_context_request) }, - { (void(*)())req_set_thread_context, sizeof(struct set_thread_context_request) }, - { (void(*)())req_get_selector_entry, sizeof(struct get_selector_entry_request) }, - { (void(*)())req_add_atom, sizeof(struct add_atom_request) }, - { (void(*)())req_delete_atom, sizeof(struct delete_atom_request) }, - { (void(*)())req_find_atom, sizeof(struct find_atom_request) }, - { (void(*)())req_get_atom_name, sizeof(struct get_atom_name_request) }, +typedef void (*req_handler)( void *req ); +static const req_handler req_handlers[REQ_NB_REQUESTS] = +{ + (req_handler)req_new_process, + (req_handler)req_new_thread, + (req_handler)req_boot_done, + (req_handler)req_init_process, + (req_handler)req_init_process_done, + (req_handler)req_init_thread, + (req_handler)req_get_thread_buffer, + (req_handler)req_terminate_process, + (req_handler)req_terminate_thread, + (req_handler)req_get_process_info, + (req_handler)req_set_process_info, + (req_handler)req_get_thread_info, + (req_handler)req_set_thread_info, + (req_handler)req_suspend_thread, + (req_handler)req_resume_thread, + (req_handler)req_load_dll, + (req_handler)req_unload_dll, + (req_handler)req_queue_apc, + (req_handler)req_get_apcs, + (req_handler)req_close_handle, + (req_handler)req_get_handle_info, + (req_handler)req_set_handle_info, + (req_handler)req_dup_handle, + (req_handler)req_open_process, + (req_handler)req_select, + (req_handler)req_create_event, + (req_handler)req_event_op, + (req_handler)req_open_event, + (req_handler)req_create_mutex, + (req_handler)req_release_mutex, + (req_handler)req_open_mutex, + (req_handler)req_create_semaphore, + (req_handler)req_release_semaphore, + (req_handler)req_open_semaphore, + (req_handler)req_create_file, + (req_handler)req_alloc_file_handle, + (req_handler)req_get_read_fd, + (req_handler)req_get_write_fd, + (req_handler)req_set_file_pointer, + (req_handler)req_truncate_file, + (req_handler)req_set_file_time, + (req_handler)req_flush_file, + (req_handler)req_get_file_info, + (req_handler)req_lock_file, + (req_handler)req_unlock_file, + (req_handler)req_create_pipe, + (req_handler)req_create_socket, + (req_handler)req_accept_socket, + (req_handler)req_set_socket_event, + (req_handler)req_get_socket_event, + (req_handler)req_enable_socket_event, + (req_handler)req_alloc_console, + (req_handler)req_free_console, + (req_handler)req_open_console, + (req_handler)req_set_console_fd, + (req_handler)req_get_console_mode, + (req_handler)req_set_console_mode, + (req_handler)req_set_console_info, + (req_handler)req_get_console_info, + (req_handler)req_write_console_input, + (req_handler)req_read_console_input, + (req_handler)req_create_change_notification, + (req_handler)req_create_mapping, + (req_handler)req_open_mapping, + (req_handler)req_get_mapping_info, + (req_handler)req_create_device, + (req_handler)req_create_snapshot, + (req_handler)req_next_process, + (req_handler)req_wait_debug_event, + (req_handler)req_exception_event, + (req_handler)req_output_debug_string, + (req_handler)req_continue_debug_event, + (req_handler)req_debug_process, + (req_handler)req_read_process_memory, + (req_handler)req_write_process_memory, + (req_handler)req_create_key, + (req_handler)req_open_key, + (req_handler)req_delete_key, + (req_handler)req_close_key, + (req_handler)req_enum_key, + (req_handler)req_query_key_info, + (req_handler)req_set_key_value, + (req_handler)req_get_key_value, + (req_handler)req_enum_key_value, + (req_handler)req_delete_key_value, + (req_handler)req_load_registry, + (req_handler)req_save_registry, + (req_handler)req_set_registry_levels, + (req_handler)req_create_timer, + (req_handler)req_open_timer, + (req_handler)req_set_timer, + (req_handler)req_cancel_timer, + (req_handler)req_get_thread_context, + (req_handler)req_set_thread_context, + (req_handler)req_get_selector_entry, + (req_handler)req_add_atom, + (req_handler)req_delete_atom, + (req_handler)req_find_atom, + (req_handler)req_get_atom_name, }; #endif /* WANT_REQUEST_HANDLERS */ diff --git a/server/thread.c b/server/thread.c index cf02b871fa7..37db99bf211 100644 --- a/server/thread.c +++ b/server/thread.c @@ -126,6 +126,7 @@ struct thread *create_thread( int fd, struct process *process, int suspend ) if (!(thread = alloc_object( &thread_ops, fd ))) return NULL; thread->unix_pid = 0; /* not known yet */ + thread->context = NULL; thread->teb = NULL; thread->mutex = NULL; thread->debug_ctx = NULL; diff --git a/server/thread.h b/server/thread.h index 9cc088d2553..198b77d2e84 100644 --- a/server/thread.h +++ b/server/thread.h @@ -47,6 +47,7 @@ struct thread int attached; /* is thread attached with ptrace? */ int exit_code; /* thread exit code */ int unix_pid; /* Unix pid of client */ + CONTEXT *context; /* current context if in an exception handler */ void *teb; /* TEB address (in client address space) */ void *entry; /* thread entry point (in client address space) */ int priority; /* priority level */ diff --git a/server/trace.c b/server/trace.c index 1313c159a73..d4ff840d596 100644 --- a/server/trace.c +++ b/server/trace.c @@ -79,23 +79,28 @@ static void dump_context( const CONTEXT *context ) #endif } -static void dump_debug_event_t( const debug_event_t *event ) +static void dump_exc_record( const EXCEPTION_RECORD *rec ) { int i; + fprintf( stderr, "{code=%lx,flags=%lx,rec=%p,addr=%p,params={", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionRecord, + rec->ExceptionAddress ); + for (i = 0; i < rec->NumberParameters; i++) + { + if (i) fputc( ',', stderr ); + fprintf( stderr, "%lx", rec->ExceptionInformation[i] ); + } + fputc( '}', stderr ); +} + +static void dump_debug_event_t( const debug_event_t *event ) +{ switch(event->code) { case EXCEPTION_DEBUG_EVENT: - fprintf( stderr, "{exception,code=%x,flags=%x,rec=%p,addr=%p,params={", - event->info.exception.code, event->info.exception.flags, - event->info.exception.record, event->info.exception.addr ); - for (i = 0; i < event->info.exception.nb_params; i++) - { - if (i) fputc( ',', stderr ); - fprintf( stderr, "%x", event->info.exception.params[i] ); - } - fprintf( stderr, "},first_chance=%d,context=", event->info.exception.first_chance ); - dump_context( &event->info.exception.context ); - fputc( '}', stderr ); + fprintf( stderr, "{exception," ); + dump_exc_record( &event->info.exception.record ); + fprintf( stderr, ",first=%d}", event->info.exception.first ); break; case CREATE_THREAD_DEBUG_EVENT: fprintf( stderr, "{create_thread,thread=%d,teb=%p,start=%p}", @@ -927,17 +932,28 @@ static void dump_wait_debug_event_reply( const struct wait_debug_event_request * dump_debug_event_t( &req->event ); } -static void dump_send_debug_event_request( const struct send_debug_event_request *req ) +static void dump_exception_event_request( const struct exception_event_request *req ) { - fprintf( stderr, " event=" ); - dump_debug_event_t( &req->event ); + fprintf( stderr, " record=" ); + dump_exc_record( &req->record ); + fprintf( stderr, "," ); + fprintf( stderr, " first=%d,", req->first ); + fprintf( stderr, " context=" ); + dump_context( &req->context ); } -static void dump_send_debug_event_reply( const struct send_debug_event_request *req ) +static void dump_exception_event_reply( const struct exception_event_request *req ) { fprintf( stderr, " status=%d", req->status ); } +static void dump_output_debug_string_request( const struct output_debug_string_request *req ) +{ + fprintf( stderr, " string=%p,", req->string ); + fprintf( stderr, " unicode=%d,", req->unicode ); + fprintf( stderr, " length=%d", req->length ); +} + static void dump_continue_debug_event_request( const struct continue_debug_event_request *req ) { fprintf( stderr, " pid=%p,", req->pid ); @@ -1310,7 +1326,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_create_snapshot_request, (dump_func)dump_next_process_request, (dump_func)dump_wait_debug_event_request, - (dump_func)dump_send_debug_event_request, + (dump_func)dump_exception_event_request, + (dump_func)dump_output_debug_string_request, (dump_func)dump_continue_debug_event_request, (dump_func)dump_debug_process_request, (dump_func)dump_read_process_memory_request, @@ -1411,7 +1428,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_create_snapshot_reply, (dump_func)dump_next_process_reply, (dump_func)dump_wait_debug_event_reply, - (dump_func)dump_send_debug_event_reply, + (dump_func)dump_exception_event_reply, + (dump_func)0, (dump_func)0, (dump_func)0, (dump_func)dump_read_process_memory_reply, @@ -1512,7 +1530,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "create_snapshot", "next_process", "wait_debug_event", - "send_debug_event", + "exception_event", + "output_debug_string", "continue_debug_event", "debug_process", "read_process_memory", @@ -1546,7 +1565,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */ -void trace_request( enum request req, int fd ) +void trace_request( enum request req ) { current->last_req = req; if (req < REQ_NB_REQUESTS) @@ -1556,7 +1575,7 @@ void trace_request( enum request req, int fd ) } else fprintf( stderr, "%08x: %d(", (unsigned int)current, req ); - if (fd != -1) fprintf( stderr, " ) fd=%d\n", fd ); + if (current->pass_fd != -1) fprintf( stderr, " ) fd=%d\n", current->pass_fd ); else fprintf( stderr, " )\n" ); } diff --git a/tools/make_requests b/tools/make_requests index 9e84e793472..d8f75f4dfaf 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -18,6 +18,7 @@ "path_t" => "&dump_path_t", "debug_event_t" => "&dump_debug_event_t", "CONTEXT" => "&dump_context", + "EXCEPTION_RECORD" => "&dump_exc_record", "char[1]" => "\\\"%s\\\"", "WCHAR[1]" => "&dump_unicode_string" ); @@ -80,13 +81,11 @@ my @request_lines = (); foreach $req (@requests) { push @request_lines, "DECL_HANDLER($req);\n"; } push @request_lines, "\n#ifdef WANT_REQUEST_HANDLERS\n\n"; -push @request_lines, "static const struct handler {\n"; -push @request_lines, " void (*handler)( void *req, int fd );\n"; -push @request_lines, " unsigned int min_size;\n"; -push @request_lines, "} req_handlers[REQ_NB_REQUESTS] = {\n"; +push @request_lines, "typedef void (*req_handler)( void *req );\n"; +push @request_lines, "static const req_handler req_handlers[REQ_NB_REQUESTS] =\n{\n"; foreach $req (@requests) { - push @request_lines, " { (void(*)())req_$req, sizeof(struct ${req}_request) },\n"; + push @request_lines, " (req_handler)req_$req,\n"; } push @request_lines, "};\n#endif /* WANT_REQUEST_HANDLERS */\n"; diff --git a/win32/except.c b/win32/except.c index 0f2fe0d80d4..f642481a47e 100644 --- a/win32/except.c +++ b/win32/except.c @@ -34,9 +34,10 @@ #include "process.h" #include "thread.h" #include "stackframe.h" +#include "server.h" #include "debugtools.h" -DEFAULT_DEBUG_CHANNEL(seh) +DEFAULT_DEBUG_CHANNEL(seh); /******************************************************************* @@ -69,12 +70,16 @@ void WINAPI RaiseException( DWORD code, DWORD flags, DWORD nbargs, const LPDWORD */ DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers) { + struct exception_event_request *req = get_req_buffer(); char message[80]; PDB *pdb = PROCESS_Current(); - if (DEBUG_SendExceptionEvent( epointers->ExceptionRecord, FALSE, - epointers->ContextRecord ) == DBG_CONTINUE) - return EXCEPTION_CONTINUE_EXECUTION; + /* send a last chance event to the debugger */ + req->record = *epointers->ExceptionRecord; + req->first = 0; + req->context = *epointers->ContextRecord; + if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *epointers->ContextRecord = req->context; + if (req->status == DBG_CONTINUE) return EXCEPTION_CONTINUE_EXECUTION; if (pdb->top_filter) {