Implemented thread and (partial) module snapshots, based on the work
of Andreas Mohr <amohr@student.ei.uni-stuttgart.de>.
This commit is contained in:
parent
c970904c2c
commit
07d8446918
|
@ -789,6 +789,7 @@ struct create_snapshot_request
|
|||
{
|
||||
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 @@ struct next_process_request
|
|||
{
|
||||
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 @@ enum request
|
|||
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 @@ enum request
|
|||
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 */
|
||||
|
|
|
@ -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 @@ extern "C" {
|
|||
#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
|
||||
|
|
|
@ -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 @@ typedef struct {
|
|||
|
||||
#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 */
|
||||
|
|
104
misc/toolhelp.c
104
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 @@ HANDLE WINAPI CreateToolhelp32Snapshot( DWORD flags, DWORD process )
|
|||
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 @@ HANDLE WINAPI CreateToolhelp32Snapshot( DWORD flags, DWORD process )
|
|||
/* 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 @@ BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY lpte)
|
|||
*
|
||||
* 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 @@ BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY lpte)
|
|||
*
|
||||
* 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 @@ static BOOL TOOLHELP_Process32Next( HANDLE handle, LPPROCESSENTRY lppe, BOOL fir
|
|||
*
|
||||
* 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 @@ BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY lppe)
|
|||
*
|
||||
* 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 @@ BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY lpme)
|
|||
*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
|
|
|
@ -563,6 +563,7 @@ struct process_snapshot *process_snap( int *count )
|
|||
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 @@ struct process_snapshot *process_snap( int *count )
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -55,10 +55,16 @@ struct process_snapshot
|
|||
{
|
||||
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 suspend_process( struct process *process );
|
|||
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; }
|
||||
|
||||
|
|
|
@ -138,6 +138,8 @@ DECL_HANDLER(get_mapping_info);
|
|||
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 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(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,
|
||||
|
|
|
@ -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 @@ static const struct object_ops snapshot_ops =
|
|||
|
||||
|
||||
/* 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 @@ static int snapshot_next_process( struct snapshot *snapshot, struct next_process
|
|||
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 @@ static void snapshot_destroy( struct object *obj )
|
|||
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 @@ DECL_HANDLER(create_snapshot)
|
|||
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 @@ DECL_HANDLER(next_process)
|
|||
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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -580,6 +580,30 @@ void kill_thread( struct thread *thread, int violent_death )
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -58,6 +58,13 @@ struct thread
|
|||
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 kill_thread( struct thread *thread, int violent_death );
|
|||
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 */
|
||||
|
||||
|
|
|
@ -929,7 +929,8 @@ static void dump_create_device_reply( const struct create_device_request *req )
|
|||
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_request( const struct next_process_request *req )
|
|||
|
||||
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 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(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 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(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 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"create_device",
|
||||
"create_snapshot",
|
||||
"next_process",
|
||||
"next_thread",
|
||||
"next_module",
|
||||
"wait_debug_event",
|
||||
"exception_event",
|
||||
"output_debug_string",
|
||||
|
|
Loading…
Reference in New Issue