server: Support both native and wow64 register contexts.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
f64d86eb0a
commit
8ac411ed6d
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.@)
|
||||
|
|
|
@ -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.@)
|
||||
|
|
|
@ -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.@)
|
||||
|
|
|
@ -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.@)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ### */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
225
server/thread.c
225
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 );
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
|
|
Loading…
Reference in New Issue