Commit e939eae0 authored by Alexandre Julliard's avatar Alexandre Julliard

Made exception_event_request non-blocking, and added

get_exception_status to retrieve the exception result returned by the debugger.
parent f4d5fefb
...@@ -107,22 +107,39 @@ static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, ...@@ -107,22 +107,39 @@ static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
* *
* Send an EXCEPTION_DEBUG_EVENT event to the debugger. * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
*/ */
static inline int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context ) static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
{ {
int ret; int ret;
HANDLE handle = 0;
SERVER_START_REQ SERVER_START_REQ
{ {
struct exception_event_request *req = server_alloc_req( sizeof(*req), struct queue_exception_event_request *req = server_alloc_req( sizeof(*req),
sizeof(*rec)+sizeof(*context) ); sizeof(*rec)+sizeof(*context) );
CONTEXT *context_ptr = server_data_ptr(req); CONTEXT *context_ptr = server_data_ptr(req);
EXCEPTION_RECORD *rec_ptr = (EXCEPTION_RECORD *)(context_ptr + 1); EXCEPTION_RECORD *rec_ptr = (EXCEPTION_RECORD *)(context_ptr + 1);
req->first = first_chance; req->first = first_chance;
*rec_ptr = *rec; *rec_ptr = *rec;
*context_ptr = *context; *context_ptr = *context;
if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *context = *context_ptr; if (!server_call_noerr( REQ_QUEUE_EXCEPTION_EVENT )) handle = req->handle;
}
SERVER_END_REQ;
if (!handle) return 0; /* no debugger present or other error */
/* No need to wait on the handle since the process gets suspended
* once the event is passed to the debugger, so when we get back
* here the event has been continued already.
*/
SERVER_START_REQ
{
struct get_exception_status_request *req = server_alloc_req( sizeof(*req), sizeof(*context) );
req->handle = handle;
if (!server_call_noerr( REQ_GET_EXCEPTION_STATUS ))
*context = *(CONTEXT *)server_data_ptr(req);
ret = req->status; ret = req->status;
} }
SERVER_END_REQ; SERVER_END_REQ;
NtClose( handle );
return ret; return ret;
} }
......
...@@ -938,13 +938,22 @@ struct wait_debug_event_request ...@@ -938,13 +938,22 @@ struct wait_debug_event_request
}; };
/* Send an exception event */ /* Queue an exception event */
struct exception_event_request struct queue_exception_event_request
{ {
REQUEST_HEADER; /* request header */ REQUEST_HEADER; /* request header */
IN int first; /* first chance exception? */ IN int first; /* first chance exception? */
OUT int status; /* event continuation status */ OUT handle_t handle; /* handle to the queued event */
IN VARARG(record,exc_event); /* thread context followed by exception record */ IN VARARG(record,exc_event); /* thread context followed by exception record */
};
/* Retrieve the status of an exception event */
struct get_exception_status_request
{
REQUEST_HEADER; /* request header */
OUT handle_t handle; /* handle to the queued event */
OUT int status; /* event continuation status */
OUT VARARG(context,context); /* modified thread context */ OUT VARARG(context,context); /* modified thread context */
}; };
...@@ -1426,7 +1435,8 @@ enum request ...@@ -1426,7 +1435,8 @@ enum request
REQ_NEXT_THREAD, REQ_NEXT_THREAD,
REQ_NEXT_MODULE, REQ_NEXT_MODULE,
REQ_WAIT_DEBUG_EVENT, REQ_WAIT_DEBUG_EVENT,
REQ_EXCEPTION_EVENT, REQ_QUEUE_EXCEPTION_EVENT,
REQ_GET_EXCEPTION_STATUS,
REQ_OUTPUT_DEBUG_STRING, REQ_OUTPUT_DEBUG_STRING,
REQ_CONTINUE_DEBUG_EVENT, REQ_CONTINUE_DEBUG_EVENT,
REQ_DEBUG_PROCESS, REQ_DEBUG_PROCESS,
...@@ -1541,7 +1551,8 @@ union generic_request ...@@ -1541,7 +1551,8 @@ union generic_request
struct next_thread_request next_thread; struct next_thread_request next_thread;
struct next_module_request next_module; struct next_module_request next_module;
struct wait_debug_event_request wait_debug_event; struct wait_debug_event_request wait_debug_event;
struct exception_event_request exception_event; struct queue_exception_event_request queue_exception_event;
struct get_exception_status_request get_exception_status;
struct output_debug_string_request output_debug_string; struct output_debug_string_request output_debug_string;
struct continue_debug_event_request continue_debug_event; struct continue_debug_event_request continue_debug_event;
struct debug_process_request debug_process; struct debug_process_request debug_process;
...@@ -1581,7 +1592,7 @@ union generic_request ...@@ -1581,7 +1592,7 @@ union generic_request
struct async_result_request async_result; struct async_result_request async_result;
}; };
#define SERVER_PROTOCOL_VERSION 35 #define SERVER_PROTOCOL_VERSION 36
/* ### make_requests end ### */ /* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */ /* Everything above this line is generated automatically by tools/make_requests */
......
...@@ -28,6 +28,7 @@ struct debug_event ...@@ -28,6 +28,7 @@ struct debug_event
enum debug_event_state state; /* event state */ enum debug_event_state state; /* event state */
int status; /* continuation status */ int status; /* continuation status */
debug_event_t data; /* event data */ debug_event_t data; /* event data */
CONTEXT context; /* register context */
}; };
/* debug context */ /* debug context */
...@@ -180,10 +181,8 @@ static int fill_unload_dll_event( struct debug_event *event, void *arg ) ...@@ -180,10 +181,8 @@ static int fill_unload_dll_event( struct debug_event *event, void *arg )
static int fill_output_debug_string_event( struct debug_event *event, void *arg ) static int fill_output_debug_string_event( struct debug_event *event, void *arg )
{ {
struct output_debug_string_request *req = arg; struct debug_event_output_string *data = arg;
event->data.info.output_string.string = req->string; event->data.info.output_string = *data;
event->data.info.output_string.unicode = req->unicode;
event->data.info.output_string.length = req->length;
return 1; return 1;
} }
...@@ -217,8 +216,11 @@ static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event ...@@ -217,8 +216,11 @@ static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event
} }
/* link an event at the end of the queue */ /* link an event at the end of the queue */
static void link_event( struct debug_ctx *debug_ctx, struct debug_event *event ) static void link_event( struct debug_event *event )
{ {
struct debug_ctx *debug_ctx = event->debugger->debug_ctx;
assert( debug_ctx );
grab_object( event ); grab_object( event );
event->next = NULL; event->next = NULL;
event->prev = debug_ctx->event_tail; event->prev = debug_ctx->event_tail;
...@@ -241,16 +243,6 @@ static struct debug_event *find_event_to_send( struct debug_ctx *debug_ctx ) ...@@ -241,16 +243,6 @@ static struct debug_event *find_event_to_send( struct debug_ctx *debug_ctx )
return event; return event;
} }
/* build a reply for the send_event request */
static void build_exception_event_reply( struct thread *thread, struct object *obj, int signaled )
{
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;
thread->context = NULL;
}
static void debug_event_dump( struct object *obj, int verbose ) static void debug_event_dump( struct object *obj, int verbose )
{ {
struct debug_event *debug_event = (struct debug_event *)obj; struct debug_event *debug_event = (struct debug_event *)obj;
...@@ -297,6 +289,7 @@ static void debug_event_destroy( struct object *obj ) ...@@ -297,6 +289,7 @@ static void debug_event_destroy( struct object *obj )
break; break;
} }
} }
if (event->sender->context == &event->context) event->sender->context = NULL;
release_object( event->sender ); release_object( event->sender );
release_object( event->debugger ); release_object( event->debugger );
} }
...@@ -357,15 +350,14 @@ static int continue_debug_event( struct process *process, struct thread *thread, ...@@ -357,15 +350,14 @@ static int continue_debug_event( struct process *process, struct thread *thread,
return 0; return 0;
} }
/* queue a debug event for a debugger */ /* alloc a debug event for a debugger */
static struct debug_event *queue_debug_event( struct thread *thread, int code, void *arg ) static struct debug_event *alloc_debug_event( struct thread *thread, int code,
void *arg, CONTEXT *context )
{ {
struct thread *debugger = thread->process->debugger; struct thread *debugger = thread->process->debugger;
struct debug_ctx *debug_ctx = debugger->debug_ctx;
struct debug_event *event; struct debug_event *event;
assert( code > 0 && code <= NB_DEBUG_EVENTS ); assert( code > 0 && code <= NB_DEBUG_EVENTS );
assert( debug_ctx );
/* cannot queue a debug event for myself */ /* cannot queue a debug event for myself */
assert( debugger->process != thread->process ); assert( debugger->process != thread->process );
...@@ -384,9 +376,11 @@ static struct debug_event *queue_debug_event( struct thread *thread, int code, v ...@@ -384,9 +376,11 @@ static struct debug_event *queue_debug_event( struct thread *thread, int code, v
release_object( event ); release_object( event );
return NULL; return NULL;
} }
if (context)
link_event( debug_ctx, event ); {
suspend_process( thread->process ); memcpy( &event->context, context, sizeof(event->context) );
thread->context = &event->context;
}
return event; return event;
} }
...@@ -395,8 +389,13 @@ void generate_debug_event( struct thread *thread, int code, void *arg ) ...@@ -395,8 +389,13 @@ void generate_debug_event( struct thread *thread, int code, void *arg )
{ {
if (thread->process->debugger) if (thread->process->debugger)
{ {
struct debug_event *event = queue_debug_event( thread, code, arg ); struct debug_event *event = alloc_debug_event( thread, code, arg, NULL );
if (event) release_object( event ); if (event)
{
link_event( event );
suspend_process( thread->process );
release_object( event );
}
} }
} }
...@@ -535,7 +534,6 @@ DECL_HANDLER(continue_debug_event) ...@@ -535,7 +534,6 @@ DECL_HANDLER(continue_debug_event)
DECL_HANDLER(debug_process) DECL_HANDLER(debug_process)
{ {
struct debug_event_exception data; struct debug_event_exception data;
struct debug_event *event;
struct process *process = get_process_from_id( req->pid ); struct process *process = get_process_from_id( req->pid );
if (!process) return; if (!process) return;
...@@ -550,16 +548,15 @@ DECL_HANDLER(debug_process) ...@@ -550,16 +548,15 @@ DECL_HANDLER(debug_process)
data.record.ExceptionAddress = get_thread_ip( process->thread_list ); data.record.ExceptionAddress = get_thread_ip( process->thread_list );
data.record.NumberParameters = 0; data.record.NumberParameters = 0;
data.first = 1; data.first = 1;
if ((event = queue_debug_event( process->thread_list, EXCEPTION_DEBUG_EVENT, &data ))) generate_debug_event( process->thread_list, EXCEPTION_DEBUG_EVENT, &data );
release_object( event );
} }
release_object( process ); release_object( process );
} }
/* send an exception event */ /* queue an exception event */
DECL_HANDLER(exception_event) DECL_HANDLER(queue_exception_event)
{ {
req->status = 0; req->handle = 0;
if (current->process->debugger) if (current->process->debugger)
{ {
struct debug_event_exception data; struct debug_event_exception data;
...@@ -574,22 +571,51 @@ DECL_HANDLER(exception_event) ...@@ -574,22 +571,51 @@ DECL_HANDLER(exception_event)
} }
data.record = *rec; data.record = *rec;
data.first = req->first; data.first = req->first;
if ((event = queue_debug_event( current, EXCEPTION_DEBUG_EVENT, &data ))) if ((event = alloc_debug_event( current, EXCEPTION_DEBUG_EVENT, &data, context )))
{ {
struct object *obj = &event->obj; if ((req->handle = alloc_handle( current->process, event, SYNCHRONIZE, FALSE )))
current->context = context; {
sleep_on( 1, &obj, 0, 0, 0, build_exception_event_reply ); link_event( event );
suspend_process( current->process );
}
release_object( event ); release_object( event );
} }
} }
} }
/* send an output string to the debugger */ /* retrieve the status of an exception event */
DECL_HANDLER(output_debug_string) DECL_HANDLER(get_exception_status)
{ {
if (current->process->debugger) struct debug_event *event;
size_t size = 0;
req->status = 0;
if ((event = (struct debug_event *)get_handle_obj( current->process, req->handle,
0, &debug_event_ops )))
{ {
struct debug_event *event = queue_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, req ); if (event->state == EVENT_CONTINUED)
if (event) release_object( event ); {
req->status = event->status;
if (current->context == &event->context)
{
size = min( sizeof(CONTEXT), get_req_data_size(req) );
memcpy( get_req_data(req), &event->context, size );
current->context = NULL;
}
}
else set_error( STATUS_PENDING );
release_object( event );
} }
set_req_data_size( req, size );
}
/* send an output string to the debugger */
DECL_HANDLER(output_debug_string)
{
struct debug_event_output_string data;
data.string = req->string;
data.unicode = req->unicode;
data.length = req->length;
generate_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, &data );
} }
...@@ -140,7 +140,8 @@ DECL_HANDLER(next_process); ...@@ -140,7 +140,8 @@ DECL_HANDLER(next_process);
DECL_HANDLER(next_thread); DECL_HANDLER(next_thread);
DECL_HANDLER(next_module); DECL_HANDLER(next_module);
DECL_HANDLER(wait_debug_event); DECL_HANDLER(wait_debug_event);
DECL_HANDLER(exception_event); DECL_HANDLER(queue_exception_event);
DECL_HANDLER(get_exception_status);
DECL_HANDLER(output_debug_string); DECL_HANDLER(output_debug_string);
DECL_HANDLER(continue_debug_event); DECL_HANDLER(continue_debug_event);
DECL_HANDLER(debug_process); DECL_HANDLER(debug_process);
...@@ -254,7 +255,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = ...@@ -254,7 +255,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_next_thread, (req_handler)req_next_thread,
(req_handler)req_next_module, (req_handler)req_next_module,
(req_handler)req_wait_debug_event, (req_handler)req_wait_debug_event,
(req_handler)req_exception_event, (req_handler)req_queue_exception_event,
(req_handler)req_get_exception_status,
(req_handler)req_output_debug_string, (req_handler)req_output_debug_string,
(req_handler)req_continue_debug_event, (req_handler)req_continue_debug_event,
(req_handler)req_debug_process, (req_handler)req_debug_process,
......
...@@ -1066,15 +1066,25 @@ static void dump_wait_debug_event_reply( const struct wait_debug_event_request * ...@@ -1066,15 +1066,25 @@ static void dump_wait_debug_event_reply( const struct wait_debug_event_request *
cur_pos += dump_varargs_debug_event( req ); cur_pos += dump_varargs_debug_event( req );
} }
static void dump_exception_event_request( const struct exception_event_request *req ) static void dump_queue_exception_event_request( const struct queue_exception_event_request *req )
{ {
fprintf( stderr, " first=%d,", req->first ); fprintf( stderr, " first=%d,", req->first );
fprintf( stderr, " record=" ); fprintf( stderr, " record=" );
cur_pos += dump_varargs_exc_event( req ); cur_pos += dump_varargs_exc_event( req );
} }
static void dump_exception_event_reply( const struct exception_event_request *req ) static void dump_queue_exception_event_reply( const struct queue_exception_event_request *req )
{ {
fprintf( stderr, " handle=%d", req->handle );
}
static void dump_get_exception_status_request( const struct get_exception_status_request *req )
{
}
static void dump_get_exception_status_reply( const struct get_exception_status_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " status=%d,", req->status ); fprintf( stderr, " status=%d,", req->status );
fprintf( stderr, " context=" ); fprintf( stderr, " context=" );
cur_pos += dump_varargs_context( req ); cur_pos += dump_varargs_context( req );
...@@ -1548,7 +1558,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { ...@@ -1548,7 +1558,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_next_thread_request, (dump_func)dump_next_thread_request,
(dump_func)dump_next_module_request, (dump_func)dump_next_module_request,
(dump_func)dump_wait_debug_event_request, (dump_func)dump_wait_debug_event_request,
(dump_func)dump_exception_event_request, (dump_func)dump_queue_exception_event_request,
(dump_func)dump_get_exception_status_request,
(dump_func)dump_output_debug_string_request, (dump_func)dump_output_debug_string_request,
(dump_func)dump_continue_debug_event_request, (dump_func)dump_continue_debug_event_request,
(dump_func)dump_debug_process_request, (dump_func)dump_debug_process_request,
...@@ -1659,7 +1670,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { ...@@ -1659,7 +1670,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_next_thread_reply, (dump_func)dump_next_thread_reply,
(dump_func)dump_next_module_reply, (dump_func)dump_next_module_reply,
(dump_func)dump_wait_debug_event_reply, (dump_func)dump_wait_debug_event_reply,
(dump_func)dump_exception_event_reply, (dump_func)dump_queue_exception_event_reply,
(dump_func)dump_get_exception_status_reply,
(dump_func)0, (dump_func)0,
(dump_func)0, (dump_func)0,
(dump_func)0, (dump_func)0,
...@@ -1770,7 +1782,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = { ...@@ -1770,7 +1782,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"next_thread", "next_thread",
"next_module", "next_module",
"wait_debug_event", "wait_debug_event",
"exception_event", "queue_exception_event",
"get_exception_status",
"output_debug_string", "output_debug_string",
"continue_debug_event", "continue_debug_event",
"debug_process", "debug_process",
......
...@@ -138,6 +138,48 @@ static void format_exception_msg( const EXCEPTION_POINTERS *ptr, char *buffer ) ...@@ -138,6 +138,48 @@ static void format_exception_msg( const EXCEPTION_POINTERS *ptr, char *buffer )
} }
/**********************************************************************
* send_debug_event
*
* Send an EXCEPTION_DEBUG_EVENT event to the debugger.
*/
static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
{
int ret;
HANDLE handle = 0;
SERVER_START_REQ
{
struct queue_exception_event_request *req = server_alloc_req( sizeof(*req),
sizeof(*rec)+sizeof(*context) );
CONTEXT *context_ptr = server_data_ptr(req);
EXCEPTION_RECORD *rec_ptr = (EXCEPTION_RECORD *)(context_ptr + 1);
req->first = first_chance;
*rec_ptr = *rec;
*context_ptr = *context;
if (!server_call_noerr( REQ_QUEUE_EXCEPTION_EVENT )) handle = req->handle;
}
SERVER_END_REQ;
if (!handle) return 0; /* no debugger present or other error */
/* No need to wait on the handle since the process gets suspended
* once the event is passed to the debugger, so when we get back
* here the event has been continued already.
*/
SERVER_START_REQ
{
struct get_exception_status_request *req = server_alloc_req( sizeof(*req), sizeof(*context) );
req->handle = handle;
if (!server_call_noerr( REQ_GET_EXCEPTION_STATUS ))
*context = *(CONTEXT *)server_data_ptr(req);
ret = req->status;
}
SERVER_END_REQ;
NtClose( handle );
return ret;
}
/******************************************************************* /*******************************************************************
* UnhandledExceptionFilter (KERNEL32.537) * UnhandledExceptionFilter (KERNEL32.537)
*/ */
...@@ -151,20 +193,7 @@ DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers) ...@@ -151,20 +193,7 @@ DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
int status; int status;
/* send a last chance event to the debugger */ /* send a last chance event to the debugger */
SERVER_START_REQ status = send_debug_event( epointers->ExceptionRecord, FALSE, epointers->ContextRecord );
{
struct exception_event_request *req = server_alloc_req( sizeof(*req),
sizeof(EXCEPTION_RECORD)+sizeof(CONTEXT) );
CONTEXT *context_ptr = server_data_ptr(req);
EXCEPTION_RECORD *rec_ptr = (EXCEPTION_RECORD *)(context_ptr + 1);
req->first = 0;
*rec_ptr = *epointers->ExceptionRecord;
*context_ptr = *epointers->ContextRecord;
if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *epointers->ContextRecord = *context_ptr;
status = req->status;
}
SERVER_END_REQ;
switch (status) switch (status)
{ {
case DBG_CONTINUE: case DBG_CONTINUE:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment