ntdll: a simple implementation of cross-process NtAllocateVirtualMemory

tkho at ucla.edu tkho at ucla.edu
Fri Jun 2 00:53:57 CDT 2006


Hello,

I ran across the need to do memory allocations across processes and came upon
Alexander Yaworsky's patch at
http://www.winehq.org/pipermail/wine-devel/2004-September/029953.html and took
a different approach. Instead of waiting for the target process to check a fd,
I changed the implementation to use ptrace to interrupt the target process and
execute code in kernel32 that does an mmap/munmap.

This is a simple implementation that does not do a full-on call to
Nt(Allocate|Free)VirtualMemory inside the target process, mainly because the
locks taken in the allocation management code would cause deadlocks.

I've done informal testing to make sure the code doesn't crash Wine by running
applications alongside this memory-churner:
http://www.seas.ucla.edu/~kho/wine/alloc_test/alloc_test.exe
http://www.seas.ucla.edu/~kho/wine/alloc_test/alloc_test.cpp

One thought that has recently crossed my mind: Building off his framework and
putting much of the code in the server may not have been a great idea, since
the only real need for the server is to get the unix pid of the thread.

Is this a step in the right direction? Comments appreciated!

Thomas Kho

---
Index: dlls/kernel/kernel32.spec
===================================================================
RCS file: /home/wine/wine/dlls/kernel/kernel32.spec,v
retrieving revision 1.174
diff -u -r1.174 kernel32.spec
--- dlls/kernel/kernel32.spec	27 May 2006 11:36:56 -0000	1.174
+++ dlls/kernel/kernel32.spec	2 Jun 2006 05:43:15 -0000
@@ -1239,3 +1239,8 @@
 
 # Init code
 @ cdecl __wine_kernel_init()
+
+# Remote memory allocation
+# kernel32 is mapped to the same place in every process
+@ cdecl wine_remote_NtAllocateVirtualMemory(ptr long long)
+@ cdecl wine_remote_NtFreeVirtualMemory(ptr long)
Index: dlls/kernel/virtual.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/virtual.c,v
retrieving revision 1.18
diff -u -r1.18 virtual.c
--- dlls/kernel/virtual.c	23 May 2006 12:48:03 -0000	1.18
+++ dlls/kernel/virtual.c	2 Jun 2006 05:43:15 -0000
@@ -42,6 +42,7 @@
 #include "wine/exception.h"
 #include "excpt.h"
 #include "wine/debug.h"
+#include "wine/library.h"
 
 #include "kernel_private.h"
 
@@ -778,3 +779,77 @@
     __ENDTRY
     return FALSE;
 }
