From d2ad6f83556449bcd8a798191cfc8f0ae8b6d950 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 20 Apr 2006 15:40:28 +0200 Subject: [PATCH] ntdll: Get registers on the client side for NtGetContextThread on the current thread. --- dlls/ntdll/ntdll_misc.h | 1 + dlls/ntdll/signal_i386.c | 32 +++++++++++++-- dlls/ntdll/signal_powerpc.c | 11 +++++ dlls/ntdll/signal_sparc.c | 11 +++++ dlls/ntdll/signal_x86_64.c | 11 +++++ dlls/ntdll/thread.c | 82 ++++++++++++++++++++++--------------- server/context_i386.c | 5 +-- 7 files changed, 113 insertions(+), 40 deletions(-) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 35cbd5b3282..fa18e46a8a5 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -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 */ diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 39b20d0d687..398dbdf0f79 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -703,6 +703,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 * @@ -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 ); } } @@ -823,6 +834,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 * diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c index 50d48d47866..cbe4f80b195 100644 --- a/dlls/ntdll/signal_powerpc.c +++ b/dlls/ntdll/signal_powerpc.c @@ -268,6 +268,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 * diff --git a/dlls/ntdll/signal_sparc.c b/dlls/ntdll/signal_sparc.c index 4ae33403d12..0bf8dac5622 100644 --- a/dlls/ntdll/signal_sparc.c +++ b/dlls/ntdll/signal_sparc.c @@ -148,6 +148,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 * diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 87d40b54c1d..4ae61e75c59 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -198,6 +198,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 * diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index b4226f995bd..67e69301a38 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -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 ) { - for (i = 0; i < 100; i++) - { - 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(); - } - NtResumeThread( handle, &dummy ); + 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) + { + if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS) + { + for (i = 0; i < 100; i++) + { + 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(); + } + 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; } diff --git a/server/context_i386.c b/server/context_i386.c index ce7fd9b6ed2..0a3a3291b7d 100644 --- a/server/context_i386.c +++ b/server/context_i386.c @@ -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 )) {