Implemented thread and (partial) module snapshots, based on the work
of Andreas Mohr <amohr@student.ei.uni-stuttgart.de>.
diff --git a/include/server.h b/include/server.h
index 3ccf97e..72b2442 100644
--- a/include/server.h
+++ b/include/server.h
@@ -789,6 +789,7 @@
{
IN int inherit; /* inherit flag */
IN int flags; /* snapshot flags (TH32CS_*) */
+ IN void* pid; /* process id */
OUT int handle; /* handle to the snapshot */
};
@@ -798,9 +799,33 @@
{
IN int handle; /* handle to the snapshot */
IN int reset; /* reset snapshot position? */
- OUT void* pid; /* process id */
- OUT int threads; /* number of threads */
- OUT int priority; /* process priority */
+ OUT int count; /* process usage count */
+ OUT void* pid; /* process id */
+ OUT int threads; /* number of threads */
+ OUT int priority; /* process priority */
+};
+
+
+/* Get the next thread from a snapshot */
+struct next_thread_request
+{
+ IN int handle; /* handle to the snapshot */
+ IN int reset; /* reset snapshot position? */
+ OUT int count; /* thread usage count */
+ OUT void* pid; /* process id */
+ OUT void* tid; /* thread id */
+ OUT int base_pri; /* base priority */
+ OUT int delta_pri; /* delta priority */
+};
+
+
+/* Get the next module from a snapshot */
+struct next_module_request
+{
+ IN int handle; /* handle to the snapshot */
+ IN int reset; /* reset snapshot position? */
+ OUT void* pid; /* process id */
+ OUT void* base; /* module base address */
};
@@ -1184,6 +1209,8 @@
REQ_CREATE_DEVICE,
REQ_CREATE_SNAPSHOT,
REQ_NEXT_PROCESS,
+ REQ_NEXT_THREAD,
+ REQ_NEXT_MODULE,
REQ_WAIT_DEBUG_EVENT,
REQ_EXCEPTION_EVENT,
REQ_OUTPUT_DEBUG_STRING,
@@ -1219,7 +1246,7 @@
REQ_NB_REQUESTS
};
-#define SERVER_PROTOCOL_VERSION 8
+#define SERVER_PROTOCOL_VERSION 9
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */
diff --git a/include/tlhelp32.h b/include/tlhelp32.h
index 05e6fcb..797aa7f 100644
--- a/include/tlhelp32.h
+++ b/include/tlhelp32.h
@@ -1,19 +1,13 @@
#ifndef __WINE_TLHELP32_H
#define __WINE_TLHELP32_H
-#include "windef.h"
-
#ifdef __cplusplus
extern "C" {
#endif
- /*===================================================================
- * Arguments for Toolhelp routines
- */
-
- /*
- * CreateToolhelp32Snapshot
- */
+/*
+ * CreateToolhelp32Snapshot
+ */
#define TH32CS_SNAPHEAPLIST 0x00000001
#define TH32CS_SNAPPROCESS 0x00000002
@@ -22,6 +16,118 @@
#define TH32CS_SNAPALL (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE)
#define TH32CS_INHERIT 0x80000000
+HANDLE WINAPI CreateToolhelp32Snapshot(DWORD,DWORD);
+
+/*
+ * thread entry list as created by CreateToolHelp32Snapshot
+ */
+
+typedef struct tagTHREADENTRY32
+{
+ DWORD dwSize;
+ DWORD cntUsage;
+ DWORD th32ThreadID;
+ DWORD th32OwnerProcessID;
+ LONG tbBasePri;
+ LONG tbDeltaPri;
+ DWORD dwFlags;
+} THREADENTRY32, *PTHREADENTRY32, *LPTHREADENTRY32;
+
+BOOL WINAPI Thread32First(HANDLE,LPTHREADENTRY32);
+BOOL WINAPI Thread32Next(HANDLE,LPTHREADENTRY32);
+
+/*
+ * Process entry list as created by CreateToolHelp32Snapshot
+ */
+
+typedef struct tagPROCESSENTRY32
+{
+ DWORD dwSize;
+ DWORD cntUsage;
+ DWORD th32ProcessID;
+ DWORD th32DefaultHeapID;
+ DWORD th32ModuleID;
+ DWORD cntThreads;
+ DWORD th32ParentProcessID;
+ LONG pcPriClassBase;
+ DWORD dwFlags;
+ char szExeFile[MAX_PATH];
+} PROCESSENTRY32, *PPROCESSENTRY32, *LPPROCESSENTRY32;
+
+typedef struct tagPROCESSENTRY32W
+{
+ DWORD dwSize;
+ DWORD cntUsage;
+ DWORD th32ProcessID;
+ DWORD th32DefaultHeapID;
+ DWORD th32ModuleID;
+ DWORD cntThreads;
+ DWORD th32ParentProcessID;
+ LONG pcPriClassBase;
+ DWORD dwFlags;
+ WCHAR szExeFile[MAX_PATH];
+} PROCESSENTRY32W, *PPROCESSENTRY32W, *LPPROCESSENTRY32W;
+
+BOOL WINAPI Process32First(HANDLE,LPPROCESSENTRY32);
+BOOL WINAPI Process32FirstW(HANDLE,LPPROCESSENTRY32W);
+BOOL WINAPI Process32Next(HANDLE,LPPROCESSENTRY32);
+BOOL WINAPI Process32NextW(HANDLE,LPPROCESSENTRY32W);
+
+#ifdef UNICODE
+#define Process32First Process32FirstW
+#define Process32Next Process32NextW
+#define PROCESSENTRY32 PROCESSENTRY32W
+#define PPROCESSENTRY32 PPROCESSENTRY32W
+#define LPPROCESSENTRY32 LPPROCESSENTRY32W
+#endif
+
+/*
+ * Module entry list as created by CreateToolHelp32Snapshot
+ */
+
+#define MAX_MODULE_NAME32 255
+
+typedef struct tagMODULEENTRY32
+{
+ DWORD dwSize;
+ DWORD th32ModuleID;
+ DWORD th32ProcessID;
+ DWORD GlblcntUsage;
+ DWORD ProccntUsage;
+ BYTE *modBaseAddr;
+ DWORD modBaseSize;
+ DWORD hModule;
+ char szModule[MAX_MODULE_NAME32 + 1];
+ char szExePath[MAX_PATH];
+} MODULEENTRY32, *PMODULEENTRY32, *LPMODULEENTRY32;
+
+typedef struct tagMODULEENTRY32W
+{
+ DWORD dwSize;
+ DWORD th32ModuleID;
+ DWORD th32ProcessID;
+ DWORD GlblcntUsage;
+ DWORD ProccntUsage;
+ BYTE *modBaseAddr;
+ DWORD modBaseSize;
+ DWORD hModule;
+ WCHAR szModule[MAX_MODULE_NAME32 + 1];
+ WCHAR szExePath[MAX_PATH];
+} MODULEENTRY32W, *PMODULEENTRY32W, *LPMODULEENTRY32W;
+
+BOOL WINAPI Module32First(HANDLE,LPMODULEENTRY32);
+BOOL WINAPI Module32FirstW(HANDLE,LPMODULEENTRY32W);
+BOOL WINAPI Module32Next(HANDLE,LPMODULEENTRY32);
+BOOL WINAPI Module32NextW(HANDLE,LPMODULEENTRY32W);
+
+#ifdef UNICODE
+#define Module32First Module32FirstW
+#define Module32Next Module32NextW
+#define MODULEENTRY32 MODULEENTRY32W
+#define PMODULEENTRY32 PMODULEENTRY32W
+#define LPMODULEENTRY32 LPMODULEENTRY32W
+#endif
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/include/toolhelp.h b/include/toolhelp.h
index 1fef7cd..735c4bb 100644
--- a/include/toolhelp.h
+++ b/include/toolhelp.h
@@ -2,7 +2,6 @@
#define __WINE_TOOLHELP_H
#include "windef.h"
-#include "tlhelp32.h"
#define MAX_DATA 11
#define MAX_MODULE_NAME 9
@@ -397,44 +396,4 @@
#include "poppack.h"
-/*
- * Thread entry list as created by CreateToolHelp32Snapshot
- */
-
-typedef struct tagTHREADENTRY {
- DWORD dwSize;
- DWORD cntUsage;
- DWORD th32ThreadID;
- DWORD th32OwnerProcessID;
- DWORD tbBasePri;
- DWORD tbDeltaPri;
- DWORD dwFlags;
- DWORD th32AccessKey;
- DWORD th32CurrentProcessID;
-} THREADENTRY, *PTHREADENTRY, *LPTHREADENTRY;
-
-BOOL WINAPI Thread32First(HANDLE,LPTHREADENTRY);
-BOOL WINAPI Thread32Next(HANDLE,LPTHREADENTRY);
-
-/*
- * Process entry list as created by CreateToolHelp32Snapshot
- */
-
-typedef struct tagPROCESSENTRY {
- DWORD dwSize;
- DWORD cntUsage;
- DWORD th32ProcessID;
- DWORD th32DefaultHeapID;
- DWORD th32ModuleID;
- DWORD cntThreads;
- DWORD th32ParentProcessID;
- LONG pcPriClassBase;
- DWORD dwFlags;
- char szExeFile[MAX_PATH];
-} PROCESSENTRY, *PPROCESSENTRY, *LPPROCESSENTRY;
-
-BOOL WINAPI Process32First(HANDLE,LPPROCESSENTRY);
-BOOL WINAPI Process32Next(HANDLE,LPPROCESSENTRY);
-
-
#endif /* __WINE_TOOLHELP_H */
diff --git a/misc/toolhelp.c b/misc/toolhelp.c
index 36097af..4fb9529 100644
--- a/misc/toolhelp.c
+++ b/misc/toolhelp.c
@@ -19,7 +19,7 @@
#include "server.h"
#include "debugtools.h"
-DEFAULT_DEBUG_CHANNEL(toolhelp)
+DEFAULT_DEBUG_CHANNEL(toolhelp);
/* FIXME: to make this working, we have to callback all these registered
@@ -150,10 +150,9 @@
struct create_snapshot_request *req = get_req_buffer();
TRACE("%lx,%lx\n", flags, process );
- if (flags & (TH32CS_SNAPHEAPLIST|TH32CS_SNAPMODULE|TH32CS_SNAPTHREAD))
- FIXME("flags %lx not implemented\n", flags );
- if (!(flags & TH32CS_SNAPPROCESS))
+ if (!(flags & (TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE)))
{
+ FIXME("flags %lx not implemented\n", flags );
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
return INVALID_HANDLE_VALUE;
}
@@ -161,23 +160,47 @@
/* Now do the snapshot */
req->flags = flags & ~TH32CS_INHERIT;
req->inherit = (flags & TH32CS_INHERIT) != 0;
+ req->pid = (void *)process;
server_call( REQ_CREATE_SNAPSHOT );
return req->handle;
}
/***********************************************************************
+ * TOOLHELP_Thread32Next
+ *
+ * Implementation of Thread32First/Next
+ */
+static BOOL TOOLHELP_Thread32Next( HANDLE handle, LPTHREADENTRY32 lpte, BOOL first )
+{
+ struct next_thread_request *req = get_req_buffer();
+
+ if (lpte->dwSize < sizeof(THREADENTRY32))
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(THREADENTRY32), lpte->dwSize);
+ return FALSE;
+ }
+ req->handle = handle;
+ req->reset = first;
+ if (server_call( REQ_NEXT_THREAD )) return FALSE;
+ lpte->cntUsage = req->count;
+ lpte->th32ThreadID = (DWORD)req->tid;
+ lpte->th32OwnerProcessID = (DWORD)req->pid;
+ lpte->tbBasePri = req->base_pri;
+ lpte->tbDeltaPri = req->delta_pri;
+ lpte->dwFlags = 0; /* SDK: "reserved; do not use" */
+ return TRUE;
+}
+
+/***********************************************************************
* Thread32First (KERNEL32.686)
*
* Return info about the first thread in a toolhelp32 snapshot
*/
-BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY lpte)
+BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
{
- if (!lpte)
- return FALSE;
-
- FIXME("(%d,%p),stub!\n",hSnapshot,lpte);
- return FALSE;
+ return TOOLHELP_Thread32Next(hSnapshot, lpte, TRUE);
}
/***********************************************************************
@@ -185,13 +208,9 @@
*
* Return info about the "next" thread in a toolhelp32 snapshot
*/
-BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY lpte)
+BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
{
- if (!lpte)
- return FALSE;
-
- FIXME("(%d,%p),stub!\n",hSnapshot,lpte);
- return FALSE;
+ return TOOLHELP_Thread32Next(hSnapshot, lpte, FALSE);
}
/***********************************************************************
@@ -199,20 +218,20 @@
*
* Implementation of Process32First/Next
*/
-static BOOL TOOLHELP_Process32Next( HANDLE handle, LPPROCESSENTRY lppe, BOOL first )
+static BOOL TOOLHELP_Process32Next( HANDLE handle, LPPROCESSENTRY32 lppe, BOOL first )
{
struct next_process_request *req = get_req_buffer();
- if (lppe->dwSize < sizeof (PROCESSENTRY))
+ if (lppe->dwSize < sizeof(PROCESSENTRY32))
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
- ERR("Result buffer too small\n");
+ ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(PROCESSENTRY32), lppe->dwSize);
return FALSE;
}
req->handle = handle;
req->reset = first;
if (server_call( REQ_NEXT_PROCESS )) return FALSE;
- lppe->cntUsage = 1;
+ lppe->cntUsage = req->count;
lppe->th32ProcessID = (DWORD)req->pid;
lppe->th32DefaultHeapID = 0; /* FIXME */
lppe->th32ModuleID = 0; /* FIXME */
@@ -230,7 +249,7 @@
*
* Return info about the first process in a toolhelp32 snapshot
*/
-BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY lppe)
+BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
{
return TOOLHELP_Process32Next( hSnapshot, lppe, TRUE );
}
@@ -240,20 +259,50 @@
*
* Return info about the "next" process in a toolhelp32 snapshot
*/
-BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY lppe)
+BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
{
return TOOLHELP_Process32Next( hSnapshot, lppe, FALSE );
}
+
+/***********************************************************************
+ * TOOLHELP_Module32Next
+ *
+ * Implementation of Module32First/Next
+ */
+static BOOL TOOLHELP_Module32Next( HANDLE handle, LPMODULEENTRY32 lpme, BOOL first )
+{
+ struct next_module_request *req = get_req_buffer();
+
+ if (lpme->dwSize < sizeof (MODULEENTRY32))
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32), lpme->dwSize);
+ return FALSE;
+ }
+ req->handle = handle;
+ req->reset = first;
+ if (server_call( REQ_NEXT_MODULE )) return FALSE;
+ lpme->th32ModuleID = 0; /* toolhelp internal id, never used */
+ lpme->th32ProcessID = (DWORD)req->pid;
+ lpme->GlblcntUsage = 0; /* FIXME */
+ lpme->ProccntUsage = 0; /* FIXME */
+ lpme->modBaseAddr = req->base;
+ lpme->modBaseSize = 0; /* FIXME */
+ lpme->hModule = (DWORD)req->base;
+ lpme->szModule[0] = 0; /* FIXME */
+ lpme->szExePath[0] = 0; /* FIXME */
+ return TRUE;
+}
+
/***********************************************************************
* Module32First (KERNEL32.527)
*
* Return info about the "first" module in a toolhelp32 snapshot
*/
-BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY lpme)
+BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
{
- FIXME("(%d,%p),stub!\n",hSnapshot,lpme);
- return FALSE;
+ return TOOLHELP_Module32Next( hSnapshot, lpme, TRUE );
}
/***********************************************************************
@@ -261,10 +310,9 @@
*
* Return info about the "next" module in a toolhelp32 snapshot
*/
-BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY lpme)
+BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
{
- FIXME("(%d,%p),stub!\n",hSnapshot,lpme);
- return FALSE;
+ return TOOLHELP_Module32Next( hSnapshot, lpme, FALSE );
}
/************************************************************************
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",