+
+/***********************************************************************
+ *             wine_remote_NtAllocateVirtualMemory   (KERNEL32.@)
+ *
+ * Reentrant function that allocates memory
+ *
+ * PARAMS
+ *  base [I] Desired base address
+ *  size [I] Number of bytes to allocate
+ *  prot [I] Memory protection flags
+ *
+ * RETURNS
+ *	Success: %eax contains base address of allocated region of pages.
+ *	Failure: %eax is NULL.
+ */
+void wine_remote_NtAllocateVirtualMemory( LPVOID base, DWORD size, DWORD prot )
+{
+    char *mem;
+    size += sizeof(int *);
+    mem = wine_anon_mmap(base, size, prot, 0);
+    /*printf("mmap base=0x%08x size=%d prot=%d, allocated at 0x%x\n",
+           base, size, prot, mem);*/
+    *(int *) mem = size;
+
+    mem += sizeof(int);
+    /* return base address of allocated memory in eax */
+    asm("movl %0, %%eax"
+        :
+        :"r"(mem)
+        :"%eax");
+    asm("int3"); /* execution doesn't continue past here */
+    return;
+}
+
+/***********************************************************************
+ *             wine_remote_NtFreeVirtualMemory   (KERNEL32.@)
+ *
+ * Reentrant function that frees mmap'd memory
+ *
+ * PARAMS
+ *  base [I] Desired base address
+ *  size [I] Number of bytes to free
+ *
+ * RETURNS
+ *	Success: %eax contains size of unmapped region
+ *	Failure: %eax is 0.
+ */
+void wine_remote_NtFreeVirtualMemory( LPVOID base, DWORD size )
+{
+    int result;
+    if (size == 0)
+    {
+        base = (char *) base - sizeof(int *);
+        size = *(int *) base;
+        result = munmap(base, size);
+    }
+    else /* FIXME unsafe for invalid base */
+        result = 1;
+
+    /*printf("munmap base=0x%08x size=%d, result: %d (%s)\n",
+           base, size, result, result == 0 ? "success" : "failure");*/
+
+    if (result == 0) /* munmap success */
+        result = size;
+    else
+        result = 0;
+    /* return munmap return value in eax */
+    asm("movl %0, %%eax"
+        :
+        :"r"(result)
+        :"%eax");
+    asm("int3"); /* execution doesn't continue past here */
+    return;
+}
Index: dlls/ntdll/virtual.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/virtual.c,v
retrieving revision 1.90
diff -u -r1.90 virtual.c
--- dlls/ntdll/virtual.c	23 May 2006 12:48:22 -0000	1.90
+++ dlls/ntdll/virtual.c	2 Jun 2006 05:43:16 -0000
@@ -144,6 +144,36 @@
 
 
 /***********************************************************************
+ *           remote_op
+ *
+ */
+NTSTATUS remote_op( HANDLE process, int opcode,
+                    void* params, int params_size,
+                    void* result, int* result_size )
+{
+    NTSTATUS status, remote_status = 0;
+
+    SERVER_START_REQ( remote_operation )
+    {
+        req->handle = process;
+        req->code   = opcode;
+        if (params) wine_server_add_data( req, params, params_size );
+        wine_server_set_reply( req, result, *result_size );
+        if (!(status = wine_server_call( req )))
+        {
+            remote_status = reply->status;
+            if (result)
+                *result_size = wine_server_reply_size( reply );
+            TRACE("result_size=%d\n", *result_size);
+        }
+    }
+    SERVER_END_REQ;
+
+    return status ? status : remote_status;
+}
+
+
+/***********************************************************************
  *           VIRTUAL_GetProtStr
  */
 static const char *VIRTUAL_GetProtStr( BYTE prot )
@@ -1250,8 +1280,8 @@
  *             NtAllocateVirtualMemory   (NTDLL.@)
  *             ZwAllocateVirtualMemory   (NTDLL.@)
  */
-NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_bits,
-                                         SIZE_T *size_ptr, ULONG type, ULONG protect )
+NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret,
+        ULONG zero_bits, SIZE_T *size_ptr, ULONG type, ULONG protect )
 {
     void *base;
     BYTE vprot;
@@ -1265,8 +1295,48 @@
 
     if (!is_current_process( process ))
     {
-        ERR("Unsupported on other process\n");
-        return STATUS_ACCESS_DENIED;
+        struct remote_op_params_vm_alloc alloc_params;
+        struct remote_op_result_vm_alloc alloc_result;
+        int result_size = sizeof(alloc_result);
+        typedef void (*allocator_type)(LPVOID base, DWORD size, DWORD prot);
+        static allocator_type allocator = NULL;
+
+        if (!allocator)
+        {
+            HMODULE hkernel32;
+            UNICODE_STRING module;
+            ANSI_STRING function;
+            WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2',
+                '.','d','l','l',0};
+            RtlInitUnicodeString(&module, kernel32W);
+            RtlInitAnsiString(&function, "wine_remote_NtAllocateVirtualMemory");
+            if (LdrGetDllHandle(0, 0, &module, &hkernel32) == STATUS_SUCCESS)
+                LdrGetProcedureAddress(hkernel32, &function, 0,
+                        (void**)&allocator);
+            else
+                return STATUS_DLL_NOT_FOUND;
+            printf("using allocator in kernel32 at 0x%08x\n",
+                    (unsigned) allocator);
+        } 
+
+        alloc_params.addr = *ret;
+        alloc_params.zerobits = zero_bits;
+        alloc_params.size = size;
+        alloc_params.type = type;
+        alloc_params.protect = VIRTUAL_GetProt( protect );
+        alloc_params.allocator = allocator;
+        status = remote_op( process, REMOTE_OP_VM_ALLOC,
+                            &alloc_params, sizeof(alloc_params),
+                            &alloc_result, &result_size );
+        if (!status)
+        {
+            *ret = alloc_result.addr;
+            *size_ptr = alloc_result.size;
+        }
+        printf("NtAllocateVirtualMemory status=0x%08x ptr=0x%08x size=%d\n",
+                (unsigned) status, (unsigned) alloc_result.addr,
+                alloc_result.size);
+        return status;
     }
 
     /* Round parameters to a page boundary */
@@ -1372,8 +1442,42 @@
 
     if (!is_current_process( process ))
     {
-        ERR("Unsupported on other process\n");
-        return STATUS_ACCESS_DENIED;
+        struct remote_op_params_vm_free free_params;
+        struct remote_op_result_vm_free free_result;
+        int result_size = sizeof(free_result);
+        typedef void (*deallocator_type)(LPVOID base, DWORD size);
+        static deallocator_type deallocator = NULL;
+
+        if (!deallocator) {
+            HMODULE hkernel32;
+            UNICODE_STRING module;
+            ANSI_STRING function;
+            WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2',
+                '.','d','l','l',0};
+            RtlInitUnicodeString(&module, kernel32W);
+            RtlInitAnsiString(&function, "wine_remote_NtFreeVirtualMemory");
+
+            if (LdrGetDllHandle(0, 0, &module, &hkernel32) == STATUS_SUCCESS)
+                LdrGetProcedureAddress(hkernel32, &function, 0, 
+                        (void**)&deallocator);
+            else
+                return STATUS_DLL_NOT_FOUND;
+            printf("using deallocator in kernel32 at 0x%08x\n",
+                    (unsigned) deallocator);
+        }
+
+        free_params.addr    = *addr_ptr;
+        free_params.size    = size;
+        free_params.type    = type;
+        free_params.deallocator = deallocator;
+        status = remote_op( process, REMOTE_OP_VM_FREE,
+                            &free_params, sizeof(free_params),
+                            &free_result, &result_size );
+        if (!status)
+            *size_ptr = free_result.size;
+        printf("NtFreeVirtualMemory status=0x%08x size=%d\n",
+                (unsigned) status, (unsigned) free_result.size);
+        return status;
     }
 
     /* Fix the parameters */
Index: include/winternl.h
===================================================================
RCS file: /home/wine/wine/include/winternl.h,v
retrieving revision 1.181
diff -u -r1.181 winternl.h
--- include/winternl.h	27 May 2006 11:37:02 -0000	1.181
+++ include/winternl.h	2 Jun 2006 05:43:17 -0000
@@ -2242,7 +2242,8 @@
 extern NTSTATUS wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
                                            UINT disposition, BOOLEAN check_case );
 extern NTSTATUS wine_unix_to_nt_file_name( const ANSI_STRING *name, UNICODE_STRING *nt );
-
+extern void wine_remote_NtAllocateVirtualMemory( LPVOID base, DWORD size, DWORD prot );
+extern void wine_remote_NtFreeVirtualMemory( LPVOID base, DWORD size );
 
 /***********************************************************************
  * Inline functions
Index: include/wine/server_protocol.h
===================================================================
RCS file: /home/wine/wine/include/wine/server_protocol.h,v
retrieving revision 1.198
diff -u -r1.198 server_protocol.h
--- include/wine/server_protocol.h	27 May 2006 11:37:01 -0000	1.198
+++ include/wine/server_protocol.h	2 Jun 2006 05:43:18 -0000
@@ -3727,6 +3727,132 @@
 };
 
 
+
+struct remote_operation_request
+{
+    struct request_header __header;
+    obj_handle_t handle;
+    int          code;
+    /* VARARG(data,bytes); */
+};
+struct remote_operation_reply
+{
+    struct reply_header __header;
+    unsigned int status;
+    /* VARARG(data,bytes); */
+};
+enum remote_op_code
+{
+    REMOTE_OP_NEW_THREAD,
+    REMOTE_OP_VM_ALLOC,
+    REMOTE_OP_VM_FREE,
+    REMOTE_OP_VM_PROTECT,
+    REMOTE_OP_VM_QUERY,
+    REMOTE_OP_VM_MAP,
+    REMOTE_OP_VM_UNMAP,
+    REMOTE_OP_VM_FLUSH
+};
+
+struct remote_op_params_new_thread
+{
+    int           suspend;
+    void         *stack_addr;
+    unsigned int  stack_reserve;
+    unsigned int  stack_commit;
+    void         *start;
+    void         *param;
+};
+struct remote_op_result_new_thread
+{
+    obj_handle_t  handle;
+    thread_id_t   tid;
+};
+
+struct remote_op_params_vm_alloc
+{
+    void          *addr;
+    unsigned long  zerobits;
+    unsigned long  size;
+    unsigned long  type;
+    unsigned long  protect;
+    void          *allocator;
+};
+struct remote_op_result_vm_alloc
+{
+    void          *addr;
+    unsigned long  size;
+};
+
+struct remote_op_params_vm_free
+{
+    void          *addr;
+    unsigned long  size;
+    unsigned long  type;
+    void          *deallocator;
+};
+struct remote_op_result_vm_free
+{
+    unsigned long  size;
+};
+
+struct remote_op_params_vm_protect
+{
+    void          *addr;
+    unsigned long  size;
+    unsigned long  new_prot;
+};
+struct remote_op_result_vm_protect
+{
+    void          *base;
+    unsigned long  size;
+    unsigned long  old_prot;
+};
+
+struct remote_op_params_vm_query
+{
+    void  *addr;
+    int    info_class;
+};
+
+struct remote_op_params_vm_map
+{
+    void          *addr;
+    unsigned long  zero_bits;
+    unsigned long  commit_size;
+    unsigned long  offset_low;
+    long           offset_high;
+    unsigned long  size;
+    int            inherit;
+    unsigned long  alloc_type;
+    unsigned long  protect;
+};
+struct remote_op_result_vm_map
+{
+    void          *base;
+    unsigned long  size;
+};
+
+struct remote_op_params_vm_flush
+{
+    void          *addr;
+    unsigned long  size;
+    unsigned long  unknown;
+};
+struct remote_op_result_vm_flush
+{
+    void          *base;
+    unsigned long  size;
+};
+
+
+struct remote_op_request
+{
+    enum remote_op_code op_code;
+    thread_id_t         originator;
+    int                 params_size;
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -3942,6 +4068,7 @@
     REQ_create_symlink,
     REQ_open_symlink,
     REQ_query_symlink,
+    REQ_remote_operation,
     REQ_NB_REQUESTS
 };
 
@@ -4162,6 +4289,7 @@
     struct create_symlink_request create_symlink_request;
     struct open_symlink_request open_symlink_request;
     struct query_symlink_request query_symlink_request;
+    struct remote_operation_request remote_operation_request;
 };
 union generic_reply
 {
@@ -4380,8 +4508,9 @@
     struct create_symlink_reply create_symlink_reply;
     struct open_symlink_reply open_symlink_reply;
     struct query_symlink_reply query_symlink_reply;
+    struct remote_operation_reply remote_operation_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 234
+#define SERVER_PROTOCOL_VERSION 238
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
Index: server/process.c
===================================================================
RCS file: /home/wine/wine/server/process.c,v
retrieving revision 1.167
diff -u -r1.167 process.c
--- server/process.c	23 May 2006 12:49:34 -0000	1.167
+++ server/process.c	2 Jun 2006 05:43:18 -0000
@@ -22,12 +22,15 @@
 #include "wine/port.h"
 
 #include <assert.h>
+#include <errno.h>
 #include <limits.h>
+#include <linux/user.h>
 #include <signal.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/ptrace.h>
 #include <sys/time.h>
 #ifdef HAVE_SYS_SOCKET_H
 # include <sys/socket.h>
@@ -36,6 +39,7 @@
 #ifdef HAVE_POLL_H
 #include <poll.h>
 #endif
+#include <sys/wait.h>
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -1081,3 +1085,209 @@
         release_object( process );
     }
 }
