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

possible) when setting the context of the current thread.
This commit is contained in:
Alexandre Julliard 2006-01-11 20:20:32 +01:00
parent 7114f8c3bd
commit 2654be08d5
11 changed files with 113 additions and 50 deletions

View File

@ -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 );

View File

@ -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 );
}

View File

@ -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
*

View File

@ -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
*

View File

@ -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
*

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 ))
{

View File

@ -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

View File

@ -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 );
}

View File

@ -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,