Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- include/winnt.h | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+)
diff --git a/include/winnt.h b/include/winnt.h index 54bf11d..c41eff4 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -2112,6 +2112,96 @@ typedef CONTEXT *PCONTEXT;
NTSYSAPI void WINAPI RtlCaptureContext(CONTEXT*);
+#define WOW64_CONTEXT_i386 0x00010000 +#define WOW64_CONTEXT_i486 0x00010000 +#define WOW64_CONTEXT_CONTROL (WOW64_CONTEXT_i386 | __MSABI_LONG(0x00000001)) +#define WOW64_CONTEXT_INTEGER (WOW64_CONTEXT_i386 | __MSABI_LONG(0x00000002)) +#define WOW64_CONTEXT_SEGMENTS (WOW64_CONTEXT_i386 | __MSABI_LONG(0x00000004)) +#define WOW64_CONTEXT_FLOATING_POINT (WOW64_CONTEXT_i386 | __MSABI_LONG(0x00000008)) +#define WOW64_CONTEXT_DEBUG_REGISTERS (WOW64_CONTEXT_i386 | __MSABI_LONG(0x00000010)) +#define WOW64_CONTEXT_EXTENDED_REGISTERS (WOW64_CONTEXT_i386 | __MSABI_LONG(0x00000020)) +#define WOW64_CONTEXT_FULL (WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | WOW64_CONTEXT_SEGMENTS) +#define WOW64_CONTEXT_ALL (WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | \ + WOW64_CONTEXT_SEGMENTS | WOW64_CONTEXT_FLOATING_POINT | \ + WOW64_CONTEXT_DEBUG_REGISTERS | WOW64_CONTEXT_EXTENDED_REGISTERS) + +#define WOW64_CONTEXT_XSTATE (WOW64_CONTEXT_i386 | __MSABI_LONG(0x00000040)) + +#define WOW64_CONTEXT_EXCEPTION_ACTIVE 0x08000000 +#define WOW64_CONTEXT_SERVICE_ACTIVE 0x10000000 +#define WOW64_CONTEXT_EXCEPTION_REQUEST 0x40000000 +#define WOW64_CONTEXT_EXCEPTION_REPORTING 0x80000000 + +#define WOW64_SIZE_OF_80387_REGISTERS 80 +#define WOW64_MAXIMUM_SUPPORTED_EXTENSION 512 + +typedef struct _WOW64_FLOATING_SAVE_AREA { + DWORD ControlWord; + DWORD StatusWord; + DWORD TagWord; + DWORD ErrorOffset; + DWORD ErrorSelector; + DWORD DataOffset; + DWORD DataSelector; + BYTE RegisterArea[WOW64_SIZE_OF_80387_REGISTERS]; + DWORD Cr0NpxState; +} WOW64_FLOATING_SAVE_AREA, *PWOW64_FLOATING_SAVE_AREA; + +#include "pshpack4.h" +typedef struct _WOW64_CONTEXT { + DWORD ContextFlags; + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr6; + DWORD Dr7; + WOW64_FLOATING_SAVE_AREA FloatSave; + DWORD SegGs; + DWORD SegFs; + DWORD SegEs; + DWORD SegDs; + DWORD Edi; + DWORD Esi; + DWORD Ebx; + DWORD Edx; + DWORD Ecx; + DWORD Eax; + DWORD Ebp; + DWORD Eip; + DWORD SegCs; + DWORD EFlags; + DWORD Esp; + DWORD SegSs; + BYTE ExtendedRegisters[WOW64_MAXIMUM_SUPPORTED_EXTENSION]; +} WOW64_CONTEXT, *PWOW64_CONTEXT; +#include "poppack.h" + +typedef struct _WOW64_LDT_ENTRY { + WORD LimitLow; + WORD BaseLow; + union { + struct { + BYTE BaseMid; + BYTE Flags1; + BYTE Flags2; + BYTE BaseHi; + } Bytes; + struct { + DWORD BaseMid : 8; + DWORD Type : 5; + DWORD Dpl : 2; + DWORD Pres : 1; + DWORD LimitHi : 4; + DWORD Sys : 1; + DWORD Reserved_0 : 1; + DWORD Default_Big : 1; + DWORD Granularity : 1; + DWORD BaseHi : 8; + } Bits; + } HighWord; +} WOW64_LDT_ENTRY, *PWOW64_LDT_ENTRY; + /* * Product types */
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);
Zebediah Figura zfigura@codeweavers.com writes:
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.
RtlWow64GetThreadContext() is probably what you are looking for. It will need some test cases obviously.
On 06/06/2018 09:34 AM, Alexandre Julliard wrote:
Zebediah Figura zfigura@codeweavers.com writes:
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.
RtlWow64GetThreadContext() is probably what you are looking for. It will need some test cases obviously.
Thanks; I can see I was looking in the wrong place. I've sent updated patches.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/kernel32/kernel32.spec | 2 +- dlls/kernel32/thread.c | 116 ++++++++++++++++++++++++++++++++++++++++++++ include/winbase.h | 1 + 3 files changed, 118 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 1cb0b54..de6f007 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1603,7 +1603,7 @@ @ stdcall Wow64GetThreadContext(long ptr) # @ stub Wow64GetThreadSelectorEntry @ stdcall Wow64RevertWow64FsRedirection(ptr) -# @ stub Wow64SetThreadContext +@ stdcall Wow64SetThreadContext(long ptr) # @ stub Wow64SuspendThread @ stdcall WriteConsoleA(long ptr long ptr ptr) @ stdcall WriteConsoleInputA(long ptr long ptr) diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c index caeec63..838cf0f 100644 --- a/dlls/kernel32/thread.c +++ b/dlls/kernel32/thread.c @@ -235,6 +235,122 @@ BOOL WINAPI SetThreadContext( HANDLE handle, /* [in] Handle to thread }
+static NTSTATUS wow64_context_to_server( context_t *to, const WOW64_CONTEXT *from ) +{ + DWORD flags = from->ContextFlags & ~WOW64_CONTEXT_i386; /* get rid of CPU id */ + + memset( to, 0, sizeof(*to) ); + to->cpu = CPU_x86; + + if (flags & WOW64_CONTEXT_CONTROL) + { + to->flags |= SERVER_CTX_CONTROL; + to->ctl.i386_regs.ebp = from->Ebp; + to->ctl.i386_regs.esp = from->Esp; + to->ctl.i386_regs.eip = from->Eip; + to->ctl.i386_regs.cs = from->SegCs; + to->ctl.i386_regs.ss = from->SegSs; + to->ctl.i386_regs.eflags = from->EFlags; + } + if (flags & WOW64_CONTEXT_INTEGER) + { + to->flags |= SERVER_CTX_INTEGER; + to->integer.i386_regs.eax = from->Eax; + to->integer.i386_regs.ebx = from->Ebx; + to->integer.i386_regs.ecx = from->Ecx; + to->integer.i386_regs.edx = from->Edx; + to->integer.i386_regs.esi = from->Esi; + to->integer.i386_regs.edi = from->Edi; + } + if (flags & WOW64_CONTEXT_SEGMENTS) + { + to->flags |= SERVER_CTX_SEGMENTS; + to->seg.i386_regs.ds = from->SegDs; + to->seg.i386_regs.es = from->SegEs; + to->seg.i386_regs.fs = from->SegFs; + to->seg.i386_regs.gs = from->SegGs; + } + if (flags & WOW64_CONTEXT_FLOATING_POINT) + { + to->flags |= SERVER_CTX_FLOATING_POINT; + to->fp.i386_regs.ctrl = from->FloatSave.ControlWord; + to->fp.i386_regs.status = from->FloatSave.StatusWord; + to->fp.i386_regs.tag = from->FloatSave.TagWord; + to->fp.i386_regs.err_off = from->FloatSave.ErrorOffset; + to->fp.i386_regs.err_sel = from->FloatSave.ErrorSelector; + to->fp.i386_regs.data_off = from->FloatSave.DataOffset; + to->fp.i386_regs.data_sel = from->FloatSave.DataSelector; + to->fp.i386_regs.cr0npx = from->FloatSave.Cr0NpxState; + memcpy( to->fp.i386_regs.regs, from->FloatSave.RegisterArea, sizeof(to->fp.i386_regs.regs) ); + } + if (flags & WOW64_CONTEXT_DEBUG_REGISTERS) + { + to->flags |= SERVER_CTX_DEBUG_REGISTERS; + to->debug.i386_regs.dr0 = from->Dr0; + to->debug.i386_regs.dr1 = from->Dr1; + to->debug.i386_regs.dr2 = from->Dr2; + to->debug.i386_regs.dr3 = from->Dr3; + to->debug.i386_regs.dr6 = from->Dr6; + to->debug.i386_regs.dr7 = from->Dr7; + } + if (flags & WOW64_CONTEXT_EXTENDED_REGISTERS) + { + to->flags |= SERVER_CTX_EXTENDED_REGISTERS; + memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) ); + } + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * Wow64GetThreadContext [KERNEL32.@] + */ +BOOL WINAPI Wow64SetThreadContext( HANDLE handle, const WOW64_CONTEXT *context) +{ + NTSTATUS ret; + DWORD dummy, i; + context_t server_context; + + wow64_context_to_server( &server_context, context ); + + SERVER_START_REQ( set_thread_context ) + { + req->handle = wine_server_obj_handle( handle ); + req->suspend = 1; + wine_server_add_data( 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( set_thread_context ) + { + req->handle = wine_server_obj_handle( handle ); + req->suspend = 0; + wine_server_add_data( 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) SetLastError( RtlNtStatusToDosError( ret ) ); + return !ret; +} + + /*********************************************************************** * GetThreadContext [KERNEL32.@] Retrieves context of thread. * diff --git a/include/winbase.h b/include/winbase.h index f7239b8..667df96 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -2708,6 +2708,7 @@ WINBASEAPI BOOL WINAPI Wow64DisableWow64FsRedirection(PVOID*); WINBASEAPI BOOLEAN WINAPI Wow64EnableWow64FsRedirection(BOOLEAN); WINBASEAPI BOOL WINAPI Wow64GetThreadContext(HANDLE, WOW64_CONTEXT *); WINBASEAPI BOOL WINAPI Wow64RevertWow64FsRedirection(PVOID); +WINBASEAPI BOOL WINAPI Wow64SetThreadContext(HANDLE, const WOW64_CONTEXT *); WINADVAPI DWORD WINAPI WriteEncryptedFileRaw(PFE_IMPORT_FUNC,PVOID,PVOID); WINBASEAPI BOOL WINAPI WriteFile(HANDLE,LPCVOID,DWORD,LPDWORD,LPOVERLAPPED); WINBASEAPI BOOL WINAPI WriteFileEx(HANDLE,LPCVOID,DWORD,LPOVERLAPPED,LPOVERLAPPED_COMPLETION_ROUTINE);