Commit 2654be08 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Handle NtSetContextThread on the client side (as far as

possible) when setting the context of the current thread.
parent 7114f8c3
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
/* exceptions */ /* exceptions */
extern void wait_suspend( CONTEXT *context ); extern void wait_suspend( CONTEXT *context );
extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT ); extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT );
extern void set_cpu_context( const CONTEXT *context );
/* debug helper */ /* debug helper */
extern LPCSTR debugstr_us( const UNICODE_STRING *str ); extern LPCSTR debugstr_us( const UNICODE_STRING *str );
......
...@@ -722,13 +722,13 @@ inline static void save_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext ) ...@@ -722,13 +722,13 @@ inline static void save_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
* *
* Restore the FPU context to a sigcontext. * Restore the FPU context to a sigcontext.
*/ */
inline static void restore_fpu( CONTEXT *context ) inline static void restore_fpu( const CONTEXT *context )
{ {
FLOATING_SAVE_AREA float_status = context->FloatSave;
/* reset the current interrupt status */ /* reset the current interrupt status */
context->FloatSave.StatusWord &= context->FloatSave.ControlWord | 0xffffff80; float_status.StatusWord &= float_status.ControlWord | 0xffffff80;
#ifdef __GNUC__ #ifdef __GNUC__
/* avoid nested exceptions */ __asm__ __volatile__( "frstor %0; fwait" : : "m" (float_status) );
__asm__ __volatile__( "frstor %0; fwait" : : "m" (context->FloatSave) );
#endif /* __GNUC__ */ #endif /* __GNUC__ */
} }
...@@ -799,12 +799,19 @@ inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigconte ...@@ -799,12 +799,19 @@ inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigconte
* *
* Set the new CPU context. * Set the new CPU context.
*/ */
inline static void DECLSPEC_NORETURN set_cpu_context( CONTEXT *context ) void set_cpu_context( const CONTEXT *context )
{ {
DWORD flags = context->ContextFlags & ~CONTEXT_i386; DWORD flags = context->ContextFlags & ~CONTEXT_i386;
if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context ); if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context );
__wine_call_from_32_restore_regs( context );
if (flags & CONTEXT_FULL)
{
if ((flags & CONTEXT_FULL) != (CONTEXT_FULL & ~CONTEXT_i386))
FIXME( "setting partial context (%lx) not supported\n", flags );
else
__wine_call_from_32_restore_regs( context );
}
} }
...@@ -991,7 +998,7 @@ static inline DWORD get_fpu_code( const CONTEXT *context ) ...@@ -991,7 +998,7 @@ static inline DWORD get_fpu_code( const CONTEXT *context )
/********************************************************************** /**********************************************************************
* raise_segv_exception * raise_segv_exception
*/ */
static void WINAPI DECLSPEC_NORETURN raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
{ {
switch(rec->ExceptionCode) switch(rec->ExceptionCode)
{ {
...@@ -1011,14 +1018,14 @@ static void WINAPI DECLSPEC_NORETURN raise_segv_exception( EXCEPTION_RECORD *rec ...@@ -1011,14 +1018,14 @@ static void WINAPI DECLSPEC_NORETURN raise_segv_exception( EXCEPTION_RECORD *rec
} }
__regs_RtlRaiseException( rec, context ); __regs_RtlRaiseException( rec, context );
done: done:
set_cpu_context( context ); NtSetContextThread( GetCurrentThread(), context );
} }
/********************************************************************** /**********************************************************************
* raise_trap_exception * raise_trap_exception
*/ */
static void WINAPI DECLSPEC_NORETURN raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) static void WINAPI raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
{ {
DWORD dr0, dr1, dr2, dr3, dr6, dr7; DWORD dr0, dr1, dr2, dr3, dr6, dr7;
...@@ -1037,6 +1044,7 @@ static void WINAPI DECLSPEC_NORETURN raise_trap_exception( EXCEPTION_RECORD *rec ...@@ -1037,6 +1044,7 @@ static void WINAPI DECLSPEC_NORETURN raise_trap_exception( EXCEPTION_RECORD *rec
* shall return a breakpoint, not a single step exception * shall return a breakpoint, not a single step exception
*/ */
if (!(context->Dr6 & 0xf)) rec->ExceptionCode = EXCEPTION_BREAKPOINT; if (!(context->Dr6 & 0xf)) rec->ExceptionCode = EXCEPTION_BREAKPOINT;
context->ContextFlags |= CONTEXT_FULL; /* restore flags */
} }
} }
...@@ -1049,15 +1057,14 @@ static void WINAPI DECLSPEC_NORETURN raise_trap_exception( EXCEPTION_RECORD *rec ...@@ -1049,15 +1057,14 @@ static void WINAPI DECLSPEC_NORETURN raise_trap_exception( EXCEPTION_RECORD *rec
__regs_RtlRaiseException( rec, context ); __regs_RtlRaiseException( rec, context );
context->ContextFlags = CONTEXT_FULL;
if (dr0 != context->Dr0 || dr1 != context->Dr1 || dr2 != context->Dr2 || if (dr0 != context->Dr0 || dr1 != context->Dr1 || dr2 != context->Dr2 ||
dr3 != context->Dr3 || dr6 != context->Dr6 || dr7 != context->Dr7) dr3 != context->Dr3 || dr6 != context->Dr6 || dr7 != context->Dr7)
{ {
/* the debug registers have changed, set the new values */ /* the debug registers have changed, set the new values */
context->ContextFlags = CONTEXT_DEBUG_REGISTERS; context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
NtSetContextThread(GetCurrentThread(), context);
} }
context->ContextFlags = CONTEXT_FULL; /* restore flags */ NtSetContextThread( GetCurrentThread(), context );
set_cpu_context( context );
} }
...@@ -1066,10 +1073,10 @@ static void WINAPI DECLSPEC_NORETURN raise_trap_exception( EXCEPTION_RECORD *rec ...@@ -1066,10 +1073,10 @@ static void WINAPI DECLSPEC_NORETURN raise_trap_exception( EXCEPTION_RECORD *rec
* *
* Generic raise function for exceptions that don't need special treatment. * Generic raise function for exceptions that don't need special treatment.
*/ */
static void WINAPI DECLSPEC_NORETURN raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) static void WINAPI raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
{ {
__regs_RtlRaiseException( rec, context ); __regs_RtlRaiseException( rec, context );
set_cpu_context( context ); NtSetContextThread( GetCurrentThread(), context );
} }
...@@ -1077,7 +1084,7 @@ static void WINAPI DECLSPEC_NORETURN raise_exception( EXCEPTION_RECORD *rec, CON ...@@ -1077,7 +1084,7 @@ static void WINAPI DECLSPEC_NORETURN raise_exception( EXCEPTION_RECORD *rec, CON
/********************************************************************** /**********************************************************************
* raise_vm86_sti_exception * raise_vm86_sti_exception
*/ */
static void WINAPI DECLSPEC_NORETURN raise_vm86_sti_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) static void WINAPI raise_vm86_sti_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
{ {
/* merge_vm86_pending_flags merges the vm86_pending flag in safely */ /* merge_vm86_pending_flags merges the vm86_pending flag in safely */
NtCurrentTeb()->vm86_pending |= VIP_MASK; NtCurrentTeb()->vm86_pending |= VIP_MASK;
...@@ -1101,7 +1108,7 @@ static void WINAPI DECLSPEC_NORETURN raise_vm86_sti_exception( EXCEPTION_RECORD ...@@ -1101,7 +1108,7 @@ static void WINAPI DECLSPEC_NORETURN raise_vm86_sti_exception( EXCEPTION_RECORD
__regs_RtlRaiseException( rec, context ); __regs_RtlRaiseException( rec, context );
} }
done: done:
set_cpu_context( context ); NtSetContextThread( GetCurrentThread(), context );
} }
......
...@@ -268,6 +268,17 @@ inline static void restore_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext ) ...@@ -268,6 +268,17 @@ inline static void restore_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
} }
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context.
*/
void set_cpu_context( const CONTEXT *context )
{
FIXME("not implemented\n");
}
/********************************************************************** /**********************************************************************
* get_fpu_code * get_fpu_code
* *
......
...@@ -148,6 +148,17 @@ static void restore_fpu( CONTEXT *context, ucontext_t *ucontext ) ...@@ -148,6 +148,17 @@ static void restore_fpu( CONTEXT *context, ucontext_t *ucontext )
} }
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context.
*/
void set_cpu_context( const CONTEXT *context )
{
FIXME("not implemented\n");
}
/********************************************************************** /**********************************************************************
* segv_handler * segv_handler
* *
......
...@@ -196,6 +196,17 @@ static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext ) ...@@ -196,6 +196,17 @@ static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
} }
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context.
*/
void set_cpu_context( const CONTEXT *context )
{
FIXME("not implemented\n");
}
/********************************************************************** /**********************************************************************
* segv_handler * segv_handler
* *
......
...@@ -491,41 +491,55 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) ...@@ -491,41 +491,55 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{ {
NTSTATUS ret; NTSTATUS ret;
DWORD dummy, i; DWORD dummy, i;
BOOL self = FALSE;
SERVER_START_REQ( set_thread_context ) #ifdef __i386__
{ /* on i386 debug registers always require a server call */
req->handle = handle; self = ((handle == GetCurrentThread()) &&
req->flags = context->ContextFlags; !(context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)));
req->suspend = 0; #endif
wine_server_add_data( req, context, sizeof(*context) );
ret = wine_server_call( req );
}
SERVER_END_REQ;
if (ret == STATUS_PENDING) if (!self)
{ {
if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS) SERVER_START_REQ( set_thread_context )
{ {
for (i = 0; i < 100; i++) req->handle = handle;
req->flags = context->ContextFlags;
req->suspend = 0;
wine_server_add_data( req, context, sizeof(*context) );
ret = wine_server_call( req );
self = reply->self;
}
SERVER_END_REQ;
if (ret == STATUS_PENDING)
{
if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
{ {
SERVER_START_REQ( set_thread_context ) for (i = 0; i < 100; i++)
{ {
req->handle = handle; SERVER_START_REQ( set_thread_context )
req->flags = context->ContextFlags; {
req->suspend = 0; req->handle = handle;
wine_server_add_data( req, context, sizeof(*context) ); req->flags = context->ContextFlags;
ret = wine_server_call( req ); req->suspend = 0;
wine_server_add_data( req, context, sizeof(*context) );
ret = wine_server_call( req );
}
SERVER_END_REQ;
if (ret != STATUS_PENDING) break;
NtYieldExecution();
} }
SERVER_END_REQ; NtResumeThread( handle, &dummy );
if (ret != STATUS_PENDING) break;
NtYieldExecution();
} }
NtResumeThread( handle, &dummy ); if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
} }
if (ret) return ret;
} }
if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED; if (self) set_cpu_context( context );
return ret; return STATUS_SUCCESS;
} }
......
...@@ -2006,6 +2006,7 @@ struct set_thread_context_request ...@@ -2006,6 +2006,7 @@ struct set_thread_context_request
struct set_thread_context_reply struct set_thread_context_reply
{ {
struct reply_header __header; struct reply_header __header;
int self;
}; };
...@@ -4347,6 +4348,6 @@ union generic_reply ...@@ -4347,6 +4348,6 @@ union generic_reply
struct query_symlink_reply query_symlink_reply; struct query_symlink_reply query_symlink_reply;
}; };
#define SERVER_PROTOCOL_VERSION 218 #define SERVER_PROTOCOL_VERSION 219
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -604,10 +604,9 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned ...@@ -604,10 +604,9 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned
flags &= ~CONTEXT_i386; /* get rid of CPU id */ flags &= ~CONTEXT_i386; /* get rid of CPU id */
if (thread->context) /* thread is inside an exception event or suspended */ if (thread->context) /* thread is inside an exception event or suspended */
{
copy_context( thread->context, context, flags ); copy_context( thread->context, context, flags );
flags &= CONTEXT_DEBUG_REGISTERS;
} flags &= CONTEXT_DEBUG_REGISTERS; /* the other registers are handled on the client side */
if (flags && suspend_for_ptrace( thread )) if (flags && suspend_for_ptrace( thread ))
{ {
......
...@@ -1442,6 +1442,8 @@ enum char_info_mode ...@@ -1442,6 +1442,8 @@ enum char_info_mode
unsigned int flags; /* context flags */ unsigned int flags; /* context flags */
int suspend; /* if setting context during suspend */ int suspend; /* if setting context during suspend */
VARARG(context,context); /* thread context */ VARARG(context,context); /* thread context */
@REPLY
int self; /* was it a handle to the current thread? */
@END @END
......
...@@ -1132,6 +1132,7 @@ DECL_HANDLER(set_thread_context) ...@@ -1132,6 +1132,7 @@ DECL_HANDLER(set_thread_context)
{ {
set_thread_context( thread, get_req_data(), req->flags ); set_thread_context( thread, get_req_data(), req->flags );
} }
reply->self = (thread == current);
release_object( thread ); release_object( thread );
} }
......
...@@ -1908,6 +1908,11 @@ static void dump_set_thread_context_request( const struct set_thread_context_req ...@@ -1908,6 +1908,11 @@ static void dump_set_thread_context_request( const struct set_thread_context_req
dump_varargs_context( cur_size ); dump_varargs_context( cur_size );
} }
static void dump_set_thread_context_reply( const struct set_thread_context_reply *req )
{
fprintf( stderr, " self=%d", req->self );
}
static void dump_get_selector_entry_request( const struct get_selector_entry_request *req ) static void dump_get_selector_entry_request( const struct get_selector_entry_request *req )
{ {
fprintf( stderr, " handle=%p,", req->handle ); fprintf( stderr, " handle=%p,", req->handle );
...@@ -3527,7 +3532,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { ...@@ -3527,7 +3532,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_cancel_timer_reply, (dump_func)dump_cancel_timer_reply,
(dump_func)dump_get_timer_info_reply, (dump_func)dump_get_timer_info_reply,
(dump_func)dump_get_thread_context_reply, (dump_func)dump_get_thread_context_reply,
(dump_func)0, (dump_func)dump_set_thread_context_reply,
(dump_func)dump_get_selector_entry_reply, (dump_func)dump_get_selector_entry_reply,
(dump_func)dump_add_atom_reply, (dump_func)dump_add_atom_reply,
(dump_func)0, (dump_func)0,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment