Commit d2ad6f83 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Get registers on the client side for NtGetContextThread on the current thread.

parent 63ef9788
......@@ -32,6 +32,7 @@
/* exceptions */
extern void wait_suspend( CONTEXT *context );
extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT );
extern void get_cpu_context( CONTEXT *context );
extern void set_cpu_context( const CONTEXT *context );
/* debug helper */
......
......@@ -704,6 +704,20 @@ inline static void *init_handler( const SIGCONTEXT *sigcontext, WORD *fs, WORD *
/***********************************************************************
* save_fpu
*
* Save the thread FPU context.
*/
inline static void save_fpu( CONTEXT *context )
{
#ifdef __GNUC__
context->ContextFlags |= CONTEXT_FLOATING_POINT;
__asm__ __volatile__( "fnsave %0; fwait" : "=m" (context->FloatSave) );
#endif
}
/***********************************************************************
* restore_fpu
*
* Restore the FPU context to a sigcontext.
......@@ -762,10 +776,7 @@ inline static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext,
else
#endif
{
#ifdef __GNUC__
context->ContextFlags |= CONTEXT_FLOATING_POINT;
__asm__ __volatile__( "fnsave %0; fwait" : "=m" (context->FloatSave) );
#endif
save_fpu( context );
}
}
......@@ -824,6 +835,19 @@ inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigconte
/***********************************************************************
* get_cpu_context
*
* Register function to get the context of the current thread.
*/
void WINAPI __regs_get_cpu_context( CONTEXT *context, CONTEXT *regs )
{
*context = *regs;
save_fpu( context );
}
DEFINE_REGS_ENTRYPOINT( get_cpu_context, 4, 4 );
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context. Used by NtSetContextThread.
......
......@@ -269,6 +269,17 @@ inline static void restore_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
/***********************************************************************
* get_cpu_context
*
* Get the context of the current thread.
*/
void get_cpu_context( CONTEXT *context )
{
FIXME("not implemented\n");
}
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context.
......
......@@ -149,6 +149,17 @@ static void restore_fpu( CONTEXT *context, ucontext_t *ucontext )
/***********************************************************************
* get_cpu_context
*
* Get the context of the current thread.
*/
void get_cpu_context( CONTEXT *context )
{
FIXME("not implemented\n");
}
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context.
......
......@@ -199,6 +199,17 @@ static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
/***********************************************************************
* get_cpu_context
*
* Get the context of the current thread.
*/
void get_cpu_context( CONTEXT *context )
{
FIXME("not implemented\n");
}
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context.
......
......@@ -921,47 +921,64 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
NTSTATUS ret;
CONTEXT ctx;
DWORD dummy, i;
BOOL self = FALSE;
DWORD needed_flags = context->ContextFlags;
BOOL self = (handle == GetCurrentThread());
SERVER_START_REQ( get_thread_context )
{
req->handle = handle;
req->flags = context->ContextFlags;
req->suspend = 0;
wine_server_set_reply( req, &ctx, sizeof(ctx) );
ret = wine_server_call( req );
self = reply->self;
}
SERVER_END_REQ;
#ifdef __i386__
/* on i386 debug registers always require a server call */
if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)) self = FALSE;
#endif
if (ret == STATUS_PENDING)
if (!self)
{
if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
SERVER_START_REQ( get_thread_context )
{
req->handle = handle;
req->flags = context->ContextFlags;
req->suspend = 0;
wine_server_set_reply( req, &ctx, sizeof(ctx) );
ret = wine_server_call( req );
self = reply->self;
}
SERVER_END_REQ;
if (ret == STATUS_PENDING)
{
for (i = 0; i < 100; i++)
if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
{
SERVER_START_REQ( get_thread_context )
for (i = 0; i < 100; i++)
{
req->handle = handle;
req->flags = context->ContextFlags;
req->suspend = 0;
wine_server_set_reply( req, &ctx, sizeof(ctx) );
ret = wine_server_call( req );
SERVER_START_REQ( get_thread_context )
{
req->handle = handle;
req->flags = context->ContextFlags;
req->suspend = 0;
wine_server_set_reply( req, &ctx, sizeof(ctx) );
ret = wine_server_call( req );
}
SERVER_END_REQ;
if (ret != STATUS_PENDING) break;
NtYieldExecution();
}
SERVER_END_REQ;
if (ret != STATUS_PENDING) break;
NtYieldExecution();
NtResumeThread( handle, &dummy );
}
NtResumeThread( handle, &dummy );
if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
}
if (ret) return ret;
copy_context( context, &ctx, context->ContextFlags & ctx.ContextFlags );
needed_flags &= ~ctx.ContextFlags;
}
if (ret == STATUS_SUCCESS)
if (self)
{
copy_context( context, &ctx, context->ContextFlags );
if (needed_flags)
{
get_cpu_context( &ctx );
copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
}
#ifdef __i386__
/* update the cached version of the debug registers */
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386))
{
struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
regs->dr0 = context->Dr0;
......@@ -973,8 +990,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
}
#endif
}
else if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
return ret;
return STATUS_SUCCESS;
}
......
......@@ -550,10 +550,9 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f
flags &= ~CONTEXT_i386; /* get rid of CPU id */
if (thread->context) /* thread is inside an exception event or suspended */
{
copy_context( context, thread->context, flags );
flags &= CONTEXT_DEBUG_REGISTERS;
}
flags &= CONTEXT_DEBUG_REGISTERS;
if (flags && suspend_for_ptrace( thread ))
{
......
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