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:
Alexandre Julliard 2001-01-26 20:45:41 +00:00
parent f4d5fefb0a
commit e939eae00b
6 changed files with 168 additions and 70 deletions

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 );
}

View File

@ -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,

View File

@ -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",

View File

@ -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: