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, ®s) == -1) + goto error; + + memcpy(&oldregs, ®s, 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, ®s) == -1) + goto error; + if (ptrace(PTRACE_CONT, pid, NULL, NULL) == -1) + goto error; + + wait(NULL); + if (ptrace(PTRACE_GETREGS, pid, NULL, ®s) == -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, ®s) == -1) + goto freeerror; + memcpy(&oldregs, ®s, 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, ®s) == -1) + goto freeerror; + if (ptrace(PTRACE_CONT, pid, NULL, NULL) == -1) + goto freeerror; + + wait(NULL); + if (ptrace(PTRACE_GETREGS, pid, NULL, ®s) == -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 */ +@REQ(remote_operation) + obj_handle_t handle; /* process handle */ + int code; /* operation code (see below) */ + VARARG(data,bytes); /* operation parameters (see below) */ +@REPLY + unsigned int status; /* operation status */ + VARARG(data,bytes); /* operation result data (see below) */ +@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