Made exception_event_request non-blocking, and added
get_exception_status to retrieve the exception result returned by the
debugger.
diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c
index fea156d..611871c 100644
--- a/dlls/ntdll/exception.c
+++ b/dlls/ntdll/exception.c
@@ -107,22 +107,39 @@
*
* 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;
+ HANDLE handle = 0;
+
SERVER_START_REQ
{
- struct exception_event_request *req = server_alloc_req( sizeof(*req),
- sizeof(*rec)+sizeof(*context) );
+ 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_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;
}
SERVER_END_REQ;
+ NtClose( handle );
return ret;
}
diff --git a/include/server.h b/include/server.h
index a1fa6cd..77f394d 100644
--- a/include/server.h
+++ b/include/server.h
@@ -938,13 +938,22 @@
};
-/* Send an exception event */
-struct exception_event_request
+/* Queue an exception event */
+struct queue_exception_event_request
{
REQUEST_HEADER; /* request header */
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 */
+};
+
+
+/* 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 */
};
@@ -1426,7 +1435,8 @@
REQ_NEXT_THREAD,
REQ_NEXT_MODULE,
REQ_WAIT_DEBUG_EVENT,
- REQ_EXCEPTION_EVENT,
+ REQ_QUEUE_EXCEPTION_EVENT,
+ REQ_GET_EXCEPTION_STATUS,
REQ_OUTPUT_DEBUG_STRING,
REQ_CONTINUE_DEBUG_EVENT,
REQ_DEBUG_PROCESS,
@@ -1541,7 +1551,8 @@
struct next_thread_request next_thread;
struct next_module_request next_module;
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 continue_debug_event_request continue_debug_event;
struct debug_process_request debug_process;
@@ -1581,7 +1592,7 @@
struct async_result_request async_result;
};
-#define SERVER_PROTOCOL_VERSION 35
+#define SERVER_PROTOCOL_VERSION 36
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */
diff --git a/server/debugger.c b/server/debugger.c
index 5edee7f4..f68cdf2 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -28,6 +28,7 @@
enum debug_event_state state; /* event state */
int status; /* continuation status */
debug_event_t data; /* event data */
+ CONTEXT context; /* register context */
};
/* debug context */
@@ -180,10 +181,8 @@
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;
+ struct debug_event_output_string *data = arg;
+ event->data.info.output_string = *data;
return 1;
}
@@ -217,8 +216,11 @@
}
/* 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 );
event->next = NULL;
event->prev = debug_ctx->event_tail;
@@ -241,16 +243,6 @@
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 )
{
struct debug_event *debug_event = (struct debug_event *)obj;
@@ -297,6 +289,7 @@
break;
}
}
+ if (event->sender->context == &event->context) event->sender->context = NULL;
release_object( event->sender );
release_object( event->debugger );
}
@@ -357,15 +350,14 @@
return 0;
}
-/* queue a debug event for a debugger */
-static struct debug_event *queue_debug_event( struct thread *thread, int code, void *arg )
+/* alloc a debug event for a debugger */
+static struct debug_event *alloc_debug_event( struct thread *thread, int code,
+ void *arg, CONTEXT *context )
{
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 );
@@ -384,9 +376,11 @@
release_object( event );
return NULL;
}
-
- link_event( debug_ctx, event );
- suspend_process( thread->process );
+ if (context)
+ {
+ memcpy( &event->context, context, sizeof(event->context) );
+ thread->context = &event->context;
+ }
return event;
}
@@ -395,8 +389,13 @@
{
if (thread->process->debugger)
{
- struct debug_event *event = queue_debug_event( thread, code, arg );
- if (event) release_object( event );
+ struct debug_event *event = alloc_debug_event( thread, code, arg, NULL );
+ if (event)
+ {
+ link_event( event );
+ suspend_process( thread->process );
+ release_object( event );
+ }
}
}
@@ -535,7 +534,6 @@
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;
@@ -550,16 +548,15 @@
data.record.ExceptionAddress = get_thread_ip( process->thread_list );
data.record.NumberParameters = 0;
data.first = 1;
- if ((event = queue_debug_event( process->thread_list, EXCEPTION_DEBUG_EVENT, &data )))
- release_object( event );
+ generate_debug_event( process->thread_list, EXCEPTION_DEBUG_EVENT, &data );
}
release_object( process );
}
-/* send an exception event */
-DECL_HANDLER(exception_event)
+/* queue an exception event */
+DECL_HANDLER(queue_exception_event)
{
- req->status = 0;
+ req->handle = 0;
if (current->process->debugger)
{
struct debug_event_exception data;
@@ -574,22 +571,51 @@
}
data.record = *rec;
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;
- current->context = context;
- sleep_on( 1, &obj, 0, 0, 0, build_exception_event_reply );
+ if ((req->handle = alloc_handle( current->process, event, SYNCHRONIZE, FALSE )))
+ {
+ link_event( event );
+ suspend_process( current->process );
+ }
release_object( event );
}
}
}
+/* retrieve the status of an exception event */
+DECL_HANDLER(get_exception_status)
+{
+ 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 )))
+ {
+ if (event->state == EVENT_CONTINUED)
+ {
+ 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)
{
- if (current->process->debugger)
- {
- struct debug_event *event = queue_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, req );
- if (event) release_object( event );
- }
+ 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 );
}
diff --git a/server/request.h b/server/request.h
index 4c627a8..6eeadea 100644
--- a/server/request.h
+++ b/server/request.h
@@ -140,7 +140,8 @@
DECL_HANDLER(next_thread);
DECL_HANDLER(next_module);
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(continue_debug_event);
DECL_HANDLER(debug_process);
@@ -254,7 +255,8 @@
(req_handler)req_next_thread,
(req_handler)req_next_module,
(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_continue_debug_event,
(req_handler)req_debug_process,
diff --git a/server/trace.c b/server/trace.c
index 6779601..6690578 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1066,15 +1066,25 @@
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, " record=" );
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, " context=" );
cur_pos += dump_varargs_context( req );
@@ -1548,7 +1558,8 @@
(dump_func)dump_next_thread_request,
(dump_func)dump_next_module_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_continue_debug_event_request,
(dump_func)dump_debug_process_request,
@@ -1659,7 +1670,8 @@
(dump_func)dump_next_thread_reply,
(dump_func)dump_next_module_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,
@@ -1770,7 +1782,8 @@
"next_thread",
"next_module",
"wait_debug_event",
- "exception_event",
+ "queue_exception_event",
+ "get_exception_status",
"output_debug_string",
"continue_debug_event",
"debug_process",
diff --git a/win32/except.c b/win32/except.c
index 88962c4..07e87e5 100644
--- a/win32/except.c
+++ b/win32/except.c
@@ -138,6 +138,48 @@
}
+/**********************************************************************
+ * 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)
*/
@@ -151,20 +193,7 @@
int status;
/* send a last chance event to the debugger */
- SERVER_START_REQ
- {
- 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;
-
+ status = send_debug_event( epointers->ExceptionRecord, FALSE, epointers->ContextRecord );
switch (status)
{
case DBG_CONTINUE: