From e712e077bcc669cbd5a71339f4b0adf0d07766c0 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sun, 23 May 1999 19:53:30 +0000 Subject: [PATCH] Added debug events support. --- include/server.h | 117 ++++++++++++- include/server/request.h | 12 ++ server/Makefile.in | 1 + server/debugger.c | 438 +++++++++++++++++++++++++++++++++++++++++++++++ server/object.h | 5 + server/process.c | 19 +- server/thread.c | 3 + server/thread.h | 2 + server/trace.c | 53 ++++++ 9 files changed, 646 insertions(+), 4 deletions(-) create mode 100644 server/debugger.c diff --git a/include/server.h b/include/server.h index eca3e934ee0..100a0c7433a 100644 --- a/include/server.h +++ b/include/server.h @@ -48,6 +48,7 @@ struct new_process_request { int inherit; /* inherit flag */ int inherit_all; /* inherit all handles from parent */ + int create_flags; /* creation flags */ int start_flags; /* flags from startup info */ int hstdin; /* handle for stdin */ int hstdout; /* handle for stdout */ @@ -732,6 +733,119 @@ struct next_process_reply }; +/* Wait for a debug event */ +struct wait_debug_event_request +{ + int timeout; /* timeout in ms */ +}; +struct wait_debug_event_reply +{ + int code; /* event code */ + void* pid; /* process id */ + void* tid; /* thread id */ + /* followed by the event data (see below) */ +}; + + +/* Send a debug event */ +struct send_debug_event_request +{ + int code; /* event code */ + /* followed by the event data (see below) */ +}; +struct send_debug_event_reply +{ + int status; /* event continuation status */ +}; + + +/* 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? */ +}; +struct debug_event_create_thread +{ + int handle; /* handle to the new thread */ + void *teb; /* thread teb (in debugged process address space) */ + void *start; /* thread startup routine */ +}; +struct debug_event_create_process +{ + int file; /* handle to the process exe file */ + int process; /* handle to the new process */ + int thread; /* handle to the new thread */ + void *base; /* base of executable image */ + int dbg_offset; /* offset of debug info in file */ + int dbg_size; /* size of debug info */ + void *teb; /* thread teb (in debugged process address space) */ + void *start; /* thread startup routine */ + void *name; /* image name (optional) */ + int unicode; /* is it Unicode? */ +}; +struct debug_event_exit +{ + int exit_code; /* thread or process exit code */ +}; +struct debug_event_load_dll +{ + int handle; /* file handle for the dll */ + void *base; /* base address of the dll */ + int dbg_offset; /* offset of debug info in file */ + int dbg_size; /* size of debug info */ + void *name; /* image name (optional) */ + int unicode; /* is it Unicode? */ +}; +struct debug_event_unload_dll +{ + void *base; /* base address of the dll */ +}; +struct debug_event_output_string +{ + void *string; /* string to display (in debugged process address space) */ + int unicode; /* is it Unicode? */ + int length; /* string length */ +}; +struct debug_event_rip_info +{ + int error; /* ??? */ + int type; /* ??? */ +}; +union debug_event_data +{ + struct debug_event_exception exception; + struct debug_event_create_thread create_thread; + struct debug_event_create_process create_process; + struct debug_event_exit exit; + struct debug_event_load_dll load_dll; + struct debug_event_unload_dll unload_dll; + struct debug_event_output_string output_string; + struct debug_event_rip_info rip_info; +}; + + +/* Continue a debug event */ +struct continue_debug_event_request +{ + void* pid; /* process id to continue */ + void* tid; /* thread id to continue */ + int status; /* continuation status */ +}; + + +/* Start debugging an existing process */ +struct debug_process_request +{ + void* pid; /* id of the process to debug */ +}; + + /* requests definitions */ #include "server/request.h" @@ -740,14 +854,13 @@ struct next_process_reply #ifndef __WINE_SERVER__ /* client communication functions */ +extern void CLIENT_ProtocolError( const char *err, ... ); extern void CLIENT_SendRequest( enum request req, int pass_fd, int n, ... /* arg_1, len_1, etc. */ ); extern unsigned int CLIENT_WaitReply( int *len, int *passed_fd, int n, ... /* arg_1, len_1, etc. */ ); extern unsigned int CLIENT_WaitSimpleReply( void *reply, int len, int *passed_fd ); extern int CLIENT_InitServer(void); - -struct _THDB; extern int CLIENT_SetDebug( int level ); extern int CLIENT_DebuggerRequest( int op ); extern int CLIENT_InitThread(void); diff --git a/include/server/request.h b/include/server/request.h index ae44fa289d9..d69db10f22d 100644 --- a/include/server/request.h +++ b/include/server/request.h @@ -63,6 +63,10 @@ enum request REQ_CREATE_DEVICE, REQ_CREATE_SNAPSHOT, REQ_NEXT_PROCESS, + REQ_WAIT_DEBUG_EVENT, + REQ_SEND_DEBUG_EVENT, + REQ_CONTINUE_DEBUG_EVENT, + REQ_DEBUG_PROCESS, REQ_NB_REQUESTS }; @@ -126,6 +130,10 @@ DECL_HANDLER(get_mapping_info); DECL_HANDLER(create_device); DECL_HANDLER(create_snapshot); DECL_HANDLER(next_process); +DECL_HANDLER(wait_debug_event); +DECL_HANDLER(send_debug_event); +DECL_HANDLER(continue_debug_event); +DECL_HANDLER(debug_process); static const struct handler { void (*handler)(); @@ -189,6 +197,10 @@ static const struct handler { { (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) }, }; #endif /* WANT_REQUEST_HANDLERS */ diff --git a/server/Makefile.in b/server/Makefile.in index 3aaa6da47b8..e98e457d539 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -8,6 +8,7 @@ MODULE = server C_SRCS = \ change.c \ console.c \ + debugger.c \ device.c \ event.c \ file.c \ diff --git a/server/debugger.c b/server/debugger.c new file mode 100644 index 00000000000..3a85925d2fa --- /dev/null +++ b/server/debugger.c @@ -0,0 +1,438 @@ +/* + * Server-side debugger functions + * + * Copyright (C) 1999 Alexandre Julliard + */ + +#include +#include "winbase.h" +#include "winerror.h" + +#include "server.h" +#include "handle.h" +#include "process.h" +#include "thread.h" + + +struct debug_event +{ + struct debug_event *next; /* event queue */ + struct debug_event *prev; + struct thread *thread; /* thread which sent this event */ + int sent; /* already sent to the debugger? */ + int code; /* event code */ + union debug_event_data data; /* event data */ +}; + +struct debug_ctx +{ + struct thread *owner; /* thread owning this debug context */ + int waiting; /* is thread waiting for an event? */ + struct timeout_user *timeout; /* timeout user for wait timeout */ + struct debug_event *event_head; /* head of pending events queue */ + struct debug_event *event_tail; /* tail of pending events queue */ +}; + +/* size of the event data */ +static const int event_sizes[] = +{ + 0, + sizeof(struct debug_event_exception), /* EXCEPTION_DEBUG_EVENT */ + sizeof(struct debug_event_create_thread), /* CREATE_THREAD_DEBUG_EVENT */ + sizeof(struct debug_event_create_process), /* CREATE_PROCESS_DEBUG_EVENT */ + sizeof(struct debug_event_exit), /* EXIT_THREAD_DEBUG_EVENT */ + sizeof(struct debug_event_exit), /* EXIT_PROCESS_DEBUG_EVENT */ + sizeof(struct debug_event_load_dll), /* LOAD_DLL_DEBUG_EVENT */ + sizeof(struct debug_event_unload_dll), /* UNLOAD_DLL_DEBUG_EVENT */ + sizeof(struct debug_event_output_string), /* OUTPUT_DEBUG_STRING_EVENT */ + sizeof(struct debug_event_rip_info) /* RIP_EVENT */ +}; + + +/* initialise the fields that do not need to be filled by the client */ +static int fill_debug_event( struct thread *debugger, struct thread *thread, + struct debug_event *event ) +{ + int handle; + + /* some events need special handling */ + switch(event->code) + { + case CREATE_THREAD_DEBUG_EVENT: + if ((event->data.create_thread.handle = alloc_handle( debugger->process, thread, + THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME, FALSE )) == -1) + return 0; + break; + case CREATE_PROCESS_DEBUG_EVENT: + if ((handle = event->data.create_process.file) != -1) + { + if ((handle = duplicate_handle( thread->process, handle, debugger->process, + GENERIC_READ, FALSE, 0 )) == -1) + return 0; + event->data.create_process.file = handle; + } + if ((event->data.create_process.process = alloc_handle( debugger->process, thread->process, + PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE )) == -1) + { + if (handle != -1) close_handle( debugger->process, handle ); + return 0; + } + if ((event->data.create_process.thread = alloc_handle( debugger->process, thread, + THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME, FALSE )) == -1) + { + if (handle != -1) close_handle( debugger->process, handle ); + close_handle( debugger->process, event->data.create_process.process ); + return 0; + } + break; + case LOAD_DLL_DEBUG_EVENT: + if ((handle = event->data.load_dll.handle) != -1) + { + if ((handle = duplicate_handle( thread->process, handle, debugger->process, + GENERIC_READ, FALSE, 0 )) == -1) + return 0; + event->data.load_dll.handle = handle; + } + break; + } + return 1; +} + +/* free a debug event structure */ +static void free_event( struct debug_event *event ) +{ + switch(event->code) + { + case CREATE_THREAD_DEBUG_EVENT: + close_handle( event->thread->process, event->data.create_thread.handle ); + break; + case CREATE_PROCESS_DEBUG_EVENT: + if (event->data.create_process.file != -1) + close_handle( event->thread->process, event->data.create_process.file ); + close_handle( event->thread->process, event->data.create_process.thread ); + close_handle( event->thread->process, event->data.create_process.process ); + break; + case LOAD_DLL_DEBUG_EVENT: + if (event->data.load_dll.handle != -1) + close_handle( event->thread->process, event->data.load_dll.handle ); + break; + } + event->thread->debug_event = NULL; + release_object( event->thread ); + free( event ); +} + +/* unlink the first event from the queue */ +static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event ) +{ + if (event->prev) event->prev->next = event->next; + else debug_ctx->event_head = event->next; + if (event->next) event->next->prev = event->prev; + else debug_ctx->event_tail = event->prev; + event->next = event->prev = NULL; +} + +/* link an event at the end of the queue */ +static void link_event( struct debug_ctx *debug_ctx, struct debug_event *event ) +{ + event->next = NULL; + event->prev = debug_ctx->event_tail; + if (event->prev) event->prev->next = event; + else debug_ctx->event_head = event; + debug_ctx->event_tail = event; +} + +/* send the first queue event as a reply */ +static void send_event_reply( struct debug_ctx *debug_ctx ) +{ + struct wait_debug_event_reply reply; + struct debug_event *event = debug_ctx->event_head; + struct thread *thread = event->thread; + + assert( event ); + assert( debug_ctx->waiting ); + + unlink_event( debug_ctx, event ); + event->sent = 1; + reply.code = event->code; + reply.pid = thread->process; + reply.tid = thread; + debug_ctx->waiting = 0; + if (debug_ctx->timeout) + { + remove_timeout_user( debug_ctx->timeout ); + debug_ctx->timeout = NULL; + } + debug_ctx->owner->error = 0; + send_reply( debug_ctx->owner, -1, 2, &reply, sizeof(reply), + &event->data, event_sizes[event->code] ); +} + +/* timeout callback while waiting for a debug event */ +static void wait_event_timeout( void *ctx ) +{ + struct debug_ctx *debug_ctx = (struct debug_ctx *)ctx; + struct wait_debug_event_reply reply; + + assert( debug_ctx->waiting ); + + reply.code = 0; + reply.pid = 0; + reply.tid = 0; + debug_ctx->waiting = 0; + debug_ctx->timeout = NULL; + debug_ctx->owner->error = WAIT_TIMEOUT; + send_reply( debug_ctx->owner, -1, 1, &reply, sizeof(reply) ); +} + +/* wait for a debug event (or send a reply at once if one is pending) */ +static int wait_for_debug_event( int timeout ) +{ + struct debug_ctx *debug_ctx = current->debug_ctx; + struct timeval when; + + if (!debug_ctx) /* current thread is not a debugger */ + { + SET_ERROR( ERROR_ACCESS_DENIED ); /* FIXME */ + return 0; + } + assert( !debug_ctx->waiting ); + if (debug_ctx->event_head) /* already have a pending event */ + { + debug_ctx->waiting = 1; + send_event_reply( debug_ctx ); + return 1; + } + if (!timeout) /* no event and we don't want to wait */ + { + SET_ERROR( WAIT_TIMEOUT ); + return 0; + } + if (timeout != -1) /* start the timeout */ + { + make_timeout( &when, timeout ); + if (!(debug_ctx->timeout = add_timeout_user( &when, wait_event_timeout, debug_ctx ))) + return 0; + } + debug_ctx->waiting = 1; + return 1; +} + +/* continue a debug event */ +static int continue_debug_event( struct process *process, struct thread *thread, int status ) +{ + struct debug_event *event = thread->debug_event; + + if (process->debugger != current || !event || !event->sent) + { + /* not debugging this process, or no event pending */ + SET_ERROR( ERROR_ACCESS_DENIED ); /* FIXME */ + return 0; + } + if (thread->state != TERMINATED) + { + /* only send a reply if the thread is still there */ + /* (we can get a continue on an exit thread/process event) */ + struct send_debug_event_reply reply; + reply.status = status; + send_reply( thread, -1, 1, &reply, sizeof(reply) ); + } + free_event( event ); + resume_process( process ); + return 1; +} + +/* queue a debug event for a debugger */ +static struct debug_event *queue_debug_event( struct thread *debugger, struct thread *thread, + int code, void *data ) +{ + struct debug_ctx *debug_ctx = debugger->debug_ctx; + struct debug_event *event; + + assert( debug_ctx ); + /* cannot queue a debug event for myself */ + assert( debugger->process != thread->process ); + + /* build the event */ + if (!(event = mem_alloc( sizeof(*event) - sizeof(event->data) + event_sizes[code] ))) + return NULL; + event->sent = 0; + event->code = code; + event->thread = (struct thread *)grab_object( thread ); + memcpy( &event->data, data, event_sizes[code] ); + + if (!fill_debug_event( debugger, thread, event )) + { + release_object( event->thread ); + free( event ); + return NULL; + } + + if (thread->debug_event) + { + /* only exit events can replace others */ + assert( code == EXIT_THREAD_DEBUG_EVENT || code == EXIT_PROCESS_DEBUG_EVENT ); + if (!thread->debug_event->sent) unlink_event( debug_ctx, thread->debug_event ); + free_event( thread->debug_event ); + } + + link_event( debug_ctx, event ); + thread->debug_event = event; + suspend_process( thread->process ); + if (debug_ctx->waiting) send_event_reply( debug_ctx ); + return event; +} + +/* attach a process to a debugger thread */ +int debugger_attach( struct process *process, struct thread *debugger ) +{ + struct debug_ctx *debug_ctx; + struct thread *thread; + + if (process->debugger) /* already being debugged */ + { + SET_ERROR( ERROR_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( ERROR_ACCESS_DENIED ); + return 0; + } + + if (!debugger->debug_ctx) /* need to allocate a context */ + { + assert( !debugger->debug_first ); + if (!(debug_ctx = mem_alloc( sizeof(*debug_ctx) ))) return 0; + debug_ctx->owner = current; + debug_ctx->waiting = 0; + debug_ctx->timeout = NULL; + debug_ctx->event_head = NULL; + debug_ctx->event_tail = NULL; + debugger->debug_ctx = debug_ctx; + } + process->debugger = debugger; + process->debug_prev = NULL; + process->debug_next = debugger->debug_first; + debugger->debug_first = process; + return 1; +} + +/* detach a process from its debugger thread */ +static void debugger_detach( struct process *process ) +{ + struct thread *debugger = process->debugger; + + assert( debugger ); + + if (process->debug_next) process->debug_next->debug_prev = process->debug_prev; + if (process->debug_prev) process->debug_prev->debug_next = process->debug_next; + else debugger->debug_first = process; + process->debugger = NULL; +} + +/* a thread is exiting */ +void debug_exit_thread( struct thread *thread, int exit_code ) +{ + struct thread *debugger = current->process->debugger; + struct debug_ctx *debug_ctx = thread->debug_ctx; + + if (debugger) /* being debugged -> send an event to the debugger */ + { + struct debug_event_exit event; + event.exit_code = exit_code; + if (!thread->proc_next && !thread->proc_prev) + { + assert( thread->process->thread_list == thread ); + /* this is the last thread, send an exit process event and cleanup */ + queue_debug_event( debugger, current, EXIT_PROCESS_DEBUG_EVENT, &event ); + debugger_detach( thread->process ); + } + else queue_debug_event( debugger, current, EXIT_THREAD_DEBUG_EVENT, &event ); + } + + if (debug_ctx) /* this thread is a debugger */ + { + struct debug_event *event; + + /* kill all debugged processes */ + while (thread->debug_first) kill_process( thread->debug_first, exit_code ); + /* free all pending events */ + while ((event = debug_ctx->event_head) != NULL) + { + unlink_event( debug_ctx, event ); + free_event( event ); + } + /* remove the timeout */ + if (debug_ctx->timeout) remove_timeout_user( debug_ctx->timeout ); + thread->debug_ctx = NULL; + free( debug_ctx ); + } +} + +/* Wait for a debug event */ +DECL_HANDLER(wait_debug_event) +{ + struct wait_debug_event_reply reply; + + if (!wait_for_debug_event( req->timeout )) + { + reply.code = 0; + reply.pid = NULL; + reply.tid = NULL; + send_reply( current, -1, 1, &reply, sizeof(reply) ); + } +} + +/* Continue a debug event */ +DECL_HANDLER(continue_debug_event) +{ + struct process *process = get_process_from_id( req->pid ); + if (process) + { + struct thread *thread = get_thread_from_id( req->tid ); + if (thread) + { + continue_debug_event( process, thread, req->status ); + release_object( thread ); + } + release_object( process ); + } + send_reply( current, -1, 0 ); +} + +/* Start debugging an existing process */ +DECL_HANDLER(debug_process) +{ + struct process *process = get_process_from_id( req->pid ); + if (process) + { + debugger_attach( process, current ); + /* FIXME: should notice the debugged process somehow */ + release_object( process ); + } + send_reply( current, -1, 0 ); +} + +/* Send a debug event */ +DECL_HANDLER(send_debug_event) +{ + struct thread *debugger = current->process->debugger; + struct send_debug_event_reply reply; + + if ((req->code <= 0) || (req->code > RIP_EVENT)) + fatal_protocol_error( "send_debug_event: bad event code %d\n", req->code ); + if (len != event_sizes[req->code]) + fatal_protocol_error( "send_debug_event: bad event length %d/%d\n", + len, event_sizes[req->code] ); + assert( !current->debug_event ); + reply.status = 0; + if (debugger) + { + if (queue_debug_event( debugger, current, req->code, data )) + return; /* don't reply now, wait for continue_debug_event */ + } + send_reply( current, -1, 1, &reply, sizeof(reply) ); +} diff --git a/server/object.h b/server/object.h index a3f9d531512..165da2df77f 100644 --- a/server/object.h +++ b/server/object.h @@ -153,6 +153,11 @@ extern void file_set_error(void); extern int create_console( int fd, struct object *obj[2] ); +/* debugger functions */ + +extern int debugger_attach( struct process *process, struct thread *debugger ); +extern void debug_exit_thread( struct thread *thread, int exit_code ); + extern int debug_level; #endif /* __WINE_SERVER_OBJECT_H */ diff --git a/server/process.c b/server/process.c index de97ff4eecf..c6a8295baaf 100644 --- a/server/process.c +++ b/server/process.c @@ -109,12 +109,21 @@ static struct process *create_process( struct new_process_request *req ) return NULL; } init_process( process ); - if (parent->console_in) process->console_in = grab_object( parent->console_in ); - if (parent->console_out) process->console_out = grab_object( parent->console_out ); if (!(process->info = mem_alloc( sizeof(*process->info) ))) goto error; memcpy( process->info, req, sizeof(*req) ); + /* set the process console */ + if (req->create_flags & CREATE_NEW_CONSOLE) + { + if (!alloc_console( process )) goto error; + } + else if (!(req->create_flags & DETACHED_PROCESS)) + { + if (parent->console_in) process->console_in = grab_object( parent->console_in ); + if (parent->console_out) process->console_out = grab_object( parent->console_out ); + } + if (!req->inherit_all && !(req->start_flags & STARTF_USESTDHANDLES)) { process->info->hstdin = duplicate_handle( parent, req->hstdin, process, @@ -125,6 +134,12 @@ static struct process *create_process( struct new_process_request *req ) 0, TRUE, DUPLICATE_SAME_ACCESS ); } + /* attach to the debugger if requested */ + if (req->create_flags & DEBUG_PROCESS) + debugger_attach( process, current ); + else if (parent->debugger && !(req->create_flags & DEBUG_ONLY_THIS_PROCESS)) + debugger_attach( process, parent->debugger ); + process->next = first_process; first_process->prev = process; first_process = process; diff --git a/server/thread.c b/server/thread.c index d4fea46963c..28cdefb346a 100644 --- a/server/thread.c +++ b/server/thread.c @@ -87,6 +87,7 @@ static void init_thread( struct thread *thread, int fd ) thread->mutex = NULL; thread->debug_ctx = NULL; thread->debug_first = NULL; + thread->debug_event = NULL; thread->wait = NULL; thread->apc = NULL; thread->apc_count = 0; @@ -157,6 +158,7 @@ static void destroy_thread( struct object *obj ) struct thread *thread = (struct thread *)obj; assert( obj->ops == &thread_ops ); + assert( !thread->debug_ctx ); /* cannot still be debugging something */ release_object( thread->process ); if (thread->next) thread->next->prev = thread->prev; if (thread->prev) thread->prev->next = thread->next; @@ -522,6 +524,7 @@ void thread_killed( struct thread *thread, int exit_code ) thread->state = TERMINATED; thread->exit_code = exit_code; if (thread->wait) end_wait( thread ); + debug_exit_thread( thread, exit_code ); abandon_mutexes( thread ); remove_process_thread( thread->process, thread ); wake_up( &thread->obj, 0 ); diff --git a/server/thread.h b/server/thread.h index cffe25549ec..4498bfc627a 100644 --- a/server/thread.h +++ b/server/thread.h @@ -20,6 +20,7 @@ struct thread_wait; struct thread_apc; struct mutex; struct debug_ctx; +struct debug_event; enum run_state { STARTING, RUNNING, TERMINATED }; @@ -34,6 +35,7 @@ struct thread struct mutex *mutex; /* list of currently owned mutexes */ struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */ struct process *debug_first; /* head of debugged processes list */ + struct debug_event *debug_event; /* pending debug event for this thread */ struct thread_wait *wait; /* current wait condition if sleeping */ struct thread_apc *apc; /* list of async procedure calls */ int apc_count; /* number of outstanding APCs */ diff --git a/server/trace.c b/server/trace.c index c5ce0348739..25b7ea1a067 100644 --- a/server/trace.c +++ b/server/trace.c @@ -10,6 +10,7 @@ static int dump_new_process_request( struct new_process_request *req, int len ) { fprintf( stderr, " inherit=%d,", req->inherit ); fprintf( stderr, " inherit_all=%d,", req->inherit_all ); + fprintf( stderr, " create_flags=%d,", req->create_flags ); fprintf( stderr, " start_flags=%d,", req->start_flags ); fprintf( stderr, " hstdin=%d,", req->hstdin ); fprintf( stderr, " hstdout=%d,", req->hstdout ); @@ -682,6 +683,46 @@ static int dump_next_process_reply( struct next_process_reply *req, int len ) return (int)sizeof(*req); } +static int dump_wait_debug_event_request( struct wait_debug_event_request *req, int len ) +{ + fprintf( stderr, " timeout=%d", req->timeout ); + return (int)sizeof(*req); +} + +static int dump_wait_debug_event_reply( struct wait_debug_event_reply *req, int len ) +{ + fprintf( stderr, " code=%d,", req->code ); + fprintf( stderr, " pid=%p,", req->pid ); + fprintf( stderr, " tid=%p", req->tid ); + return (int)sizeof(*req); +} + +static int dump_send_debug_event_request( struct send_debug_event_request *req, int len ) +{ + fprintf( stderr, " code=%d", req->code ); + return (int)sizeof(*req); +} + +static int dump_send_debug_event_reply( struct send_debug_event_reply *req, int len ) +{ + fprintf( stderr, " status=%d", req->status ); + return (int)sizeof(*req); +} + +static int dump_continue_debug_event_request( struct continue_debug_event_request *req, int len ) +{ + fprintf( stderr, " pid=%p,", req->pid ); + fprintf( stderr, " tid=%p,", req->tid ); + fprintf( stderr, " status=%d", req->status ); + return (int)sizeof(*req); +} + +static int dump_debug_process_request( struct debug_process_request *req, int len ) +{ + fprintf( stderr, " pid=%p", req->pid ); + return (int)sizeof(*req); +} + struct dumper { int (*dump_req)( void *data, int len ); @@ -806,6 +847,14 @@ static const struct dumper dumpers[REQ_NB_REQUESTS] = (void(*)())dump_create_snapshot_reply }, { (int(*)(void *,int))dump_next_process_request, (void(*)())dump_next_process_reply }, + { (int(*)(void *,int))dump_wait_debug_event_request, + (void(*)())dump_wait_debug_event_reply }, + { (int(*)(void *,int))dump_send_debug_event_request, + (void(*)())dump_send_debug_event_reply }, + { (int(*)(void *,int))dump_continue_debug_event_request, + (void(*)())0 }, + { (int(*)(void *,int))dump_debug_process_request, + (void(*)())0 }, }; static const char * const req_names[REQ_NB_REQUESTS] = @@ -868,6 +917,10 @@ static const char * const req_names[REQ_NB_REQUESTS] = "create_device", "create_snapshot", "next_process", + "wait_debug_event", + "send_debug_event", + "continue_debug_event", + "debug_process", }; void trace_request( enum request req, void *data, int len, int fd ) -- 2.11.4.GIT