[PATCH 2/3] ntdll/tests: Test getting and setting AVX registers for the other thread.

Paul Gofman pgofman at codeweavers.com
Fri Oct 9 08:03:55 CDT 2020


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/ntdll/tests/exception.c | 362 ++++++++++++++++++++++++-----------
 1 file changed, 253 insertions(+), 109 deletions(-)

diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index 66dbe8089c3..07b813ac1fa 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -6423,6 +6423,172 @@ done:
     return ExceptionContinueExecution;
 }
 
+struct call_func_offsets
+{
+    unsigned int func_addr;
+    unsigned int func_param1;
+    unsigned int func_param2;
+    unsigned int ymm0_save;
+};
+#ifdef __x86_64__
+static BYTE call_func_code_set_ymm0[] =
+{
+    0x55,                         /* pushq %rbp */
+    0x48, 0xb8,                   /* mov imm,%rax */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    0x48, 0xb9,                   /* mov imm,%rcx */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    0x48, 0xba,                   /* mov imm,%rdx */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    0x48, 0xbd,                   /* mov imm,%rbp */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    0xc5, 0xfc, 0x10, 0x45, 0x00, /* vmovups (%rbp),%ymm0 */
+    0x48, 0x83, 0xec, 0x20,       /* sub $0x20,%rsp */
+    0xff, 0xd0,                   /* call *rax */
+    0x48, 0x83, 0xc4, 0x20,       /* add $0x20,%rsp */
+    0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%rbp) */
+    0x5d,                         /* popq %rbp */
+    0xc3,                         /* ret  */
+};
+static BYTE call_func_code_reset_ymm_state[] =
+{
+    0x55,                         /* pushq %rbp */
+    0x48, 0xb8,                   /* mov imm,%rax */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    0x48, 0xb9,                   /* mov imm,%rcx */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    0x48, 0xba,                   /* mov imm,%rdx */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    0x48, 0xbd,                   /* mov imm,%rbp */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+    0xc5, 0xf8, 0x77,             /* vzeroupper */
+    0x0f, 0x57, 0xc0,             /* xorps  %xmm0,%xmm0 */
+    0x48, 0x83, 0xec, 0x20,       /* sub $0x20,%rsp */
+    0xff, 0xd0,                   /* call *rax */
+    0x48, 0x83, 0xc4, 0x20,       /* add $0x20,%rsp */
+    0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%rbp) */
+    0x5d,                         /* popq %rbp */
+    0xc3,                         /* ret  */
+};
+static const struct call_func_offsets call_func_offsets = {3, 13, 23, 33};
+#else
+static BYTE call_func_code_set_ymm0[] =
+{
+    0x55,                         /* pushl %ebp */
+    0xb8,                         /* mov imm,%eax */
+    0x00, 0x00, 0x00, 0x00,
+
+    0xb9,                         /* mov imm,%ecx */
+    0x00, 0x00, 0x00, 0x00,
+
+    0xba,                         /* mov imm,%edx */
+    0x00, 0x00, 0x00, 0x00,
+
+    0xbd,                         /* mov imm,%ebp */
+    0x00, 0x00, 0x00, 0x00,
+
+    0x81, 0xfa, 0xef, 0xbe, 0xad, 0xde,
+                                  /* cmpl $0xdeadbeef, %edx */
+    0x74, 0x01,                   /* je 1f */
+    0x52,                         /* pushl %edx */
+    0x51,                         /* 1: pushl %ecx */
+    0xc5, 0xfc, 0x10, 0x45, 0x00, /* vmovups (%ebp),%ymm0 */
+    0xff, 0xd0,                   /* call *eax */
+    0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%ebp) */
+    0x5d,                         /* popl %ebp */
+    0xc3,                         /* ret  */
+};
+static BYTE call_func_code_reset_ymm_state[] =
+{
+    0x55,                         /* pushl %ebp */
+    0xb8,                         /* mov imm,%eax */
+    0x00, 0x00, 0x00, 0x00,
+
+    0xb9,                         /* mov imm,%ecx */
+    0x00, 0x00, 0x00, 0x00,
+
+    0xba,                         /* mov imm,%edx */
+    0x00, 0x00, 0x00, 0x00,
+
+    0xbd,                         /* mov imm,%ebp */
+    0x00, 0x00, 0x00, 0x00,
+
+    0x81, 0xfa, 0xef, 0xbe, 0xad, 0xde,
+                                  /* cmpl $0xdeadbeef, %edx */
+    0x74, 0x01,                   /* je 1f */
+    0x52,                         /* pushl %edx */
+    0x51,                         /* 1: pushl %ecx */
+    0xc5, 0xf8, 0x77,             /* vzeroupper */
+    0x0f, 0x57, 0xc0,             /* xorps  %xmm0,%xmm0 */
+    0xff, 0xd0,                   /* call *eax */
+    0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%ebp) */
+    0x5d,                         /* popl %ebp */
+    0xc3,                         /* ret  */
+};
+static const struct call_func_offsets call_func_offsets = {2, 7, 12, 17};
+#endif
+
+static DWORD WINAPI test_extended_context_thread(void *arg)
+{
+    ULONG (WINAPI* func)(void) = code_mem;
+    static unsigned int data[8];
+    unsigned int i;
+
+    memcpy(code_mem, call_func_code_reset_ymm_state, sizeof(call_func_code_reset_ymm_state));
+    *(void **)((BYTE *)code_mem + call_func_offsets.func_addr) = SuspendThread;
+    *(void **)((BYTE *)code_mem + call_func_offsets.func_param1) = (void *)GetCurrentThread();
+    *(void **)((BYTE *)code_mem + call_func_offsets.func_param2) = (void *)0xdeadbeef;
+    *(void **)((BYTE *)code_mem + call_func_offsets.ymm0_save) = data;
+    func();
+
+    for (i = 0; i < 4; ++i)
+        ok(!data[i], "Got unexpected data %#x, i %u.\n", data[i], i);
+    for (; i < 8; ++i)
+        ok(data[i] == 0x48484848, "Got unexpected data %#x, i %u.\n", data[i], i);
+    memset(data, 0x68, sizeof(data));
+
+    memcpy(code_mem, call_func_code_set_ymm0, sizeof(call_func_code_set_ymm0));
+    *(void **)((BYTE *)code_mem + call_func_offsets.func_addr) = SuspendThread;
+    *(void **)((BYTE *)code_mem + call_func_offsets.func_param1) = (void *)GetCurrentThread();
+    *(void **)((BYTE *)code_mem + call_func_offsets.func_param2) = (void *)0xdeadbeef;
+    *(void **)((BYTE *)code_mem + call_func_offsets.ymm0_save) = data;
+    func();
+
+    memcpy(code_mem, call_func_code_reset_ymm_state, sizeof(call_func_code_reset_ymm_state));
+    *(void **)((BYTE *)code_mem + call_func_offsets.func_addr) = SuspendThread;
+    *(void **)((BYTE *)code_mem + call_func_offsets.func_param1) = (void *)GetCurrentThread();
+    *(void **)((BYTE *)code_mem + call_func_offsets.func_param2) = (void *)0xdeadbeef;
+    *(void **)((BYTE *)code_mem + call_func_offsets.ymm0_save) = data;
+    func();
+    return 0;
+}
+
+static void wait_for_thread_next_suspend(HANDLE thread)
+{
+    DWORD result;
+
+    result = ResumeThread(thread);
+    ok(result == 1, "Got unexpexted suspend count %u.\n", result);
+
+    /* NtQueryInformationThread(ThreadSuspendCount, ...) is not supported on older Windows. */
+    while (!(result = SuspendThread(thread)))
+    {
+        ResumeThread(thread);
+        Sleep(1);
+    }
+    ok(result == 1, "Got unexpexted suspend count %u.\n", result);
+    result = ResumeThread(thread);
+    ok(result == 2, "Got unexpexted suspend count %u.\n", result);
+}
+
 #define CONTEXT_NATIVE (CONTEXT_XSTATE & CONTEXT_CONTROL)
 
 static void test_extended_context(void)
