Added debug events support.

diff --git a/server/debugger.c b/server/debugger.c
new file mode 100644
index 0000000..3a85925
--- /dev/null
+++ b/server/debugger.c
@@ -0,0 +1,438 @@
+/*
+ * Server-side debugger functions
+ *
+ * Copyright (C) 1999 Alexandre Julliard
+ */
+
+#include <assert.h>
+#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) );
+}