Implemented thread and (partial) module snapshots, based on the work of Andreas Mohr <amohr@student.ei.uni-stuttgart.de>.
diff --git a/server/process.c b/server/process.c index 3cc87f6..c84672d 100644 --- a/server/process.c +++ b/server/process.c
@@ -563,6 +563,7 @@ if (!process->running_threads) continue; ptr->process = process; ptr->threads = process->running_threads; + ptr->count = process->obj.refcount; ptr->priority = process->priority; grab_object( process ); ptr++; @@ -571,6 +572,25 @@ return snapshot; } +/* take a snapshot of the modules of a process */ +struct module_snapshot *module_snap( struct process *process, int *count ) +{ + struct module_snapshot *snapshot, *ptr; + struct process_dll *dll; + int total = 0; + + for (dll = &process->exe; dll; dll = dll->next) total++; + if (!(snapshot = mem_alloc( sizeof(*snapshot) * total ))) return NULL; + + for (ptr = snapshot, dll = &process->exe; dll; dll = dll->next, ptr++) + { + ptr->base = dll->base; + } + *count = total; + return snapshot; +} + + /* create a new process */ DECL_HANDLER(new_process) {
diff --git a/server/process.h b/server/process.h index 6cdbb6a..6e98a47 100644 --- a/server/process.h +++ b/server/process.h
@@ -55,10 +55,16 @@ { struct process *process; /* process ptr */ struct process *parent; /* process parent */ + int count; /* process refcount */ int threads; /* number of threads */ int priority; /* priority class */ }; +struct module_snapshot +{ + void *base; /* module base addr */ +}; + /* process functions */ extern struct thread *create_process( int fd, struct process *parent, @@ -75,6 +81,7 @@ extern void resume_process( struct process *process ); extern void kill_debugged_processes( struct thread *debugger, int exit_code ); extern struct process_snapshot *process_snap( int *count ); +extern struct module_snapshot *module_snap( struct process *process, int *count ); static inline void *get_process_id( struct process *process ) { return process; }
diff --git a/server/request.h b/server/request.h index 03943d9..c7b970b 100644 --- a/server/request.h +++ b/server/request.h
@@ -138,6 +138,8 @@ DECL_HANDLER(create_device); DECL_HANDLER(create_snapshot); DECL_HANDLER(next_process); +DECL_HANDLER(next_thread); +DECL_HANDLER(next_module); DECL_HANDLER(wait_debug_event); DECL_HANDLER(exception_event); DECL_HANDLER(output_debug_string); @@ -244,6 +246,8 @@ (req_handler)req_create_device, (req_handler)req_create_snapshot, (req_handler)req_next_process, + (req_handler)req_next_thread, + (req_handler)req_next_module, (req_handler)req_wait_debug_event, (req_handler)req_exception_event, (req_handler)req_output_debug_string,
diff --git a/server/snapshot.c b/server/snapshot.c index 2a16ac5..3f806be 100644 --- a/server/snapshot.c +++ b/server/snapshot.c
@@ -3,7 +3,7 @@ * * Copyright (C) 1999 Alexandre Julliard * - * FIXME: only process snapshots implemented for now + * FIXME: heap snapshots not implemented */ #include <assert.h> @@ -22,9 +22,16 @@ struct snapshot { struct object obj; /* object header */ - struct process_snapshot *process; /* processes snapshot */ + struct process *process; /* process of this snapshot (for modules and heaps) */ + struct process_snapshot *processes; /* processes snapshot */ int process_count; /* count of processes */ int process_pos; /* current position in proc snapshot */ + struct thread_snapshot *threads; /* threads snapshot */ + int thread_count; /* count of threads */ + int thread_pos; /* current position in thread snapshot */ + struct module_snapshot *modules; /* modules snapshot */ + int module_count; /* count of modules */ + int module_pos; /* current position in module snapshot */ }; static void snapshot_dump( struct object *obj, int verbose ); @@ -49,18 +56,41 @@ /* create a new snapshot */ -static struct snapshot *create_snapshot( int flags ) +static struct snapshot *create_snapshot( void *pid, int flags ) { + struct process *process = NULL; struct snapshot *snapshot; - if ((snapshot = alloc_object( &snapshot_ops, -1 ))) + /* need a process for modules and heaps */ + if (flags & (TH32CS_SNAPMODULE|TH32CS_SNAPHEAPLIST)) { - if (flags & TH32CS_SNAPPROCESS) - snapshot->process = process_snap( &snapshot->process_count ); - else - snapshot->process_count = 0; - snapshot->process_pos = 0; + if (!pid) process = (struct process *)grab_object( current->process ); + else if (!(process = get_process_from_id( pid ))) return NULL; } + + if (!(snapshot = alloc_object( &snapshot_ops, -1 ))) + { + if (process) release_object( process ); + return NULL; + } + + snapshot->process = process; + + snapshot->process_pos = 0; + snapshot->process_count = 0; + if (flags & TH32CS_SNAPPROCESS) + snapshot->processes = process_snap( &snapshot->process_count ); + + snapshot->thread_pos = 0; + snapshot->thread_count = 0; + if (flags & TH32CS_SNAPTHREAD) + snapshot->threads = thread_snap( &snapshot->thread_count ); + + snapshot->module_pos = 0; + snapshot->module_count = 0; + if (flags & TH32CS_SNAPMODULE) + snapshot->modules = module_snap( process, &snapshot->module_count ); + return snapshot; } @@ -80,19 +110,67 @@ set_error( STATUS_NO_MORE_FILES ); return 0; } - ptr = &snapshot->process[snapshot->process_pos++]; - req->pid = ptr->process; + ptr = &snapshot->processes[snapshot->process_pos++]; + req->count = ptr->count; + req->pid = get_process_id( ptr->process ); req->threads = ptr->threads; req->priority = ptr->priority; return 1; } +/* get the next thread in the snapshot */ +static int snapshot_next_thread( struct snapshot *snapshot, struct next_thread_request *req ) +{ + struct thread_snapshot *ptr; + + if (!snapshot->thread_count) + { + set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ + return 0; + } + if (req->reset) snapshot->thread_pos = 0; + else if (snapshot->thread_pos >= snapshot->thread_count) + { + set_error( STATUS_NO_MORE_FILES ); + return 0; + } + ptr = &snapshot->threads[snapshot->thread_pos++]; + req->count = ptr->count; + req->pid = get_process_id( ptr->thread->process ); + req->tid = get_thread_id( ptr->thread ); + req->base_pri = ptr->priority; + req->delta_pri = 0; /* FIXME */ + return 1; +} + +/* get the next module in the snapshot */ +static int snapshot_next_module( struct snapshot *snapshot, struct next_module_request *req ) +{ + struct module_snapshot *ptr; + + if (!snapshot->module_count) + { + set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ + return 0; + } + if (req->reset) snapshot->module_pos = 0; + else if (snapshot->module_pos >= snapshot->module_count) + { + set_error( STATUS_NO_MORE_FILES ); + return 0; + } + ptr = &snapshot->modules[snapshot->module_pos++]; + req->pid = get_process_id( snapshot->process ); + req->base = ptr->base; + return 1; +} + static void snapshot_dump( struct object *obj, int verbose ) { struct snapshot *snapshot = (struct snapshot *)obj; assert( obj->ops == &snapshot_ops ); - fprintf( stderr, "Snapshot: %d processes\n", - snapshot->process_count ); + fprintf( stderr, "Snapshot: %d procs %d threads %d modules\n", + snapshot->process_count, snapshot->thread_count, snapshot->module_count ); } static void snapshot_destroy( struct object *obj ) @@ -103,9 +181,17 @@ if (snapshot->process_count) { for (i = 0; i < snapshot->process_count; i++) - release_object( snapshot->process[i].process ); - free( snapshot->process ); + release_object( snapshot->processes[i].process ); + free( snapshot->processes ); } + if (snapshot->thread_count) + { + for (i = 0; i < snapshot->thread_count; i++) + release_object( snapshot->threads[i].thread ); + free( snapshot->threads ); + } + if (snapshot->module_count) free( snapshot->modules ); + if (snapshot->process) release_object( snapshot->process ); } /* create a snapshot */ @@ -114,7 +200,7 @@ struct snapshot *snapshot; req->handle = -1; - if ((snapshot = create_snapshot( req->flags ))) + if ((snapshot = create_snapshot( req->pid, req->flags ))) { req->handle = alloc_handle( current->process, snapshot, 0, req->inherit ); release_object( snapshot ); @@ -133,3 +219,29 @@ release_object( snapshot ); } } + +/* get the next thread from a snapshot */ +DECL_HANDLER(next_thread) +{ + struct snapshot *snapshot; + + if ((snapshot = (struct snapshot *)get_handle_obj( current->process, req->handle, + 0, &snapshot_ops ))) + { + snapshot_next_thread( snapshot, req ); + release_object( snapshot ); + } +} + +/* get the next module from a snapshot */ +DECL_HANDLER(next_module) +{ + struct snapshot *snapshot; + + if ((snapshot = (struct snapshot *)get_handle_obj( current->process, req->handle, + 0, &snapshot_ops ))) + { + snapshot_next_module( snapshot, req ); + release_object( snapshot ); + } +}
diff --git a/server/thread.c b/server/thread.c index 3963f60..eeedd2b 100644 --- a/server/thread.c +++ b/server/thread.c
@@ -580,6 +580,30 @@ release_object( thread ); } +/* take a snapshot of currently running threads */ +struct thread_snapshot *thread_snap( int *count ) +{ + struct thread_snapshot *snapshot, *ptr; + struct thread *thread; + int total = 0; + + for (thread = first_thread; thread; thread = thread->next) + if (thread->state != TERMINATED) total++; + if (!total || !(snapshot = mem_alloc( sizeof(*snapshot) * total ))) return NULL; + ptr = snapshot; + for (thread = first_thread; thread; thread = thread->next) + { + if (thread->state == TERMINATED) continue; + ptr->thread = thread; + ptr->count = thread->obj.refcount; + ptr->priority = thread->priority; + grab_object( thread ); + ptr++; + } + *count = total; + return snapshot; +} + /* signal that we are finished booting on the client side */ DECL_HANDLER(boot_done) {
diff --git a/server/thread.h b/server/thread.h index 2913a42..6f836dc 100644 --- a/server/thread.h +++ b/server/thread.h
@@ -58,6 +58,13 @@ enum request last_req; /* last request received (for debugging) */ }; +struct thread_snapshot +{ + struct thread *thread; /* thread ptr */ + int count; /* thread refcount */ + int priority; /* priority class */ +}; + /* callback function for building the thread reply when sleep_on is finished */ typedef void (*sleep_reply)( struct thread *thread, struct object *obj, int signaled ); @@ -79,6 +86,7 @@ extern void wake_up( struct object *obj, int max ); extern int sleep_on( int count, struct object *objects[], int flags, int timeout, sleep_reply func ); +extern struct thread_snapshot *thread_snap( int *count ); /* ptrace functions */
diff --git a/server/trace.c b/server/trace.c index aeba409..66b48bd 100644 --- a/server/trace.c +++ b/server/trace.c
@@ -929,7 +929,8 @@ static void dump_create_snapshot_request( const struct create_snapshot_request *req ) { fprintf( stderr, " inherit=%d,", req->inherit ); - fprintf( stderr, " flags=%d", req->flags ); + fprintf( stderr, " flags=%d,", req->flags ); + fprintf( stderr, " pid=%p", req->pid ); } static void dump_create_snapshot_reply( const struct create_snapshot_request *req ) @@ -945,11 +946,39 @@ static void dump_next_process_reply( const struct next_process_request *req ) { + fprintf( stderr, " count=%d,", req->count ); fprintf( stderr, " pid=%p,", req->pid ); fprintf( stderr, " threads=%d,", req->threads ); fprintf( stderr, " priority=%d", req->priority ); } +static void dump_next_thread_request( const struct next_thread_request *req ) +{ + fprintf( stderr, " handle=%d,", req->handle ); + fprintf( stderr, " reset=%d", req->reset ); +} + +static void dump_next_thread_reply( const struct next_thread_request *req ) +{ + fprintf( stderr, " count=%d,", req->count ); + fprintf( stderr, " pid=%p,", req->pid ); + fprintf( stderr, " tid=%p,", req->tid ); + fprintf( stderr, " base_pri=%d,", req->base_pri ); + fprintf( stderr, " delta_pri=%d", req->delta_pri ); +} + +static void dump_next_module_request( const struct next_module_request *req ) +{ + fprintf( stderr, " handle=%d,", req->handle ); + fprintf( stderr, " reset=%d", req->reset ); +} + +static void dump_next_module_reply( const struct next_module_request *req ) +{ + fprintf( stderr, " pid=%p,", req->pid ); + fprintf( stderr, " base=%p", req->base ); +} + static void dump_wait_debug_event_request( const struct wait_debug_event_request *req ) { fprintf( stderr, " timeout=%d", req->timeout ); @@ -1364,6 +1393,8 @@ (dump_func)dump_create_device_request, (dump_func)dump_create_snapshot_request, (dump_func)dump_next_process_request, + (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_output_debug_string_request, @@ -1467,6 +1498,8 @@ (dump_func)dump_create_device_reply, (dump_func)dump_create_snapshot_reply, (dump_func)dump_next_process_reply, + (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)0, @@ -1570,6 +1603,8 @@ "create_device", "create_snapshot", "next_process", + "next_thread", + "next_module", "wait_debug_event", "exception_event", "output_debug_string",