Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- With code essentially copied from ntdll. As far as I can tell there is no ntdll entry point for this function.
dlls/kernel32/kernel32.spec | 2 +- dlls/kernel32/thread.c | 131 ++++++++++++++++++++++++++++++++++++++++++++ include/winbase.h | 1 + 3 files changed, 133 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 9ed5dfb..1cb0b54 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1600,7 +1600,7 @@ @ stdcall WinExec(str long) @ stdcall Wow64EnableWow64FsRedirection(long) @ stdcall Wow64DisableWow64FsRedirection(ptr) -# @ stub Wow64GetThreadContext +@ stdcall Wow64GetThreadContext(long ptr) # @ stub Wow64GetThreadSelectorEntry @ stdcall Wow64RevertWow64FsRedirection(ptr) # @ stub Wow64SetThreadContext diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c index b6ca9f260..caeec63 100644 --- a/dlls/kernel32/thread.c +++ b/dlls/kernel32/thread.c @@ -251,6 +251,137 @@ BOOL WINAPI GetThreadContext( HANDLE handle, /* [in] Handle to thread with }
+/* convert CPU-specific flags to generic server flags */ +static inline unsigned int wow64_get_server_context_flags( DWORD flags ) +{ + unsigned int ret = 0; + + flags &= 0x3f; /* mask CPU id flags */ + if (flags & WOW64_CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL; + if (flags & WOW64_CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER; + if (flags & WOW64_CONTEXT_SEGMENTS) ret |= SERVER_CTX_SEGMENTS; + if (flags & WOW64_CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT; + if (flags & WOW64_CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS; + if (flags & WOW64_CONTEXT_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS; + return ret; +} + +static NTSTATUS wow64_context_from_server( WOW64_CONTEXT *to, const context_t *from ) +{ + if (from->cpu != CPU_x86) return STATUS_INVALID_PARAMETER; + + to->ContextFlags = WOW64_CONTEXT_i386; + if (from->flags & SERVER_CTX_CONTROL) + { + to->ContextFlags |= WOW64_CONTEXT_CONTROL; + to->Ebp = from->ctl.i386_regs.ebp; + to->Esp = from->ctl.i386_regs.esp; + to->Eip = from->ctl.i386_regs.eip; + to->SegCs = from->ctl.i386_regs.cs; + to->SegSs = from->ctl.i386_regs.ss; + to->EFlags = from->ctl.i386_regs.eflags; + } + if (from->flags & SERVER_CTX_INTEGER) + { + to->ContextFlags |= WOW64_CONTEXT_INTEGER; + to->Eax = from->integer.i386_regs.eax; + to->Ebx = from->integer.i386_regs.ebx; + to->Ecx = from->integer.i386_regs.ecx; + to->Edx = from->integer.i386_regs.edx; + to->Esi = from->integer.i386_regs.esi; + to->Edi = from->integer.i386_regs.edi; + } + if (from->flags & SERVER_CTX_SEGMENTS) + { + to->ContextFlags |= WOW64_CONTEXT_SEGMENTS; + to->SegDs = from->seg.i386_regs.ds; + to->SegEs = from->seg.i386_regs.es; + to->SegFs = from->seg.i386_regs.fs; + to->SegGs = from->seg.i386_regs.gs; + } + if (from->flags & SERVER_CTX_FLOATING_POINT) + { + to->ContextFlags |= WOW64_CONTEXT_FLOATING_POINT; + to->FloatSave.ControlWord = from->fp.i386_regs.ctrl; + to->FloatSave.StatusWord = from->fp.i386_regs.status; + to->FloatSave.TagWord = from->fp.i386_regs.tag; + to->FloatSave.ErrorOffset = from->fp.i386_regs.err_off; + to->FloatSave.ErrorSelector = from->fp.i386_regs.err_sel; + to->FloatSave.DataOffset = from->fp.i386_regs.data_off; + to->FloatSave.DataSelector = from->fp.i386_regs.data_sel; + to->FloatSave.Cr0NpxState = from->fp.i386_regs.cr0npx; + memcpy( to->FloatSave.RegisterArea, from->fp.i386_regs.regs, sizeof(to->FloatSave.RegisterArea) ); + } + if (from->flags & SERVER_CTX_DEBUG_REGISTERS) + { + to->ContextFlags |= WOW64_CONTEXT_DEBUG_REGISTERS; + to->Dr0 = from->debug.i386_regs.dr0; + to->Dr1 = from->debug.i386_regs.dr1; + to->Dr2 = from->debug.i386_regs.dr2; + to->Dr3 = from->debug.i386_regs.dr3; + to->Dr6 = from->debug.i386_regs.dr6; + to->Dr7 = from->debug.i386_regs.dr7; + } + if (from->flags & SERVER_CTX_EXTENDED_REGISTERS) + { + to->ContextFlags |= WOW64_CONTEXT_EXTENDED_REGISTERS; + memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) ); + } + return STATUS_SUCCESS; +} + +/*********************************************************************** + * Wow64GetThreadContext [KERNEL32.@] + */ +BOOL WINAPI Wow64GetThreadContext( HANDLE handle, WOW64_CONTEXT *context) +{ + unsigned int server_flags = wow64_get_server_context_flags( context->ContextFlags ); + context_t server_context; + DWORD dummy, i; + NTSTATUS ret; + + SERVER_START_REQ( get_thread_context ) + { + req->handle = wine_server_obj_handle( handle ); + req->flags = server_flags; + req->suspend = 1; + wine_server_set_reply( req, &server_context, sizeof(server_context) ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + + if (ret == STATUS_PENDING) + { + for (i = 0; i < 100; i++) + { + SERVER_START_REQ( get_thread_context ) + { + req->handle = wine_server_obj_handle( handle ); + req->flags = server_flags; + req->suspend = 0; + wine_server_set_reply( req, &server_context, sizeof(server_context) ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + if (ret == STATUS_PENDING) + { + LARGE_INTEGER timeout; + timeout.QuadPart = -10000; + NtDelayExecution( FALSE, &timeout ); + } + else break; + } + NtResumeThread( handle, &dummy ); + if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED; + } + + if (!ret) ret = wow64_context_from_server( context, &server_context ); + + if (ret) SetLastError( RtlNtStatusToDosError( ret ) ); + return !ret; +} + + /********************************************************************** * SuspendThread [KERNEL32.@] Suspends a thread. * diff --git a/include/winbase.h b/include/winbase.h index 4ddc1d3..f7239b8 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -2706,6 +2706,7 @@ WINBASEAPI VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE); WINBASEAPI UINT WINAPI WinExec(LPCSTR,UINT); WINBASEAPI BOOL WINAPI Wow64DisableWow64FsRedirection(PVOID*); WINBASEAPI BOOLEAN WINAPI Wow64EnableWow64FsRedirection(BOOLEAN); +WINBASEAPI BOOL WINAPI Wow64GetThreadContext(HANDLE, WOW64_CONTEXT *); WINBASEAPI BOOL WINAPI Wow64RevertWow64FsRedirection(PVOID); WINADVAPI DWORD WINAPI WriteEncryptedFileRaw(PFE_IMPORT_FUNC,PVOID,PVOID); WINBASEAPI BOOL WINAPI WriteFile(HANDLE,LPCVOID,DWORD,LPDWORD,LPOVERLAPPED);