+
+/* Accept parameters for remote operation and start it */
+DECL_HANDLER(remote_operation)
+{
+    int access;
+    struct process *process;
+    struct thread *thread;
+
+    /* define required access rights */
+    switch( req->code )
+    {
+        case REMOTE_OP_NEW_THREAD:
+            access = PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION
+                     | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE;
+            break;
+        case REMOTE_OP_VM_ALLOC:   access = PROCESS_VM_OPERATION; break;
+        case REMOTE_OP_VM_FREE:    access = PROCESS_VM_OPERATION; break;
+        case REMOTE_OP_VM_PROTECT: access = PROCESS_VM_OPERATION; break;
+        case REMOTE_OP_VM_QUERY:   access = PROCESS_QUERY_INFORMATION; break;
+        case REMOTE_OP_VM_MAP:     access = PROCESS_VM_OPERATION; break;
+        case REMOTE_OP_VM_UNMAP:   access = PROCESS_VM_OPERATION; break;
+        case REMOTE_OP_VM_FLUSH:   access = PROCESS_VM_OPERATION; break; /* FIXME: is access right? */
+        default:
+            set_error( STATUS_INVALID_PARAMETER );
+            return;
+    }
+
+    switch( req->code )
+    {
+        case REMOTE_OP_NEW_THREAD:
+            break;
+        case REMOTE_OP_VM_ALLOC:
+        {
+#if defined(linux) && defined(__i386__)
+            int pid;
+            struct user_regs_struct oldregs, regs;
+            struct remote_op_params_vm_alloc *params;
+            struct remote_op_result_vm_alloc result;
+
+            params = (struct remote_op_params_vm_alloc *) get_req_data();
+
+            /* get process object */
+            if (!(process = get_process_from_handle( req->handle, access )))
+                return;
+
+            thread = get_process_first_thread(process);
+            pid = thread->unix_pid;
+            release_object(process);
+
+            /*printf("attaching to process with pid %d\n", pid);*/
+            if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1)
+                goto errorbeforeattach;
+
+            wait(NULL);
+            if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1)
+                goto error;
+
+            memcpy(&oldregs, &regs, sizeof(struct user_regs_struct));
+
+            regs.eip = (int) params->allocator;
+
+            /* cdecl */
+            if (ptrace(PTRACE_POKEDATA, pid, regs.esp-4, params->protect) == -1)
+                goto error;
+            if (ptrace(PTRACE_POKEDATA, pid, regs.esp-8, params->size) == -1)
+                goto error;
+            if (ptrace(PTRACE_POKEDATA, pid, regs.esp-12, params->addr) == -1)
+                goto error;
+            regs.esp -= 16;
+
+            /* prevent the kernel from restarting the system call.
+             * see i386_linux_write_pc() in gdb/i386-linux-tdep.c of gdb */
+            regs.orig_eax = -1;
+
+            if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) == -1)
+                goto error;
+            if (ptrace(PTRACE_CONT, pid, NULL, NULL) == -1)
+                goto error;
+
+            wait(NULL);
+            if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1)
+                goto error;
+
+            /* eax has pointer to allocated memory */
+            /*printf("mem allocated in target process at 0x%08x\n",
+                   (unsigned) regs.eax);*/
+            if (ptrace(PTRACE_SETREGS, pid, NULL, &oldregs) == -1)
+                goto error;
+            if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1)
+                goto error;
+
+            reply->status = regs.eax ? STATUS_SUCCESS
+                    : STATUS_INVALID_PARAMETER;
+            result.addr = (void *) regs.eax;
+            result.size = params->size;
+
+            assert(sizeof(result) <= get_reply_max_size());
+            set_reply_data(&result, sizeof(result));
+
+            break;
+
+error:
+            printf("error!\n");
+            ptrace(PTRACE_DETACH, pid, NULL, NULL);
+            set_error( STATUS_INVALID_PARAMETER );
+            break;
+
+errorbeforeattach:
+            printf("error before attach!\n");
+            set_error( STATUS_INVALID_PARAMETER );
+            break;
+#else
+            set_error( STATUS_NOT_IMPLEMENTED );
+#endif
+        }
+        case REMOTE_OP_VM_FREE:
+        {
+#if defined(linux) && defined(__i386__)
+            int pid;
+            struct user_regs_struct oldregs, regs;
+            struct remote_op_params_vm_free *params;
+            struct remote_op_result_vm_free result;
+
+            params = (struct remote_op_params_vm_free *) get_req_data();
+
+            /* get process object */
+            if (!(process = get_process_from_handle( req->handle, access )))
+                return;
+
+            thread = get_process_first_thread(process);
+            pid = thread->unix_pid;
+            release_object(process);
+
+            /*printf("attaching to process with pid %d\n", pid);*/
+            if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1)
+                goto freeerrorbeforeattach;
+
+            wait(NULL);
+            if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1)
+                goto freeerror;
+            memcpy(&oldregs, &regs, sizeof(struct user_regs_struct));
+
+            regs.eip = (int) params->deallocator;
+
+            /* cdecl */
+            if (ptrace(PTRACE_POKEDATA, pid, regs.esp-4, params->size) == -1)
+                goto freeerror;
+            if (ptrace(PTRACE_POKEDATA, pid, regs.esp-8, params->addr) == -1)
+                goto freeerror;
+            regs.esp -= 12;
+
+            /* prevent the kernel from restarting the system call.
+             * see i386_linux_write_pc() in gdb/i386-linux-tdep.c of gdb */
+            regs.orig_eax = -1;
+
+            if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) == -1)
+                goto freeerror;
+            if (ptrace(PTRACE_CONT, pid, NULL, NULL) == -1)
+                goto freeerror;
+
+            wait(NULL);
+            if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1)
+                goto freeerror;
+
+            /* eax has return value */
+            /*printf("munmap'd in target process, result=0x%08x\n",
+                   (unsigned) regs.eax);*/
+            if (ptrace(PTRACE_SETREGS, pid, NULL, &oldregs) == -1)
+                goto freeerror;
+            if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1)
+                goto freeerror;
+
+            reply->status = regs.eax ? STATUS_SUCCESS
+                    : STATUS_INVALID_PARAMETER;
+            result.size = regs.eax;
+
+            assert(sizeof(result) <= get_reply_max_size());
+            set_reply_data(&result, sizeof(result));
+
+            break;
+
+freeerror:
+            printf("error!\n");
+            ptrace(PTRACE_DETACH, pid, NULL, NULL);
+            set_error( STATUS_INVALID_PARAMETER );
+            break;
+
+freeerrorbeforeattach:
+            printf("error before attach!\n");
+            set_error( STATUS_INVALID_PARAMETER );
+            break;
+#else
+            set_error( STATUS_NOT_IMPLEMENTED );
+#endif
+        }
+        case REMOTE_OP_VM_PROTECT:
+        case REMOTE_OP_VM_QUERY:
+        case REMOTE_OP_VM_MAP:
+        case REMOTE_OP_VM_UNMAP:
+        case REMOTE_OP_VM_FLUSH:
+            break;
+        default:
+            set_error( STATUS_INVALID_PARAMETER );
+            return;
+    }
+}
Index: server/protocol.def
===================================================================
RCS file: /home/wine/wine/server/protocol.def,v
retrieving revision 1.198
diff -u -r1.198 protocol.def
--- server/protocol.def	27 May 2006 11:37:01 -0000	1.198
+++ server/protocol.def	2 Jun 2006 05:43:18 -0000
@@ -2615,3 +2615,124 @@
 @REPLY
     VARARG(target_name,unicode_str); /* target name */
 @END
