Alexandre Julliard : ntdll: Use the CPU area to get/set the Wow64 context on x86-64.
Alexandre Julliard
julliard at winehq.org
Thu Jul 1 15:53:49 CDT 2021
Module: wine
Branch: master
Commit: 11d6c52f32e4ac31414f1b8580606e61c738c452
URL: https://source.winehq.org/git/wine.git/?a=commit;h=11d6c52f32e4ac31414f1b8580606e61c738c452
Author: Alexandre Julliard <julliard at winehq.org>
Date: Thu Jul 1 12:17:29 2021 +0200
ntdll: Use the CPU area to get/set the Wow64 context on x86-64.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/unix/signal_x86_64.c | 184 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 179 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index f9e82d72190..56dc640e082 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -1614,7 +1614,8 @@ void *get_native_context( CONTEXT *context )
*/
void *get_wow_context( CONTEXT *context )
{
- return NULL;
+ if (context->SegCs != cs64_sel) return NULL;
+ return get_cpu_area( IMAGE_FILE_MACHINE_I386 );
}
@@ -1851,10 +1852,97 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
*/
NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size )
{
- BOOL self;
+ BOOL self = (handle == GetCurrentThread());
+ struct syscall_frame *frame = amd64_thread_data()->syscall_frame;
+ I386_CONTEXT *wow_frame;
+ const I386_CONTEXT *context = ctx;
+ DWORD flags = context->ContextFlags & ~CONTEXT_i386;
if (size != sizeof(I386_CONTEXT)) return STATUS_INFO_LENGTH_MISMATCH;
- return set_thread_context( handle, ctx, &self, IMAGE_FILE_MACHINE_I386 );
+
+ /* debug registers require a server call */
+ if (self && (flags & CONTEXT_I386_DEBUG_REGISTERS))
+ self = (amd64_thread_data()->dr0 == context->Dr0 &&
+ amd64_thread_data()->dr1 == context->Dr1 &&
+ amd64_thread_data()->dr2 == context->Dr2 &&
+ amd64_thread_data()->dr3 == context->Dr3 &&
+ amd64_thread_data()->dr6 == context->Dr6 &&
+ amd64_thread_data()->dr7 == context->Dr7);
+
+ if (!self)
+ {
+ NTSTATUS ret = set_thread_context( handle, context, &self, IMAGE_FILE_MACHINE_I386 );
+ if (ret || !self) return ret;
+ if (flags & CONTEXT_I386_DEBUG_REGISTERS)
+ {
+ amd64_thread_data()->dr0 = context->Dr0;
+ amd64_thread_data()->dr1 = context->Dr1;
+ amd64_thread_data()->dr2 = context->Dr2;
+ amd64_thread_data()->dr3 = context->Dr3;
+ amd64_thread_data()->dr6 = context->Dr6;
+ amd64_thread_data()->dr7 = context->Dr7;
+ }
+ if (!(flags & ~CONTEXT_I386_DEBUG_REGISTERS)) return ret;
+ }
+
+ if (!(wow_frame = get_cpu_area( IMAGE_FILE_MACHINE_I386 ))) return STATUS_INVALID_PARAMETER;
+
+ if (flags & CONTEXT_I386_INTEGER)
+ {
+ wow_frame->Eax = context->Eax;
+ wow_frame->Ebx = context->Ebx;
+ wow_frame->Ecx = context->Ecx;
+ wow_frame->Edx = context->Edx;
+ wow_frame->Esi = context->Esi;
+ wow_frame->Edi = context->Edi;
+ }
+ if (flags & CONTEXT_I386_CONTROL)
+ {
+ wow_frame->Esp = context->Esp;
+ wow_frame->Ebp = context->Ebp;
+ wow_frame->Eip = context->Eip;
+ wow_frame->EFlags = context->EFlags;
+ wow_frame->SegCs = cs32_sel;
+ wow_frame->SegSs = ds64_sel;
+ }
+ if (flags & CONTEXT_I386_SEGMENTS)
+ {
+ wow_frame->SegDs = ds64_sel;
+ wow_frame->SegEs = ds64_sel;
+ wow_frame->SegFs = 0; /* FIXME */
+ wow_frame->SegGs = ds64_sel;
+ }
+ if (flags & CONTEXT_I386_DEBUG_REGISTERS)
+ {
+ wow_frame->Dr0 = context->Dr0;
+ wow_frame->Dr1 = context->Dr1;
+ wow_frame->Dr2 = context->Dr2;
+ wow_frame->Dr3 = context->Dr3;
+ wow_frame->Dr6 = context->Dr6;
+ wow_frame->Dr7 = context->Dr7;
+ }
+ if (flags & CONTEXT_I386_EXTENDED_REGISTERS)
+ {
+ memcpy( &frame->xsave, context->ExtendedRegisters, sizeof(frame->xsave) );
+ }
+ else if (flags & CONTEXT_I386_FLOATING_POINT)
+ {
+ fpu_to_fpux( &frame->xsave, &context->FloatSave );
+ }
+ if (flags & CONTEXT_I386_XSTATE)
+ {
+ CONTEXT_EX *context_ex = (CONTEXT_EX *)(context + 1);
+ XSTATE *xs = (XSTATE *)((char *)context_ex + context_ex->XState.Offset);
+
+ if (xs->Mask & XSTATE_MASK_GSSE)
+ {
+ frame->xstate.Mask |= XSTATE_MASK_GSSE;
+ memcpy( &frame->xstate.YmmContext, &xs->YmmContext, sizeof(xs->YmmContext) );
+ }
+ else frame->xstate.Mask &= ~XSTATE_MASK_GSSE;
+ frame->restore_flags |= CONTEXT_I386_XSTATE;
+ }
+ return STATUS_SUCCESS;
}
@@ -1863,10 +1951,96 @@ NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size )
*/
NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size )
{
- BOOL self;
+ DWORD needed_flags;
+ struct syscall_frame *frame = amd64_thread_data()->syscall_frame;
+ I386_CONTEXT *wow_frame, *context = ctx;
+ BOOL self = (handle == GetCurrentThread());
if (size != sizeof(I386_CONTEXT)) return STATUS_INFO_LENGTH_MISMATCH;
- return get_thread_context( handle, ctx, &self, IMAGE_FILE_MACHINE_I386 );
+
+ needed_flags = context->ContextFlags & ~CONTEXT_i386;
+
+ /* debug registers require a server call */
+ if (needed_flags & CONTEXT_I386_DEBUG_REGISTERS) self = FALSE;
+
+ if (!self)
+ {
+ NTSTATUS ret = get_thread_context( handle, context, &self, IMAGE_FILE_MACHINE_I386 );
+ if (ret || !self) return ret;
+ /* update the cached version of the debug registers */
+ if (needed_flags & CONTEXT_I386_DEBUG_REGISTERS)
+ {
+ amd64_thread_data()->dr0 = context->Dr0;
+ amd64_thread_data()->dr1 = context->Dr1;
+ amd64_thread_data()->dr2 = context->Dr2;
+ amd64_thread_data()->dr3 = context->Dr3;
+ amd64_thread_data()->dr6 = context->Dr6;
+ amd64_thread_data()->dr7 = context->Dr7;
+ }
+ if (!(needed_flags & ~CONTEXT_I386_DEBUG_REGISTERS)) return ret;
+ }
+
+ if (!(wow_frame = get_cpu_area( IMAGE_FILE_MACHINE_I386 ))) return STATUS_INVALID_PARAMETER;
+
+ if (needed_flags & CONTEXT_I386_INTEGER)
+ {
+ context->Eax = wow_frame->Eax;
+ context->Ebx = wow_frame->Ebx;
+ context->Ecx = wow_frame->Ecx;
+ context->Edx = wow_frame->Edx;
+ context->Esi = wow_frame->Esi;
+ context->Edi = wow_frame->Edi;
+ context->ContextFlags |= CONTEXT_I386_INTEGER;
+ }
+ if (needed_flags & CONTEXT_I386_CONTROL)
+ {
+ context->Esp = wow_frame->Esp;
+ context->Ebp = wow_frame->Ebp;
+ context->Eip = wow_frame->Eip;
+ context->EFlags = wow_frame->EFlags;
+ context->SegCs = wow_frame->SegCs;
+ context->SegSs = wow_frame->SegSs;
+ context->ContextFlags |= CONTEXT_I386_CONTROL;
+ }
+ if (needed_flags & CONTEXT_I386_SEGMENTS)
+ {
+ context->SegDs = wow_frame->SegDs;
+ context->SegEs = wow_frame->SegEs;
+ context->SegFs = wow_frame->SegFs;
+ context->SegGs = wow_frame->SegGs;
+ context->ContextFlags |= CONTEXT_I386_SEGMENTS;
+ }
+ if (needed_flags & CONTEXT_I386_EXTENDED_REGISTERS)
+ {
+ memcpy( context->ExtendedRegisters, &frame->xsave, sizeof(context->ExtendedRegisters) );
+ context->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS;
+ }
+ if (needed_flags & CONTEXT_I386_FLOATING_POINT)
+ {
+ fpux_to_fpu( &context->FloatSave, &frame->xsave );
+ context->ContextFlags |= CONTEXT_I386_FLOATING_POINT;
+ }
+ if ((needed_flags & CONTEXT_I386_XSTATE) && (cpu_info.ProcessorFeatureBits & CPU_FEATURE_AVX))
+ {
+ CONTEXT_EX *context_ex = (CONTEXT_EX *)(context + 1);
+ XSTATE *xstate = (XSTATE *)((char *)context_ex + context_ex->XState.Offset);
+ unsigned int mask;
+
+ if (context_ex->XState.Length < offsetof(XSTATE, YmmContext) ||
+ context_ex->XState.Length > sizeof(XSTATE))
+ return STATUS_INVALID_PARAMETER;
+
+ mask = (xstate_compaction_enabled ? xstate->CompactionMask : xstate->Mask) & XSTATE_MASK_GSSE;
+ xstate->Mask = frame->xstate.Mask & mask;
+ xstate->CompactionMask = xstate_compaction_enabled ? (0x8000000000000000 | mask) : 0;
+ memset( xstate->Reserved, 0, sizeof(xstate->Reserved) );
+ if (xstate->Mask)
+ {
+ if (context_ex->XState.Length < sizeof(XSTATE)) return STATUS_BUFFER_OVERFLOW;
+ memcpy( &xstate->YmmContext, &frame->xstate.YmmContext, sizeof(xstate->YmmContext) );
+ }
+ }
+ return STATUS_SUCCESS;
}
More information about the wine-cvs
mailing list