Made exception_event_request non-blocking, and added
get_exception_status to retrieve the exception result returned by the debugger.
This commit is contained in:
parent
f4d5fefb0a
commit
e939eae00b
|
@ -107,22 +107,39 @@ static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
|
|||
*
|
||||
* 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),
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -938,13 +938,22 @@ struct wait_debug_event_request
|
|||
};
|
||||
|
||||
|
||||
/* 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 @@ enum request
|
|||
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 @@ union generic_request
|
|||
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 @@ union generic_request
|
|||
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 */
|
||||
|
|
|
@ -28,6 +28,7 @@ struct debug_event
|
|||
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_unload_dll_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;
|
||||
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 @@ static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event
|
|||
}
|
||||
|
||||
/* 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 @@ static struct debug_event *find_event_to_send( struct debug_ctx *debug_ctx )
|
|||
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 @@ static void debug_event_destroy( struct object *obj )
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (event->sender->context == &event->context) event->sender->context = NULL;
|
||||
release_object( event->sender );
|
||||
release_object( event->debugger );
|
||||
}
|
||||
|
@ -357,15 +350,14 @@ static int continue_debug_event( struct process *process, struct thread *thread,
|
|||
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 @@ static struct debug_event *queue_debug_event( struct thread *thread, int code, v
|
|||
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 @@ 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 );
|
||||
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(continue_debug_event)
|
|||
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 @@ DECL_HANDLER(debug_process)
|
|||
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 @@ DECL_HANDLER(exception_event)
|
|||
}
|
||||
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 );
|
||||
}
|
||||
|
|
|
@ -140,7 +140,8 @@ DECL_HANDLER(next_process);
|
|||
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 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(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,
|
||||
|
|
|
@ -1066,15 +1066,25 @@ static void dump_wait_debug_event_reply( const struct wait_debug_event_request *
|
|||
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 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(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 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(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 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"next_thread",
|
||||
"next_module",
|
||||
"wait_debug_event",
|
||||
"exception_event",
|
||||
"queue_exception_event",
|
||||
"get_exception_status",
|
||||
"output_debug_string",
|
||||
"continue_debug_event",
|
||||
"debug_process",
|
||||
|
|
|
@ -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)
|
||||
*/
|
||||
|
@ -151,20 +193,7 @@ DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
|
|||
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:
|
||||
|
|
Loading…
Reference in New Issue