+
+
+/* Accept parameters for remote operation and start it */
+ at REQ(remote_operation)
+    obj_handle_t handle;       /* process handle */
+    int          code;         /* operation code (see below) */
+    VARARG(data,bytes);        /* operation parameters (see below) */
+ at REPLY
+    unsigned int status;       /* operation status */
+    VARARG(data,bytes);        /* operation result data (see below) */
+ at END
+enum remote_op_code
+{
+    REMOTE_OP_NEW_THREAD,
+    REMOTE_OP_VM_ALLOC,
+    REMOTE_OP_VM_FREE,
+    REMOTE_OP_VM_PROTECT,
+    REMOTE_OP_VM_QUERY,
+    REMOTE_OP_VM_MAP,
+    REMOTE_OP_VM_UNMAP,
+    REMOTE_OP_VM_FLUSH
+};
+
+struct remote_op_params_new_thread
+{
+    int           suspend;
+    void         *stack_addr;
+    unsigned int  stack_reserve;
+    unsigned int  stack_commit;
+    void         *start;
+    void         *param;
+};
+struct remote_op_result_new_thread
+{
+    obj_handle_t  handle;
+    thread_id_t   tid;
+};
+
+struct remote_op_params_vm_alloc
+{
+    void          *addr;
+    unsigned long  zerobits;
+    unsigned long  size;
+    unsigned long  type;
+    unsigned long  protect;
+    void          *allocator;
+};
+struct remote_op_result_vm_alloc
+{
+    void          *addr;
+    unsigned long  size;
+};
+
+struct remote_op_params_vm_free
+{
+    void          *addr;
+    unsigned long  size;
+    unsigned long  type;
+    void          *deallocator;
+};
+struct remote_op_result_vm_free
+{
+    unsigned long  size;
+};
+
+struct remote_op_params_vm_protect
+{
+    void          *addr;
+    unsigned long  size;
+    unsigned long  new_prot;
+};
+struct remote_op_result_vm_protect
+{
+    void          *base;
+    unsigned long  size;
+    unsigned long  old_prot;
+};
+
+struct remote_op_params_vm_query
+{
+    void  *addr;
+    int    info_class;
+};
+
+struct remote_op_params_vm_map
+{
+    void          *addr;
+    unsigned long  zero_bits;
+    unsigned long  commit_size;
+    unsigned long  offset_low;
+    long           offset_high;
+    unsigned long  size;
+    int            inherit;
+    unsigned long  alloc_type;
+    unsigned long  protect;
+};
+struct remote_op_result_vm_map
+{
+    void          *base;
+    unsigned long  size;
+};
+
+struct remote_op_params_vm_flush
+{
+    void          *addr;
+    unsigned long  size;
+    unsigned long  unknown;
+};
+struct remote_op_result_vm_flush
+{
+    void          *base;
+    unsigned long  size;
+};
+
+/* structure for marshalling remote operation requests */
+struct remote_op_request
+{
+    enum remote_op_code op_code;
+    thread_id_t         originator;
+    int                 params_size;
+};
Index: server/request.h
===================================================================
RCS file: /home/wine/wine/server/request.h,v
retrieving revision 1.132
diff -u -r1.132 request.h
--- server/request.h	23 May 2006 12:49:34 -0000	1.132
+++ server/request.h	2 Jun 2006 05:43:18 -0000
@@ -323,6 +323,7 @@
 DECL_HANDLER(create_symlink);
 DECL_HANDLER(open_symlink);
 DECL_HANDLER(query_symlink);
+DECL_HANDLER(remote_operation);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -542,6 +543,7 @@
     (req_handler)req_create_symlink,
     (req_handler)req_open_symlink,
     (req_handler)req_query_symlink,
+    (req_handler)req_remote_operation,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
Index: server/trace.c
===================================================================
RCS file: /home/wine/wine/server/trace.c,v
retrieving revision 1.310
diff -u -r1.310 trace.c
--- server/trace.c	27 May 2006 11:37:01 -0000	1.310
+++ server/trace.c	2 Jun 2006 05:43:19 -0000
@@ -3263,6 +3263,21 @@
     dump_varargs_unicode_str( cur_size );
 }
 
+static void dump_remote_operation_request( const struct remote_operation_request *req )
+{
+    fprintf( stderr, " handle=%p,", req->handle );
+    fprintf( stderr, " code=%d,", req->code );
+    fprintf( stderr, " data=" );
+    dump_varargs_bytes( cur_size );
+}
+
+static void dump_remote_operation_reply( const struct remote_operation_reply *req )
+{
+    fprintf( stderr, " status=%08x,", req->status );
+    fprintf( stderr, " data=" );
+    dump_varargs_bytes( cur_size );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -3477,6 +3492,7 @@
     (dump_func)dump_create_symlink_request,
     (dump_func)dump_open_symlink_request,
     (dump_func)dump_query_symlink_request,
+    (dump_func)dump_remote_operation_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -3693,6 +3709,7 @@
     (dump_func)dump_create_symlink_reply,
     (dump_func)dump_open_symlink_reply,
     (dump_func)dump_query_symlink_reply,
+    (dump_func)dump_remote_operation_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -3909,6 +3926,7 @@
     "create_symlink",
     "open_symlink",
     "query_symlink",
+    "remote_operation",
 };
 
 static const struct



More information about the wine-devel mailing list