diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 7fa966b0c4e..cc97a98e0d6 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -4318,9 +4318,7 @@ static void test_wow64_context(void) "rsp is not at top of stack %p / %p\n", (void *)context.Rsp, teb.Tib.StackBase ); todo_wine ok( context.EFlags == 0x200, "wrong flags %08x\n", context.EFlags ); - todo_wine ok( context.MxCsr == 0x1f80, "wrong mxcsr %08x\n", context.MxCsr ); - todo_wine ok( context.FltSave.ControlWord == 0x27f, "wrong control %08x\n", context.FltSave.ControlWord ); todo_wine ok( context.SegCs != ctx.SegCs, "wrong cs %04x\n", context.SegCs ); diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 9cf82a7567e..5e3d7347a24 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -622,10 +622,11 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT wine_server_add_data( req, select_op, size ); if (suspend_context) { - wine_server_add_data( req, context, sizeof(*context) ); + data_size_t ctx_size = (context[1].machine ? 2 : 1) * sizeof(*context); + wine_server_add_data( req, context, ctx_size ); suspend_context = FALSE; /* server owns the context now */ } - if (context) wine_server_set_reply( req, context, sizeof(*context) ); + if (context) wine_server_set_reply( req, context, 2 * sizeof(*context) ); ret = server_call_unlocked( req ); apc_handle = reply->apc_handle; call = reply->call; diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index c24fa3a9b78..c82cdb8a9cf 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -331,6 +331,24 @@ NTSTATUS signal_set_full_context( CONTEXT *context ) } +/*********************************************************************** + * get_native_context + */ +void *get_native_context( CONTEXT *context ) +{ + return context; +} + + +/*********************************************************************** + * get_wow_context + */ +void *get_wow_context( CONTEXT *context ) +{ + return NULL; +} + + /*********************************************************************** * NtSetContextThread (NTDLL.@) * ZwSetContextThread (NTDLL.@) diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 5b8fff6a406..a88e5a4fd8c 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -420,6 +420,24 @@ NTSTATUS signal_set_full_context( CONTEXT *context ) } +/*********************************************************************** + * get_native_context + */ +void *get_native_context( CONTEXT *context ) +{ + return context; +} + + +/*********************************************************************** + * get_wow_context + */ +void *get_wow_context( CONTEXT *context ) +{ + return NULL; +} + + /*********************************************************************** * NtSetContextThread (NTDLL.@) * ZwSetContextThread (NTDLL.@) diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index a941a680b27..5c26e65548a 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -876,6 +876,24 @@ NTSTATUS signal_set_full_context( CONTEXT *context ) } +/*********************************************************************** + * get_native_context + */ +void *get_native_context( CONTEXT *context ) +{ + return is_wow64 ? NULL : context; +} + + +/*********************************************************************** + * get_wow_context + */ +void *get_wow_context( CONTEXT *context ) +{ + return is_wow64 ? context : NULL; +} + + /*********************************************************************** * NtSetContextThread (NTDLL.@) * ZwSetContextThread (NTDLL.@) diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index ac8eddf739e..cd2a17f9c91 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1597,6 +1597,24 @@ NTSTATUS signal_set_full_context( CONTEXT *context ) } +/*********************************************************************** + * get_native_context + */ +void *get_native_context( CONTEXT *context ) +{ + return context; +} + + +/*********************************************************************** + * get_wow_context + */ +void *get_wow_context( CONTEXT *context ) +{ + return NULL; +} + + /*********************************************************************** * NtSetContextThread (NTDLL.@) * ZwSetContextThread (NTDLL.@) diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 54556035934..ef3937d7fe8 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1009,6 +1009,46 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma } +/*********************************************************************** + * contexts_to_server + */ +static void contexts_to_server( context_t server_contexts[2], CONTEXT *context ) +{ + unsigned int count = 0; + void *native_context = get_native_context( context ); + void *wow_context = get_wow_context( context ); + + if (native_context) + { + context_to_server( &server_contexts[count++], native_machine, native_context, native_machine ); + if (wow_context) context_to_server( &server_contexts[count++], main_image_info.Machine, + wow_context, main_image_info.Machine ); + } + else + context_to_server( &server_contexts[count++], native_machine, + wow_context, main_image_info.Machine ); + + if (count < 2) memset( &server_contexts[1], 0, sizeof(server_contexts[1]) ); +} + + +/*********************************************************************** + * contexts_from_server + */ +static void contexts_from_server( CONTEXT *context, context_t server_contexts[2] ) +{ + void *native_context = get_native_context( context ); + void *wow_context = get_wow_context( context ); + + if (native_context) + { + context_from_server( native_context, &server_contexts[0], native_machine ); + if (wow_context) context_from_server( wow_context, &server_contexts[1], main_image_info.Machine ); + } + else context_from_server( wow_context, &server_contexts[0], main_image_info.Machine ); +} + + /*********************************************************************** * pthread_exit_wrapper */ @@ -1362,12 +1402,12 @@ void exit_process( int status ) void wait_suspend( CONTEXT *context ) { int saved_errno = errno; - context_t server_context; + context_t server_contexts[2]; - context_to_server( &server_context, current_machine, context, current_machine ); + contexts_to_server( server_contexts, context ); /* wait with 0 timeout, will only return once the thread is no longer suspended */ - server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, &server_context, NULL, NULL ); - context_from_server( context, &server_context, current_machine ); + server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, server_contexts, NULL, NULL ); + contexts_from_server( context, server_contexts ); errno = saved_errno; } @@ -1408,15 +1448,14 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c if (handle) { - context_t server_context; + context_t server_contexts[2]; select_op.wait.op = SELECT_WAIT; select_op.wait.handles[0] = handle; - context_to_server( &server_context, current_machine, context, current_machine ); - + contexts_to_server( server_contexts, context ); server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, - TIMEOUT_INFINITE, &server_context, NULL, NULL ); + TIMEOUT_INFINITE, server_contexts, NULL, NULL ); SERVER_START_REQ( get_exception_status ) { @@ -1424,7 +1463,7 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c ret = wine_server_call( req ); } SERVER_END_REQ; - if (ret >= 0) context_from_server( context, &server_context, current_machine ); + if (ret >= 0) contexts_from_server( context, server_contexts ); } pthread_sigmask( SIG_SETMASK, &old_set, NULL ); @@ -1594,14 +1633,18 @@ NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1 */ NTSTATUS set_thread_context( HANDLE handle, const void *context, BOOL *self, USHORT machine ) { - context_t server_context; + context_t server_contexts[2]; + unsigned int count = 0; NTSTATUS ret; - context_to_server( &server_context, machine, context, machine ); + context_to_server( &server_contexts[count++], native_machine, context, machine ); + if (machine != native_machine) + context_to_server( &server_contexts[count++], machine, context, machine ); + SERVER_START_REQ( set_thread_context ) { req->handle = wine_server_obj_handle( handle ); - wine_server_add_data( req, &server_context, sizeof(server_context) ); + wine_server_add_data( req, server_contexts, count * sizeof(server_contexts[0]) ); ret = wine_server_call( req ); *self = reply->self; } @@ -1618,17 +1661,20 @@ NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT ma { NTSTATUS ret; HANDLE context_handle; - context_t server_context; + context_t server_contexts[2]; + unsigned int count; unsigned int flags = get_server_context_flags( context, machine ); SERVER_START_REQ( get_thread_context ) { req->handle = wine_server_obj_handle( handle ); req->flags = flags; - wine_server_set_reply( req, &server_context, sizeof(server_context) ); + req->machine = machine; + wine_server_set_reply( req, server_contexts, sizeof(server_contexts) ); ret = wine_server_call( req ); *self = reply->self; context_handle = wine_server_ptr_handle( reply->handle ); + count = wine_server_reply_size( reply ) / sizeof(server_contexts[0]); } SERVER_END_REQ; @@ -1640,12 +1686,18 @@ NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT ma { req->context = wine_server_obj_handle( context_handle ); req->flags = flags; - wine_server_set_reply( req, &server_context, sizeof(server_context) ); + req->machine = machine; + wine_server_set_reply( req, server_contexts, sizeof(server_contexts) ); ret = wine_server_call( req ); + count = wine_server_reply_size( reply ) / sizeof(server_contexts[0]); } SERVER_END_REQ; } - if (!ret) ret = context_from_server( context, &server_context, machine ); + if (!ret) + { + ret = context_from_server( context, &server_contexts[0], machine ); + if (!ret && count > 1) ret = context_from_server( context, &server_contexts[1], machine ); + } return ret; } diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 51663d548f9..20b78e2a266 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -230,6 +230,8 @@ extern NTSTATUS get_builtin_unix_info( void *module, const char **name, void **h extern NTSTATUS set_builtin_unix_info( void *module, const char *name, void *handle, void *entry ) DECLSPEC_HIDDEN; extern NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len ) DECLSPEC_HIDDEN; +extern void *get_native_context( CONTEXT *context ) DECLSPEC_HIDDEN; +extern void *get_wow_context( CONTEXT *context ) DECLSPEC_HIDDEN; extern BOOL get_thread_times( int unix_pid, int unix_tid, LARGE_INTEGER *kernel_time, LARGE_INTEGER *user_time ) DECLSPEC_HIDDEN; extern void signal_init_threading(void) DECLSPEC_HIDDEN; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 4463b8fa380..58310a4d9a2 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1307,14 +1307,14 @@ struct select_request obj_handle_t prev_apc; /* VARARG(result,apc_result); */ /* VARARG(data,select_op,size); */ - /* VARARG(context,context); */ + /* VARARG(contexts,contexts); */ }; struct select_reply { struct reply_header __header; apc_call_t call; obj_handle_t apc_handle; - /* VARARG(context,context); */ + /* VARARG(contexts,contexts); */ char __pad_60[4]; }; #define SELECT_ALERTABLE 1 @@ -2462,13 +2462,15 @@ struct get_thread_context_request obj_handle_t handle; obj_handle_t context; unsigned int flags; + unsigned short machine; + char __pad_26[6]; }; struct get_thread_context_reply { struct reply_header __header; int self; obj_handle_t handle; - /* VARARG(context,context); */ + /* VARARG(contexts,contexts); */ }; @@ -2477,7 +2479,7 @@ struct set_thread_context_request { struct request_header __header; obj_handle_t handle; - /* VARARG(context,context); */ + /* VARARG(contexts,contexts); */ }; struct set_thread_context_reply { @@ -6218,7 +6220,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 716 +#define SERVER_PROTOCOL_VERSION 717 /* ### protocol_version end ### */ diff --git a/server/protocol.def b/server/protocol.def index 6a11dfac77d..5d165e7bfa4 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1156,11 +1156,11 @@ typedef struct obj_handle_t prev_apc; /* handle to previous APC */ VARARG(result,apc_result); /* result of previous APC */ VARARG(data,select_op,size); /* operation-specific data */ - VARARG(context,context); /* suspend context */ + VARARG(contexts,contexts); /* suspend context(s) */ @REPLY apc_call_t call; /* APC call arguments */ obj_handle_t apc_handle; /* handle to next APC */ - VARARG(context,context); /* suspend context */ + VARARG(contexts,contexts); /* suspend context(s) */ @END #define SELECT_ALERTABLE 1 #define SELECT_INTERRUPTIBLE 2 @@ -1885,17 +1885,18 @@ struct process_info obj_handle_t handle; /* thread handle */ obj_handle_t context; /* context handle */ unsigned int flags; /* context flags */ + unsigned short machine; /* context architecture */ @REPLY int self; /* was it a handle to the current thread? */ obj_handle_t handle; /* pending context handle */ - VARARG(context,context); /* thread context */ + VARARG(contexts,contexts); /* thread context(s) */ @END /* Set the current context of a thread */ @REQ(set_thread_context) obj_handle_t handle; /* thread handle */ - VARARG(context,context); /* thread context */ + VARARG(contexts,contexts); /* thread context(s) */ @REPLY int self; /* was it a handle to the current thread? */ @END diff --git a/server/request.h b/server/request.h index 2106e3a3224..defb3a640fd 100644 --- a/server/request.h +++ b/server/request.h @@ -1255,7 +1255,8 @@ C_ASSERT( sizeof(struct get_timer_info_reply) == 24 ); C_ASSERT( FIELD_OFFSET(struct get_thread_context_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_thread_context_request, context) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_thread_context_request, flags) == 20 ); -C_ASSERT( sizeof(struct get_thread_context_request) == 24 ); +C_ASSERT( FIELD_OFFSET(struct get_thread_context_request, machine) == 24 ); +C_ASSERT( sizeof(struct get_thread_context_request) == 32 ); C_ASSERT( FIELD_OFFSET(struct get_thread_context_reply, self) == 8 ); C_ASSERT( FIELD_OFFSET(struct get_thread_context_reply, handle) == 12 ); C_ASSERT( sizeof(struct get_thread_context_reply) == 16 ); diff --git a/server/thread.c b/server/thread.c index 70e0b3fad15..703b23d73d1 100644 --- a/server/thread.c +++ b/server/thread.c @@ -120,8 +120,11 @@ struct context { struct object obj; /* object header */ unsigned int status; /* status of the context */ - context_t regs; /* context data */ + context_t regs[3]; /* context data */ }; +#define CTX_NATIVE 0 /* context for native machine */ +#define CTX_WOW 1 /* context if thread is inside WoW */ +#define CTX_PENDING 2 /* pending native context when we don't know whether thread is inside WoW */ static void dump_context( struct object *obj, int verbose ); static int context_signaled( struct object *obj, struct wait_queue_entry *entry ); @@ -268,7 +271,8 @@ static void dump_context( struct object *obj, int verbose ) struct context *context = (struct context *)obj; assert( obj->ops == &context_ops ); - fprintf( stderr, "context flags=%x\n", context->regs.flags ); + fprintf( stderr, "context flags=%x/%x\n", + context->regs[CTX_NATIVE].flags, context->regs[CTX_WOW].flags ); } @@ -285,7 +289,8 @@ static struct context *create_thread_context( struct thread *thread ) if (!(context = alloc_object( &context_ops ))) return NULL; context->status = STATUS_PENDING; memset( &context->regs, 0, sizeof(context->regs) ); - context->regs.machine = thread->process->machine; + context->regs[CTX_NATIVE].machine = native_machine; + context->regs[CTX_PENDING].machine = native_machine; return context; } @@ -865,7 +870,7 @@ static int send_thread_wakeup( struct thread *thread, client_ptr_t cookie, int s if (thread->context && thread->suspend_cookie == cookie && signaled != STATUS_KERNEL_APC && signaled != STATUS_USER_APC) { - if (!thread->context->regs.flags) + if (!thread->context->regs[CTX_NATIVE].flags && !thread->context->regs[CTX_WOW].flags) { release_object( thread->context ); thread->context = NULL; @@ -1575,41 +1580,66 @@ DECL_HANDLER(resume_thread) DECL_HANDLER(select) { select_op_t select_op; - data_size_t op_size; + data_size_t op_size, ctx_size; + struct context *ctx; struct thread_apc *apc; const apc_result_t *result = get_req_data(); + unsigned int ctx_count; - if (get_req_data_size() < sizeof(*result) || - get_req_data_size() - sizeof(*result) < req->size || - req->size & 3) - { - set_error( STATUS_INVALID_PARAMETER ); - return; - } + if (get_req_data_size() < sizeof(*result)) goto invalid_param; + if (get_req_data_size() - sizeof(*result) < req->size) goto invalid_param; + if (req->size & 3) goto invalid_param; + ctx_size = get_req_data_size() - sizeof(*result) - req->size; + ctx_count = ctx_size / sizeof(context_t); + if (ctx_count * sizeof(context_t) != ctx_size) goto invalid_param; + if (ctx_count > 1 + (current->process->machine != native_machine)) goto invalid_param; - if (get_req_data_size() - sizeof(*result) - req->size == sizeof(context_t)) + if (ctx_count) { - const context_t *context = (const context_t *)((const char *)(result + 1) + req->size); - if ((current->context && current->context->status != STATUS_PENDING) || - context->machine != current->process->machine) + const context_t *native_context = (const context_t *)((const char *)(result + 1) + req->size); + const context_t *wow_context = (ctx_count > 1) ? native_context + 1 : NULL; + unsigned int system_flags = get_context_system_regs( native_machine ); + + if (current->context && current->context->status != STATUS_PENDING) goto invalid_param; + + if (native_context->machine == native_machine) { - set_error( STATUS_INVALID_PARAMETER ); - return; + if (wow_context && wow_context->machine != current->process->machine) goto invalid_param; } + else if (native_context->machine == current->process->machine) + { + if (wow_context) goto invalid_param; + wow_context = native_context; + native_context = NULL; + } + else goto invalid_param; if (!current->context && !(current->context = create_thread_context( current ))) return; - copy_context( ¤t->context->regs, context, - context->flags & ~(current->context->regs.flags | get_context_system_regs(current->process->machine)) ); - current->context->status = STATUS_SUCCESS; + + ctx = current->context; + if (native_context) + { + copy_context( &ctx->regs[CTX_NATIVE], native_context, + native_context->flags & ~(ctx->regs[CTX_NATIVE].flags | system_flags) ); + } + if (wow_context) + { + ctx->regs[CTX_WOW].machine = current->process->machine; + copy_context( &ctx->regs[CTX_WOW], wow_context, wow_context->flags & ~ctx->regs[CTX_WOW].flags ); + } + else if (ctx->regs[CTX_PENDING].flags) + { + unsigned int flags = ctx->regs[CTX_PENDING].flags & ~ctx->regs[CTX_NATIVE].flags; + copy_context( &ctx->regs[CTX_NATIVE], &ctx->regs[CTX_PENDING], flags ); + ctx->regs[CTX_NATIVE].flags |= flags; + } + ctx->regs[CTX_PENDING].flags = 0; + ctx->status = STATUS_SUCCESS; current->suspend_cookie = req->cookie; - wake_up( ¤t->context->obj, 0 ); + wake_up( &ctx->obj, 0 ); } - if (!req->cookie) - { - set_error( STATUS_INVALID_PARAMETER ); - return; - } + if (!req->cookie) goto invalid_param; op_size = min( req->size, sizeof(select_op) ); memset( &select_op, 0, sizeof(select_op) ); @@ -1655,19 +1685,24 @@ DECL_HANDLER(select) } release_object( apc ); } - else if (get_error() != STATUS_PENDING && get_reply_max_size() == sizeof(context_t) && + else if (get_error() != STATUS_PENDING && get_reply_max_size() >= sizeof(context_t) && current->context && current->suspend_cookie == req->cookie) { - if (current->context->regs.flags) + ctx = current->context; + if (ctx->regs[CTX_NATIVE].flags || ctx->regs[CTX_WOW].flags) { - unsigned int system_flags = get_context_system_regs(current->process->machine) & - current->context->regs.flags; - if (system_flags) set_thread_context( current, ¤t->context->regs, system_flags ); - set_reply_data( ¤t->context->regs, sizeof(context_t) ); + data_size_t size = (ctx->regs[CTX_WOW].flags ? 2 : 1) * sizeof(context_t); + unsigned int system_flags = get_context_system_regs( native_machine ) & ctx->regs[CTX_NATIVE].flags; + if (system_flags) set_thread_context( current, &ctx->regs[CTX_NATIVE], system_flags ); + set_reply_data( ctx->regs, min( size, get_reply_max_size() )); } - release_object( current->context ); + release_object( ctx ); current->context = NULL; } + return; + +invalid_param: + set_error( STATUS_INVALID_PARAMETER ); } /* queue an APC for a thread or process */ @@ -1787,11 +1822,10 @@ DECL_HANDLER(get_apc_result) DECL_HANDLER(get_thread_context) { struct context *thread_context = NULL; - unsigned int system_flags; struct thread *thread; context_t *context; - if (get_reply_max_size() < sizeof(context_t)) + if (get_reply_max_size() < 2 * sizeof(context_t)) { set_error( STATUS_INVALID_PARAMETER ); return; @@ -1799,53 +1833,76 @@ DECL_HANDLER(get_thread_context) if (req->context) { - if (!(thread_context = (struct context *)get_handle_obj( current->process, req->context, 0, &context_ops ))) + if (!(thread_context = (struct context *)get_handle_obj( current->process, req->context, + 0, &context_ops ))) return; close_handle( current->process, req->context ); /* avoid extra server call */ } else { if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return; - system_flags = get_context_system_regs( thread->process->machine ); - if (thread->state == RUNNING) + if (req->machine != native_machine && req->machine != thread->process->machine) + set_error( STATUS_INVALID_PARAMETER ); + else if (thread->state != RUNNING) + set_error( STATUS_UNSUCCESSFUL ); + else { + unsigned int system_flags = get_context_system_regs( native_machine ); reply->self = (thread == current); if (thread != current) stop_thread( thread ); if (thread->context) { /* make sure that system regs are valid in thread context */ - if (thread->unix_tid != -1 && (req->flags & system_flags & ~thread->context->regs.flags)) - get_thread_context( thread, &thread->context->regs, req->flags & system_flags ); + if (thread->unix_tid != -1 && (system_flags & ~thread->context->regs[CTX_NATIVE].flags)) + get_thread_context( thread, &thread->context->regs[CTX_NATIVE], system_flags ); if (!get_error()) thread_context = (struct context *)grab_object( thread->context ); } else if (!get_error() && (context = set_reply_data_size( sizeof(context_t) ))) { assert( reply->self ); memset( context, 0, sizeof(context_t) ); - context->machine = thread->process->machine; - if (req->flags & system_flags) - { - get_thread_context( thread, context, req->flags & system_flags ); - context->flags |= req->flags & system_flags; - } + context->machine = native_machine; + if (system_flags) get_thread_context( thread, context, system_flags ); } } - else set_error( STATUS_UNSUCCESSFUL ); release_object( thread ); if (!thread_context) return; } - set_error( thread_context->status ); - if (!thread_context->status && (context = set_reply_data_size( sizeof(context_t) ))) + if (!thread_context->status) { - memset( context, 0, sizeof(context_t) ); - context->machine = thread_context->regs.machine; - copy_context( context, &thread_context->regs, req->flags ); - context->flags = req->flags; + unsigned int system_flags = get_context_system_regs( native_machine ); + unsigned int native_flags = req->flags, wow_flags = 0; + + if (req->machine == thread_context->regs[CTX_WOW].machine) + { + native_flags = req->flags & system_flags; + wow_flags = req->flags & ~system_flags; + } + if ((context = set_reply_data_size( (!!native_flags + !!wow_flags) * sizeof(context_t) ))) + { + if (native_flags) + { + memset( context, 0, sizeof(*context) ); + context->machine = thread_context->regs[CTX_NATIVE].machine; + copy_context( context, &thread_context->regs[CTX_NATIVE], native_flags ); + context->flags = native_flags; + context++; + } + if (wow_flags) + { + memset( context, 0, sizeof(*context) ); + context->machine = thread_context->regs[CTX_WOW].machine; + copy_context( context, &thread_context->regs[CTX_WOW], wow_flags ); + context->flags = wow_flags; + } + } } - else if (thread_context->status == STATUS_PENDING) + else { - reply->handle = alloc_handle( current->process, thread_context, SYNCHRONIZE, 0 ); + set_error( thread_context->status ); + if (thread_context->status == STATUS_PENDING) + reply->handle = alloc_handle( current->process, thread_context, SYNCHRONIZE, 0 ); } release_object( thread_context ); @@ -1855,49 +1912,55 @@ DECL_HANDLER(get_thread_context) DECL_HANDLER(set_thread_context) { struct thread *thread; - const context_t *context = get_req_data(); + const context_t *contexts = get_req_data(); + unsigned int ctx_count = get_req_data_size() / sizeof(context_t); - if (get_req_data_size() < sizeof(context_t)) + if (!ctx_count || ctx_count > 2 || ctx_count * sizeof(context_t) != get_req_data_size()) { set_error( STATUS_INVALID_PARAMETER ); return; } + if (!(thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT ))) return; reply->self = (thread == current); - if (thread->state == TERMINATED) set_error( STATUS_UNSUCCESSFUL ); - else if (context->machine == thread->process->machine) + if (contexts[CTX_NATIVE].machine != native_machine || + (ctx_count == 2 && contexts[CTX_WOW].machine != thread->process->machine)) + set_error( STATUS_INVALID_PARAMETER ); + else if (thread->state != TERMINATED) { - unsigned int system_flags = get_context_system_regs( context->machine ) & context->flags; + unsigned int flags, ctx = CTX_NATIVE; + const context_t *context = &contexts[CTX_NATIVE]; + unsigned int system_flags = get_context_system_regs( native_machine ) & context->flags; if (thread != current) stop_thread( thread ); else if (system_flags) set_thread_context( thread, context, system_flags ); if (thread->context && !get_error()) { - copy_context( &thread->context->regs, context, context->flags ); - thread->context->regs.flags |= context->flags; - } - } - else if (context->machine == IMAGE_FILE_MACHINE_AMD64 && - thread->process->machine == IMAGE_FILE_MACHINE_I386) - { - /* convert the WoW64 context */ - unsigned int system_flags = get_context_system_regs( context->machine ) & context->flags; - if (system_flags) - { - set_thread_context( thread, context, system_flags ); - if (thread->context && !get_error()) + if (ctx_count == 2) { - thread->context->regs.debug.i386_regs.dr0 = context->debug.x86_64_regs.dr0; - thread->context->regs.debug.i386_regs.dr1 = context->debug.x86_64_regs.dr1; - thread->context->regs.debug.i386_regs.dr2 = context->debug.x86_64_regs.dr2; - thread->context->regs.debug.i386_regs.dr3 = context->debug.x86_64_regs.dr3; - thread->context->regs.debug.i386_regs.dr6 = context->debug.x86_64_regs.dr6; - thread->context->regs.debug.i386_regs.dr7 = context->debug.x86_64_regs.dr7; + /* If the target thread doesn't have a WoW context, set native instead. + * If we don't know yet whether we have a WoW context, store native context + * in CTX_PENDING and update when the target thread sends its context(s). */ + if (thread->context->status != STATUS_PENDING) + { + ctx = thread->context->regs[CTX_WOW].machine ? CTX_WOW : CTX_NATIVE; + context = &contexts[ctx]; + } + else ctx = CTX_PENDING; } + flags = context->flags; + if (system_flags && ctx != CTX_NATIVE) /* system regs are always set from the native context */ + { + copy_context( &thread->context->regs[CTX_NATIVE], &contexts[CTX_NATIVE], system_flags ); + thread->context->regs[CTX_NATIVE].flags |= system_flags; + flags &= ~system_flags; + } + copy_context( &thread->context->regs[ctx], context, flags ); + thread->context->regs[ctx].flags |= flags; } } - else set_error( STATUS_INVALID_PARAMETER ); + else set_error( STATUS_UNSUCCESSFUL ); release_object( thread ); } diff --git a/server/trace.c b/server/trace.c index 87ed4862e88..406be00008e 100644 --- a/server/trace.c +++ b/server/trace.c @@ -815,6 +815,21 @@ static void dump_varargs_context( const char *prefix, data_size_t size ) remove_data( size ); } +static void dump_varargs_contexts( const char *prefix, data_size_t size ) +{ + if (!size) + { + fprintf( stderr, "%s{}", prefix ); + return; + } + fprintf( stderr, "%s{", prefix ); + while (cur_size) + { + dump_varargs_context( "", cur_size ); + fputc( cur_size ? ',' : '}', stderr ); + } +} + static void dump_varargs_debug_event( const char *prefix, data_size_t size ) { debug_event_t event; @@ -1781,14 +1796,14 @@ static void dump_select_request( const struct select_request *req ) fprintf( stderr, ", prev_apc=%04x", req->prev_apc ); dump_varargs_apc_result( ", result=", cur_size ); dump_varargs_select_op( ", data=", min(cur_size,req->size) ); - dump_varargs_context( ", context=", cur_size ); + dump_varargs_contexts( ", contexts=", cur_size ); } static void dump_select_reply( const struct select_reply *req ) { dump_apc_call( " call=", &req->call ); fprintf( stderr, ", apc_handle=%04x", req->apc_handle ); - dump_varargs_context( ", context=", cur_size ); + dump_varargs_contexts( ", contexts=", cur_size ); } static void dump_create_event_request( const struct create_event_request *req ) @@ -2555,19 +2570,20 @@ static void dump_get_thread_context_request( const struct get_thread_context_req fprintf( stderr, " handle=%04x", req->handle ); fprintf( stderr, ", context=%04x", req->context ); fprintf( stderr, ", flags=%08x", req->flags ); + fprintf( stderr, ", machine=%04x", req->machine ); } static void dump_get_thread_context_reply( const struct get_thread_context_reply *req ) { fprintf( stderr, " self=%d", req->self ); fprintf( stderr, ", handle=%04x", req->handle ); - dump_varargs_context( ", context=", cur_size ); + dump_varargs_contexts( ", contexts=", cur_size ); } static void dump_set_thread_context_request( const struct set_thread_context_request *req ) { fprintf( stderr, " handle=%04x", req->handle ); - dump_varargs_context( ", context=", cur_size ); + dump_varargs_contexts( ", contexts=", cur_size ); } static void dump_set_thread_context_reply( const struct set_thread_context_reply *req )