ntdll: Handle NtSetContextThread on the client side (as far as
possible) when setting the context of the current thread.
This commit is contained in:
parent
7114f8c3bd
commit
2654be08d5
|
@ -32,6 +32,7 @@
|
|||
/* exceptions */
|
||||
extern void wait_suspend( CONTEXT *context );
|
||||
extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT );
|
||||
extern void set_cpu_context( const CONTEXT *context );
|
||||
|
||||
/* debug helper */
|
||||
extern LPCSTR debugstr_us( const UNICODE_STRING *str );
|
||||
|
|
|
@ -722,13 +722,13 @@ inline static void save_fpu( CONTEXT *context, const SIGCONTEXT *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 */
|
||||
context->FloatSave.StatusWord &= context->FloatSave.ControlWord | 0xffffff80;
|
||||
float_status.StatusWord &= float_status.ControlWord | 0xffffff80;
|
||||
#ifdef __GNUC__
|
||||
/* avoid nested exceptions */
|
||||
__asm__ __volatile__( "frstor %0; fwait" : : "m" (context->FloatSave) );
|
||||
__asm__ __volatile__( "frstor %0; fwait" : : "m" (float_status) );
|
||||
#endif /* __GNUC__ */
|
||||
}
|
||||
|
||||
|
@ -799,12 +799,19 @@ inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigconte
|
|||
*
|
||||
* 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;
|
||||
|
||||
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 )
|
|||
/**********************************************************************
|
||||
* 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)
|
||||
{
|
||||
|
@ -1011,14 +1018,14 @@ static void WINAPI DECLSPEC_NORETURN raise_segv_exception( EXCEPTION_RECORD *rec
|
|||
}
|
||||
__regs_RtlRaiseException( rec, context );
|
||||
done:
|
||||
set_cpu_context( context );
|
||||
NtSetContextThread( GetCurrentThread(), context );
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* 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;
|
||||
|
||||
|
@ -1037,6 +1044,7 @@ static void WINAPI DECLSPEC_NORETURN raise_trap_exception( EXCEPTION_RECORD *rec
|
|||
* shall return a breakpoint, not a single step exception
|
||||
*/
|
||||
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
|
|||
|
||||
__regs_RtlRaiseException( rec, context );
|
||||
|
||||
context->ContextFlags = CONTEXT_FULL;
|
||||
if (dr0 != context->Dr0 || dr1 != context->Dr1 || dr2 != context->Dr2 ||
|
||||
dr3 != context->Dr3 || dr6 != context->Dr6 || dr7 != context->Dr7)
|
||||
{
|
||||
/* the debug registers have changed, set the new values */
|
||||
context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
||||
NtSetContextThread(GetCurrentThread(), context);
|
||||
context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
||||
}
|
||||
context->ContextFlags = CONTEXT_FULL; /* restore flags */
|
||||
set_cpu_context( context );
|
||||
NtSetContextThread( GetCurrentThread(), context );
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
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 );
|
||||
set_cpu_context( context );
|
||||
NtSetContextThread( GetCurrentThread(), context );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1077,7 +1084,7 @@ static void WINAPI DECLSPEC_NORETURN raise_exception( EXCEPTION_RECORD *rec, CON
|
|||
/**********************************************************************
|
||||
* 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 */
|
||||
NtCurrentTeb()->vm86_pending |= VIP_MASK;
|
||||
|
@ -1101,7 +1108,7 @@ static void WINAPI DECLSPEC_NORETURN raise_vm86_sti_exception( EXCEPTION_RECORD
|
|||
__regs_RtlRaiseException( rec, context );
|
||||
}
|
||||
done:
|
||||
set_cpu_context( context );
|
||||
NtSetContextThread( GetCurrentThread(), context );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -491,41 +491,55 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
|||
{
|
||||
NTSTATUS ret;
|
||||
DWORD dummy, i;
|
||||
BOOL self = FALSE;
|
||||
|
||||
SERVER_START_REQ( set_thread_context )
|
||||
{
|
||||
req->handle = handle;
|
||||
req->flags = context->ContextFlags;
|
||||
req->suspend = 0;
|
||||
wine_server_add_data( req, context, sizeof(*context) );
|
||||
ret = wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
#ifdef __i386__
|
||||
/* on i386 debug registers always require a server call */
|
||||
self = ((handle == GetCurrentThread()) &&
|
||||
!(context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)));
|
||||
#endif
|
||||
|
||||
if (ret == STATUS_PENDING)
|
||||
if (!self)
|
||||
{
|
||||
if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
|
||||
SERVER_START_REQ( set_thread_context )
|
||||
{
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
SERVER_START_REQ( set_thread_context )
|
||||
{
|
||||
req->handle = handle;
|
||||
req->flags = context->ContextFlags;
|
||||
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();
|
||||
}
|
||||
NtResumeThread( handle, &dummy );
|
||||
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)
|
||||
{
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
SERVER_START_REQ( set_thread_context )
|
||||
{
|
||||
req->handle = handle;
|
||||
req->flags = context->ContextFlags;
|
||||
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();
|
||||
}
|
||||
NtResumeThread( handle, &dummy );
|
||||
}
|
||||
if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (ret) return ret;
|
||||
}
|
||||
|
||||
if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
|
||||
return ret;
|
||||
if (self) set_cpu_context( context );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2006,6 +2006,7 @@ struct set_thread_context_request
|
|||
struct set_thread_context_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
int self;
|
||||
};
|
||||
|
||||
|
||||
|
@ -4347,6 +4348,6 @@ union generic_reply
|
|||
struct query_symlink_reply query_symlink_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 218
|
||||
#define SERVER_PROTOCOL_VERSION 219
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -604,10 +604,9 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned
|
|||
flags &= ~CONTEXT_i386; /* get rid of CPU id */
|
||||
|
||||
if (thread->context) /* thread is inside an exception event or suspended */
|
||||
{
|
||||
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 ))
|
||||
{
|
||||
|
|
|
@ -1442,6 +1442,8 @@ enum char_info_mode
|
|||
unsigned int flags; /* context flags */
|
||||
int suspend; /* if setting context during suspend */
|
||||
VARARG(context,context); /* thread context */
|
||||
@REPLY
|
||||
int self; /* was it a handle to the current thread? */
|
||||
@END
|
||||
|
||||
|
||||
|
|
|
@ -1132,6 +1132,7 @@ DECL_HANDLER(set_thread_context)
|
|||
{
|
||||
set_thread_context( thread, get_req_data(), req->flags );
|
||||
}
|
||||
reply->self = (thread == current);
|
||||
release_object( thread );
|
||||
}
|
||||
|
||||
|
|
|
@ -1908,6 +1908,11 @@ static void dump_set_thread_context_request( const struct set_thread_context_req
|
|||
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 )
|
||||
{
|
||||
fprintf( stderr, " handle=%p,", req->handle );
|
||||
|
@ -3527,7 +3532,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_cancel_timer_reply,
|
||||
(dump_func)dump_get_timer_info_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_add_atom_reply,
|
||||
(dump_func)0,
|
||||
|
|
Loading…
Reference in New Issue