Store the list of loaded dlls in the server, and generate debug events
internally.
diff --git a/server/debugger.c b/server/debugger.c
index b62d0d3..7b7b9b4 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -84,72 +84,85 @@
/* 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 )
+static int fill_debug_event( struct debug_event *event, void *arg )
{
+ struct process *debugger = event->debugger->process;
+ struct process *process;
+ struct thread *thread;
+ struct process_dll *dll;
int handle;
/* some events need special handling */
switch(event->data.code)
{
case CREATE_THREAD_DEBUG_EVENT:
- if ((event->data.info.create_thread.handle = alloc_handle( debugger->process, thread,
- /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
- THREAD_ALL_ACCESS, FALSE )) == -1)
+ thread = arg;
+ /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
+ if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1)
return 0;
- event->data.info.create_thread.teb = thread->teb;
- event->data.info.create_thread.start = thread->entry;
+ event->data.info.create_thread.handle = handle;
+ event->data.info.create_thread.teb = thread->teb;
+ event->data.info.create_thread.start = thread->entry;
break;
case CREATE_PROCESS_DEBUG_EVENT:
- if ((handle = alloc_handle( debugger->process, thread->process,
- /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
- PROCESS_ALL_ACCESS, FALSE )) == -1)
+ process = arg;
+ thread = process->thread_list;
+ /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
+ if ((handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, FALSE )) == -1)
return 0;
event->data.info.create_process.process = handle;
- if ((handle = alloc_handle( debugger->process, thread,
- /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
- THREAD_ALL_ACCESS, FALSE )) == -1)
+ /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
+ if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1)
{
- close_handle( debugger->process, event->data.info.create_process.process );
+ close_handle( debugger, event->data.info.create_process.process );
return 0;
}
event->data.info.create_process.thread = handle;
handle = -1;
- if (thread->process->exe_file &&
- ((handle = alloc_handle( debugger->process, thread->process->exe_file,
- /* the doc says write access too, but this doesn't seem a good idea */
- GENERIC_READ, FALSE )) == -1))
+ if (process->exe.file &&
+ /* the doc says write access too, but this doesn't seem a good idea */
+ ((handle = alloc_handle( debugger, process->exe.file, GENERIC_READ, FALSE )) == -1))
{
- close_handle( debugger->process, event->data.info.create_process.process );
- close_handle( debugger->process, event->data.info.create_process.thread );
+ close_handle( debugger, event->data.info.create_process.process );
+ close_handle( debugger, event->data.info.create_process.thread );
return 0;
}
event->data.info.create_process.file = handle;
event->data.info.create_process.teb = thread->teb;
- event->data.info.create_process.base = thread->process->module;
+ event->data.info.create_process.base = process->exe.base;
event->data.info.create_process.start = thread->entry;
- event->data.info.create_process.dbg_offset = 0;
- event->data.info.create_process.dbg_size = 0;
+ event->data.info.create_process.dbg_offset = process->exe.dbg_offset;
+ event->data.info.create_process.dbg_size = process->exe.dbg_size;
event->data.info.create_process.name = 0;
event->data.info.create_process.unicode = 0;
break;
case LOAD_DLL_DEBUG_EVENT:
- if ((handle = event->data.info.load_dll.handle) != -1)
- {
- if ((handle = duplicate_handle( thread->process, handle, debugger->process,
- GENERIC_READ, FALSE, 0 )) == -1)
- return 0;
- event->data.info.load_dll.handle = handle;
- }
+ dll = arg;
+ handle = -1;
+ if (dll->file &&
+ (handle = alloc_handle( debugger, dll->file, GENERIC_READ, FALSE )) == -1)
+ return 0;
+ event->data.info.load_dll.handle = handle;
+ event->data.info.load_dll.base = dll->base;
+ event->data.info.load_dll.dbg_offset = dll->dbg_offset;
+ event->data.info.load_dll.dbg_size = dll->dbg_size;
+ event->data.info.load_dll.name = dll->name;
+ event->data.info.load_dll.unicode = 0;
break;
case EXIT_PROCESS_DEBUG_EVENT:
+ process = arg;
+ event->data.info.exit.exit_code = process->exit_code;
+ break;
case EXIT_THREAD_DEBUG_EVENT:
+ thread = arg;
event->data.info.exit.exit_code = thread->exit_code;
break;
- case EXCEPTION_DEBUG_EVENT:
case UNLOAD_DLL_DEBUG_EVENT:
+ event->data.info.unload_dll.base = arg;
+ break;
+ case EXCEPTION_DEBUG_EVENT:
case OUTPUT_DEBUG_STRING_EVENT:
case RIP_EVENT:
break;
@@ -333,7 +346,6 @@
{
if (event == debug_ctx->to_send) goto error;
if (event->sender == thread) break;
- event = event->next;
}
if (!event) goto error;
@@ -351,7 +363,7 @@
}
/* queue a debug event for a debugger */
-static struct debug_event *queue_debug_event( struct thread *thread, int code,
+static struct debug_event *queue_debug_event( struct thread *thread, int code, void *arg,
debug_event_t *data )
{
struct thread *debugger = thread->process->debugger;
@@ -372,7 +384,7 @@
if (data) memcpy( &event->data, data, sizeof(event->data) );
event->data.code = code;
- if (!fill_debug_event( debugger, thread, event ))
+ if (!fill_debug_event( event, arg ))
{
event->data.code = -1; /* make sure we don't attempt to close handles */
release_object( event );
@@ -385,15 +397,35 @@
}
/* generate a debug event from inside the server and queue it */
-void generate_debug_event( struct thread *thread, int code )
+void generate_debug_event( struct thread *thread, int code, void *arg )
{
if (thread->process->debugger)
{
- struct debug_event *event = queue_debug_event( thread, code, NULL );
+ struct debug_event *event = queue_debug_event( thread, code, arg, NULL );
if (event) release_object( event );
}
}
+/* generate all startup events of a given process */
+void generate_startup_debug_events( struct process *process )
+{
+ struct process_dll *dll;
+ struct thread *thread = process->thread_list;
+
+ /* generate creation events */
+ generate_debug_event( thread, CREATE_PROCESS_DEBUG_EVENT, process );
+ while ((thread = thread->next))
+ generate_debug_event( thread, CREATE_THREAD_DEBUG_EVENT, thread );
+
+ /* generate dll events (in loading order, i.e. reverse list order) */
+ for (dll = &process->exe; dll->next; dll = dll->next);
+ while (dll != &process->exe)
+ {
+ generate_debug_event( process->thread_list, LOAD_DLL_DEBUG_EVENT, dll );
+ dll = dll->prev;
+ }
+}
+
/* return a pointer to the context in case the thread is inside an exception event */
CONTEXT *get_debug_context( struct thread *thread )
{
@@ -487,10 +519,8 @@
if (!process) return;
if (debugger_attach( process, current ))
{
- struct thread *thread = process->thread_list;
- generate_debug_event( thread, CREATE_PROCESS_DEBUG_EVENT );
- while ((thread = thread->next)) generate_debug_event( thread, CREATE_THREAD_DEBUG_EVENT );
- /* FIXME: load dll + breakpoint exception events */
+ generate_startup_debug_events( process );
+ /* FIXME: breakpoint exception event */
}
release_object( process );
}
@@ -507,7 +537,8 @@
return;
}
req->status = 0;
- if (current->process->debugger && ((event = queue_debug_event( current, code, &req->event ))))
+ if (current->process->debugger && ((event = queue_debug_event( current, code,
+ NULL, &req->event ))))
{
/* wait for continue_debug_event */
struct object *obj = &event->obj;