Module: wine Branch: master Commit: 881defc4b2b8a57f31c9cede0cc27b1f62336a91 URL: https://gitlab.winehq.org/wine/wine/-/commit/881defc4b2b8a57f31c9cede0cc27b1...
Author: Alexandre Julliard julliard@winehq.org Date: Fri Feb 24 11:46:11 2023 +0100
ntdll: Implement getting/setting the WoW context on ARM64.
---
dlls/ntdll/unix/signal_arm64.c | 213 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 209 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index ac16ae065b1..3855afc34f4 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -690,8 +690,9 @@ 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()); USHORT machine; + void *frame;
switch (size) { @@ -699,7 +700,112 @@ NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size ) case sizeof(ARM_CONTEXT): machine = IMAGE_FILE_MACHINE_ARMNT; break; default: return STATUS_INFO_LENGTH_MISMATCH; } - return set_thread_context( handle, ctx, &self, machine ); + + if (!self) + { + NTSTATUS ret = set_thread_context( handle, ctx, &self, machine ); + if (ret || !self) return ret; + } + + if (!(frame = get_cpu_area( machine ))) return STATUS_INVALID_PARAMETER; + + switch (machine) + { + case IMAGE_FILE_MACHINE_I386: + { + I386_CONTEXT *wow_frame = frame; + const I386_CONTEXT *context = ctx; + DWORD flags = context->ContextFlags & ~CONTEXT_i386; + + 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) + { + WOW64_CPURESERVED *cpu = NtCurrentTeb()->TlsSlots[WOW64_TLS_CPURESERVED]; + + wow_frame->Esp = context->Esp; + wow_frame->Ebp = context->Ebp; + wow_frame->Eip = context->Eip; + wow_frame->EFlags = context->EFlags; + wow_frame->SegCs = context->SegCs; + wow_frame->SegSs = context->SegSs; + cpu->Flags |= WOW64_CPURESERVED_FLAG_RESET_STATE; + } + if (flags & CONTEXT_I386_SEGMENTS) + { + wow_frame->SegDs = context->SegDs; + wow_frame->SegEs = context->SegEs; + wow_frame->SegFs = context->SegFs; + wow_frame->SegGs = context->SegGs; + } + 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( &wow_frame->ExtendedRegisters, context->ExtendedRegisters, sizeof(context->ExtendedRegisters) ); + } + if (flags & CONTEXT_I386_FLOATING_POINT) + { + memcpy( &wow_frame->FloatSave, &context->FloatSave, sizeof(context->FloatSave) ); + } + /* FIXME: CONTEXT_I386_XSTATE */ + break; + } + + case IMAGE_FILE_MACHINE_ARMNT: + { + ARM_CONTEXT *wow_frame = frame; + const ARM_CONTEXT *context = ctx; + DWORD flags = context->ContextFlags & ~CONTEXT_ARM; + + if (flags & CONTEXT_INTEGER) + { + wow_frame->R0 = context->R0; + wow_frame->R1 = context->R1; + wow_frame->R2 = context->R2; + wow_frame->R3 = context->R3; + wow_frame->R4 = context->R4; + wow_frame->R5 = context->R5; + wow_frame->R6 = context->R6; + wow_frame->R7 = context->R7; + wow_frame->R8 = context->R8; + wow_frame->R9 = context->R9; + wow_frame->R10 = context->R10; + wow_frame->R11 = context->R11; + wow_frame->R12 = context->R12; + } + if (flags & CONTEXT_CONTROL) + { + wow_frame->Sp = context->Sp; + wow_frame->Lr = context->Lr; + wow_frame->Pc = context->Pc & ~1; + wow_frame->Cpsr = context->Cpsr; + if (context->Cpsr & 0x20) wow_frame->Pc |= 1; /* thumb */ + } + if (flags & CONTEXT_FLOATING_POINT) + { + wow_frame->Fpscr = context->Fpscr; + memcpy( wow_frame->u.D, context->u.D, sizeof(context->u.D) ); + } + break; + } + + } + return STATUS_SUCCESS; }
@@ -708,8 +814,9 @@ 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; + BOOL self = (handle == GetCurrentThread()); USHORT machine; + void *frame;
switch (size) { @@ -717,7 +824,105 @@ NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size ) case sizeof(ARM_CONTEXT): machine = IMAGE_FILE_MACHINE_ARMNT; break; default: return STATUS_INFO_LENGTH_MISMATCH; } - return get_thread_context( handle, ctx, &self, machine ); + + if (!self) + { + NTSTATUS ret = get_thread_context( handle, ctx, &self, machine ); + if (ret || !self) return ret; + } + + if (!(frame = get_cpu_area( machine ))) return STATUS_INVALID_PARAMETER; + + switch (machine) + { + case IMAGE_FILE_MACHINE_I386: + { + I386_CONTEXT *wow_frame = frame, *context = ctx; + DWORD needed_flags = context->ContextFlags & ~CONTEXT_i386; + + 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, &wow_frame->ExtendedRegisters, sizeof(context->ExtendedRegisters) ); + context->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS; + } + if (needed_flags & CONTEXT_I386_FLOATING_POINT) + { + memcpy( &context->FloatSave, &wow_frame->FloatSave, sizeof(context->FloatSave) ); + context->ContextFlags |= CONTEXT_I386_FLOATING_POINT; + } + /* FIXME: CONTEXT_I386_XSTATE */ + break; + } + + case IMAGE_FILE_MACHINE_ARMNT: + { + ARM_CONTEXT *wow_frame = frame, *context = ctx; + DWORD needed_flags = context->ContextFlags & ~CONTEXT_ARM; + + if (needed_flags & CONTEXT_INTEGER) + { + context->R0 = wow_frame->R0; + context->R1 = wow_frame->R1; + context->R2 = wow_frame->R2; + context->R3 = wow_frame->R3; + context->R4 = wow_frame->R4; + context->R5 = wow_frame->R5; + context->R6 = wow_frame->R6; + context->R7 = wow_frame->R7; + context->R8 = wow_frame->R8; + context->R9 = wow_frame->R9; + context->R10 = wow_frame->R10; + context->R11 = wow_frame->R11; + context->R12 = wow_frame->R12; + context->ContextFlags |= CONTEXT_INTEGER; + } + if (needed_flags & CONTEXT_CONTROL) + { + context->Sp = wow_frame->Sp; + context->Lr = wow_frame->Lr; + context->Pc = wow_frame->Pc; + context->Cpsr = wow_frame->Cpsr; + context->ContextFlags |= CONTEXT_CONTROL; + } + if (needed_flags & CONTEXT_FLOATING_POINT) + { + context->Fpscr = wow_frame->Fpscr; + memcpy( context->u.D, wow_frame->u.D, sizeof(wow_frame->u.D) ); + context->ContextFlags |= CONTEXT_FLOATING_POINT; + } + break; + } + + } + return STATUS_SUCCESS; }