@@ -6462,115 +6628,6 @@ static void test_extended_context(void)
         0xc3,                         /* ret  */
     };
 
-    struct call_func_offsets
-    {
-        unsigned int func_addr;
-        unsigned int func_param1;
-        unsigned int func_param2;
-        unsigned int ymm0_save;
-    };
-#ifdef __x86_64__
-    static BYTE call_func_code_set_ymm0[] =
-    {
-        0x55,                         /* pushq %rbp */
-        0x48, 0xb8,                   /* mov imm,%rax */
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-        0x48, 0xb9,                   /* mov imm,%rcx */
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-        0x48, 0xba,                   /* mov imm,%rdx */
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-        0x48, 0xbd,                   /* mov imm,%rbp */
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-        0xc5, 0xfc, 0x10, 0x45, 0x00, /* vmovups (%rbp),%ymm0 */
-        0xff, 0xd0,                   /* call *rax */
-        0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%rbp) */
-        0x5d,                         /* popq %rbp */
-        0xc3,                         /* ret  */
-    };
-    static BYTE call_func_code_reset_ymm_state[] =
-    {
-        0x55,                         /* pushq %rbp */
-        0x48, 0xb8,                   /* mov imm,%rax */
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-        0x48, 0xb9,                   /* mov imm,%rcx */
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-        0x48, 0xba,                   /* mov imm,%rdx */
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-        0x48, 0xbd,                   /* mov imm,%rbp */
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-        0xc5, 0xf8, 0x77,             /* vzeroupper */
-        0x0f, 0x57, 0xc0,             /* xorps  %xmm0,%xmm0 */
-        0xff, 0xd0,                   /* call *rax */
-        0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%rbp) */
-        0x5d,                         /* popq %rbp */
-        0xc3,                         /* ret  */
-    };
-    static const struct call_func_offsets call_func_offsets = {3, 13, 23, 33};
-#else
-    static BYTE call_func_code_set_ymm0[] =
-    {
-        0x55,                         /* pushl %ebp */
-        0xb8,                         /* mov imm,%eax */
-        0x00, 0x00, 0x00, 0x00,
-
-        0xb9,                         /* mov imm,%ecx */
-        0x00, 0x00, 0x00, 0x00,
-
-        0xba,                         /* mov imm,%edx */
-        0x00, 0x00, 0x00, 0x00,
-
-        0xbd,                         /* mov imm,%ebp */
-        0x00, 0x00, 0x00, 0x00,
-
-        0x81, 0xfa, 0xef, 0xbe, 0xad, 0xde,
-                                      /* cmpl $0xdeadbeef, %edx */
-        0x74, 0x01,                   /* je 1f */
-        0x52,                         /* pushl %edx */
-        0x51,                         /* 1: pushl %ecx */
-        0xc5, 0xfc, 0x10, 0x45, 0x00, /* vmovups (%ebp),%ymm0 */
-        0xff, 0xd0,                   /* call *eax */
-        0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%ebp) */
-        0x5d,                         /* popl %ebp */
-        0xc3,                         /* ret  */
-    };
-    static BYTE call_func_code_reset_ymm_state[] =
-    {
-        0x55,                         /* pushl %ebp */
-        0xb8,                         /* mov imm,%eax */
-        0x00, 0x00, 0x00, 0x00,
-
-        0xb9,                         /* mov imm,%ecx */
-        0x00, 0x00, 0x00, 0x00,
-
-        0xba,                         /* mov imm,%edx */
-        0x00, 0x00, 0x00, 0x00,
-
-        0xbd,                         /* mov imm,%ebp */
-        0x00, 0x00, 0x00, 0x00,
-
-        0x81, 0xfa, 0xef, 0xbe, 0xad, 0xde,
-                                      /* cmpl $0xdeadbeef, %edx */
-        0x74, 0x01,                   /* je 1f */
-        0x52,                         /* pushl %edx */
-        0x51,                         /* 1: pushl %ecx */
-        0xc5, 0xf8, 0x77,             /* vzeroupper */
-        0x0f, 0x57, 0xc0,             /* xorps  %xmm0,%xmm0 */
-        0xff, 0xd0,                   /* call *eax */
-        0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%ebp) */
-        0x5d,                         /* popl %ebp */
-        0xc3,                         /* ret  */
-    };
-    static const struct call_func_offsets call_func_offsets = {2, 7, 12, 17};
-#endif
-
     static const struct
     {
         ULONG flag;
@@ -6622,6 +6679,7 @@ static void test_extended_context(void)
     CONTEXT_EX *context_ex;
     CONTEXT *context;
     unsigned data[8];
+    HANDLE thread;
     ULONG64 mask;
     XSTATE *xs;
     BOOL bret;
@@ -7396,6 +7454,92 @@ static void test_extended_context(void)
 
     for (i = 0; i < 8; ++i)
         ok(data[i] == test_extended_context_data[i], "Got unexpected data %#x, i %u.\n", data[i], i);
+
+    /* Test GetThreadContext for the other thread. */
+    thread = CreateThread(NULL, 0, test_extended_context_thread, 0, CREATE_SUSPENDED, NULL);
+    ok(!!thread, "Failed to create thread.\n");
+
+    bret = pInitializeContext(context_buffer, CONTEXT_FULL | CONTEXT_XSTATE | CONTEXT_FLOATING_POINT,
+            &context, &length);
+    ok(bret, "Got unexpected bret %#x.\n", bret);
+    memset(&xs->YmmContext, 0xcc, sizeof(xs->YmmContext));
+    context_ex = (CONTEXT_EX *)(context + 1);
+    xs = (XSTATE *)((BYTE *)context_ex + context_ex->XState.Offset);
+    pSetXStateFeaturesMask(context, 4);
+
+    bret = GetThreadContext(thread, context);
+    ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError());
+    ok(!xs->Mask, "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask));
+    ok(xs->CompactionMask == expected_compaction, "Got unexpected CompactionMask %s.\n",
+            wine_dbgstr_longlong(xs->CompactionMask));
+    for (i = 0; i < 16 * 4; ++i)
+        ok(((ULONG *)&xs->YmmContext)[i] == 0xcccccccc, "Got unexpected value %#x, i %u.\n",
+                ((ULONG *)&xs->YmmContext)[i], i);
+
+    pSetXStateFeaturesMask(context, 4);
+    memset(&xs->YmmContext, 0, sizeof(xs->YmmContext));
+    bret = SetThreadContext(thread, context);
+    ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError());
+
+    memset(&xs->YmmContext, 0xcc, sizeof(xs->YmmContext));
+    bret = GetThreadContext(thread, context);
+    ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError());
+    ok(!xs->Mask || broken(xs->Mask == 4), "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask));
+    ok(xs->CompactionMask == expected_compaction, "Got unexpected CompactionMask %s.\n",
+            wine_dbgstr_longlong(xs->CompactionMask));
+    for (i = 0; i < 16 * 4; ++i)
+        ok(((ULONG *)&xs->YmmContext)[i] == 0xcccccccc || broken(xs->Mask == 4 && !((ULONG *)&xs->YmmContext)[i]),
+                "Got unexpected value %#x, i %u.\n", ((ULONG *)&xs->YmmContext)[i], i);
+
+    pSetXStateFeaturesMask(context, 4);
+    memset(&xs->YmmContext, 0x28, sizeof(xs->YmmContext));
+    bret = SetThreadContext(thread, context);
+    ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError());
+    memset(&xs->YmmContext, 0xcc, sizeof(xs->YmmContext));
+    bret = GetThreadContext(thread, context);
+    ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError());
+    ok(xs->Mask == 4, "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask));
+    ok(xs->CompactionMask == expected_compaction, "Got unexpected CompactionMask %s.\n",
+            wine_dbgstr_longlong(xs->CompactionMask));
+    for (i = 0; i < 16 * 4; ++i)
+        ok(((ULONG *)&xs->YmmContext)[i] == 0x28282828, "Got unexpected value %#x, i %u.\n",
+                ((ULONG *)&xs->YmmContext)[i], i);
+
+    wait_for_thread_next_suspend(thread);
+
+    bret = GetThreadContext(thread, context);
+    ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError());
+    pSetXStateFeaturesMask(context, 4);
+    memset(&xs->YmmContext, 0x48, sizeof(xs->YmmContext));
+    bret = SetThreadContext(thread, context);
+    ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError());
+
+    wait_for_thread_next_suspend(thread);
+
+    memset(&xs->YmmContext, 0xcc, sizeof(xs->YmmContext));
+    bret = GetThreadContext(thread, context);
+    ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError());
+    ok(xs->Mask == 4, "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask));
+
+    for (i = 0; i < 4; ++i)
+        ok(((ULONG *)&xs->YmmContext)[i] == 0x68686868, "Got unexpected value %#x, i %u.\n",
+                ((ULONG *)&xs->YmmContext)[i], i);
+
+    wait_for_thread_next_suspend(thread);
+
+    memset(&xs->YmmContext, 0xcc, sizeof(xs->YmmContext));
+    bret = GetThreadContext(thread, context);
+    ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError());
+    ok(xs->Mask == (sizeof(void *) == 4 ? 4 : 0), "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask));
+    for (i = 0; i < 16 * 4; ++i)
+        ok(((ULONG *)&xs->YmmContext)[i] == (sizeof(void *) == 4 ? (i < 8 * 4 ? 0 : 0x48484848) : 0xcccccccc),
+                "Got unexpected value %#x, i %u.\n", ((ULONG *)&xs->YmmContext)[i], i);
+
+    bret = ResumeThread(thread);
+    ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError());
+
+    WaitForSingleObject(thread, INFINITE);
+    CloseHandle(thread);
 }
 
 struct modified_range
-- 
2.26.2




More information about the wine-devel mailing list