[PATCH v3 2/5] ntdll: Implement RtlWow64GetThreadContext().

Zebediah Figura zfigura at codeweavers.com
Wed Jun 6 13:30:17 CDT 2018


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
v3: fix test failures on Vista

 dlls/ntdll/ntdll.spec        |   1 +
 dlls/ntdll/tests/exception.c |  36 ++++++++++++++
 dlls/ntdll/thread.c          | 114 ++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 143 insertions(+), 8 deletions(-)

diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index c0f5d6f..f1dd6ed 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -977,6 +977,7 @@
 @ stdcall RtlWalkHeap(long ptr)
 @ stdcall RtlWow64EnableFsRedirection(long)
 @ stdcall RtlWow64EnableFsRedirectionEx(long ptr)
+@ stdcall -arch=win64 RtlWow64GetThreadContext(long ptr)
 @ stub RtlWriteMemoryStream
 @ stdcall RtlWriteRegistryValue(long ptr ptr long ptr long)
 @ stub RtlZeroHeap
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index c47c8cb..9310297 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -149,6 +149,7 @@ static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UN
 static EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64, CONTEXT*, DISPATCHER_CONTEXT*);
 static VOID      (WINAPI *pRtlCaptureContext)(CONTEXT*);
 static VOID      (CDECL *pRtlRestoreContext)(CONTEXT*, EXCEPTION_RECORD*);
+static NTSTATUS  (WINAPI *pRtlWow64GetThreadContext)(HANDLE, WOW64_CONTEXT *);
 static VOID      (CDECL *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, CONTEXT*, UNWIND_HISTORY_TABLE*);
 static int       (CDECL *p_setjmp)(_JUMP_BUFFER*);
 #endif
@@ -2490,6 +2491,38 @@ static void test_dpe_exceptions(void)
     pRtlRemoveVectoredExceptionHandler(handler);
 }
 
+static void test_wow64_context(void)
+{
+    char cmdline[] = "C:\\windows\\syswow64\\notepad.exe";
+    PROCESS_INFORMATION pi;
+    STARTUPINFOA si = {0};
+    WOW64_CONTEXT ctx;
+    NTSTATUS ret;
+
+    memset(&ctx, 0x55, sizeof(ctx));
+    ctx.ContextFlags = WOW64_CONTEXT_ALL;
+    ret = pRtlWow64GetThreadContext( GetCurrentThread(), &ctx );
+    ok(ret == STATUS_INVALID_PARAMETER || broken(ret == STATUS_PARTIAL_COPY), "got %#x\n", ret);
+
+    CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
+
+    ret = pRtlWow64GetThreadContext( pi.hThread, &ctx );
+    ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+    ok(ctx.ContextFlags == WOW64_CONTEXT_ALL, "got context flags %#x\n", ctx.ContextFlags);
+    ok(!ctx.Ebp, "got ebp %08x\n", ctx.Ebp);
+    ok(!ctx.Ecx, "got ecx %08x\n", ctx.Ecx);
+    ok(!ctx.Edx, "got edx %08x\n", ctx.Edx);
+    ok(!ctx.Esi, "got esi %08x\n", ctx.Esi);
+    ok(!ctx.Edi, "got edi %08x\n", ctx.Edi);
+    ok((ctx.EFlags & ~2) == 0x200, "got eflags %08x\n", ctx.EFlags);
+    ok((WORD) ctx.FloatSave.ControlWord == 0x27f, "got control word %08x\n",
+        ctx.FloatSave.ControlWord);
+    ok(*(WORD *)ctx.ExtendedRegisters == 0x27f, "got SSE control word %04x\n",
+       *(WORD *)ctx.ExtendedRegisters);
+
+    pNtTerminateProcess(pi.hProcess, 0);
+}
+
 #endif  /* __x86_64__ */
 
 #if defined(__i386__) || defined(__x86_64__)
@@ -3128,6 +3161,8 @@ START_TEST(exception)
                                                                  "RtlRestoreContext" );
     pRtlUnwindEx                       = (void *)GetProcAddress( hntdll,
                                                                  "RtlUnwindEx" );
+    pRtlWow64GetThreadContext          = (void *)GetProcAddress( hntdll,
+                                                                 "RtlWow64GetThreadContext" );
     p_setjmp                           = (void *)GetProcAddress( hmsvcrt,
                                                                  "_setjmp" );
 
@@ -3143,6 +3178,7 @@ START_TEST(exception)
     test_restore_context();
     test_prot_fault();
     test_dpe_exceptions();
+    test_wow64_context();
 
     if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
       test_dynamic_unwind();
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 35e23d2..df04b33 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -924,22 +924,18 @@ static inline unsigned int get_server_context_flags( DWORD flags )
     return ret;
 }
 
-/***********************************************************************
- *              get_thread_context
- */
-NTSTATUS get_thread_context( HANDLE handle, CONTEXT *context, BOOL *self )
+static NTSTATUS get_server_context( HANDLE handle, unsigned int server_flags,
+                                    context_t *context, BOOL *self )
 {
     NTSTATUS ret;
     DWORD dummy, i;
-    unsigned int server_flags = get_server_context_flags( context->ContextFlags );
-    context_t server_context;
 
     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) );
+        wine_server_set_reply( req, context, sizeof(*context) );
         ret = wine_server_call( req );
         *self = reply->self;
     }
@@ -954,7 +950,7 @@ NTSTATUS get_thread_context( HANDLE handle, CONTEXT *context, BOOL *self )
                 req->handle  = wine_server_obj_handle( handle );
                 req->flags   = server_flags;
                 req->suspend = 0;
-                wine_server_set_reply( req, &server_context, sizeof(server_context) );
+                wine_server_set_reply( req, context, sizeof(*context) );
                 ret = wine_server_call( req );
             }
             SERVER_END_REQ;
@@ -969,10 +965,112 @@ NTSTATUS get_thread_context( HANDLE handle, CONTEXT *context, BOOL *self )
         NtResumeThread( handle, &dummy );
         if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
     }
+    return ret;
+}
+
+NTSTATUS get_thread_context( HANDLE handle, CONTEXT *context, BOOL *self)
+{
+    context_t server_context;
+    unsigned int server_flags = get_server_context_flags( context->ContextFlags );
+    NTSTATUS ret = get_server_context( handle, server_flags, &server_context, self);
     if (!ret) ret = context_from_server( context, &server_context );
     return ret;
 }
 
+#ifdef _WIN64
+/* 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;
+}
+
+
+/******************************************************************************
+ *              RtlWow64GetThreadContext  (NTDLL.@)
+ */
+NTSTATUS WINAPI RtlWow64GetThreadContext( HANDLE handle, WOW64_CONTEXT *context )
+{
+    BOOL self;
+    context_t server_context;
+    unsigned int server_flags = wow64_get_server_context_flags( context->ContextFlags );
+    NTSTATUS ret = get_server_context( handle, server_flags, &server_context, &self );
+    if (!ret) ret = wow64_context_from_server( context, &server_context );
+    return ret;
+}
+#endif
 
 /******************************************************************************
  *              NtQueryInformationThread  (NTDLL.@)
-- 
2.7.4




More information about the wine-devel mailing list