[PATCH 2/3] kernel32: Implement Wow64GetThreadContext().

Zebediah Figura zfigura at codeweavers.com
Tue Jun 5 18:39:07 CDT 2018


Signed-off-by: Zebediah Figura <zfigura at 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);
-- 
2.7.4




More information about the wine-devel mailing list