forked from Mirrors/wine-wine
ntdll: Handle NtSetContextThread on the client side (as far as
possible) when setting the context of the current thread.oldstable
parent
7114f8c3bd
commit
2654be08d5
|
@ -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 )
|
||||||
*
|
*
|
||||||
* 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
|
||||||
*
|
*
|
||||||
* 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 )
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* 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
|
||||||
}
|
}
|
||||||
__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
|
||||||
* 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
|
||||||
|
|
||||||
__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
|
||||||
*
|
*
|
||||||
* 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
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* 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
|
||||||
__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 )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* 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 )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* 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 )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* 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 )
|
||||||
{
|
{
|
||||||
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;
|
||||||
SERVER_START_REQ( set_thread_context )
|
req->suspend = 0;
|
||||||
{
|
wine_server_add_data( req, context, sizeof(*context) );
|
||||||
req->handle = handle;
|
ret = wine_server_call( req );
|
||||||
req->flags = context->ContextFlags;
|
self = reply->self;
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
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;
|
if (self) set_cpu_context( context );
|
||||||
return ret;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
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
|
||||||
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
|
||||||
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)
|
||||||
{
|
{
|
||||||
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
|
||||||
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] = {
|
||||||
(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,
|
||||||
|
|
Loading…
Reference in New Issue