[v4 2/4] ntdll/tests: Test values of debug regs in handler.

Andrew Wesie awesie at gmail.com
Sun Feb 12 16:41:21 CST 2017


Signed-off-by: Andrew Wesie <awesie at gmail.com>
---
 dlls/ntdll/tests/exception.c | 167 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 145 insertions(+), 22 deletions(-)

diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index 3abec1b..183cf18 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -110,6 +110,49 @@ typedef struct _JUMP_BUFFER
     SETJMP_FLOAT128  Xmm15;
 } _JUMP_BUFFER;
 
+typedef enum _UNWIND_OP_CODES
+{
+    UWOP_PUSH_NONVOL = 0,
+    UWOP_ALLOC_LARGE,
+    UWOP_ALLOC_SMALL,
+    UWOP_SET_FPREG,
+    UWOP_SAVE_NONVOL,
+    UWOP_SAVE_NONVOL_FAR,
+    UWOP_SAVE_XMM128,
+    UWOP_SAVE_XMM128_FAR,
+    UWOP_PUSH_MACHFRAME
+} UNWIND_CODE_OPS;
+
+typedef union _UNWIND_CODE
+{
+    struct
+    {
+        BYTE CodeOffset;
+        BYTE UnwindOp : 4;
+        BYTE OpInfo   : 4;
+    } u;
+    USHORT FrameOffset;
+} UNWIND_CODE, *PUNWIND_CODE;
+
+typedef struct _UNWIND_INFO
+{
+    BYTE Version       : 3;
+    BYTE Flags         : 5;
+    BYTE SizeOfProlog;
+    BYTE CountOfCodes;
+    BYTE FrameRegister : 4;
+    BYTE FrameOffset   : 4;
+    UNWIND_CODE UnwindCode[1]; /* actually CountOfCodes (aligned) */
+/*
+ *  union
+ *  {
+ *      OPTIONAL ULONG ExceptionHandler;
+ *      OPTIONAL ULONG FunctionEntry;
+ *  };
+ *  OPTIONAL ULONG ExceptionData[];
+ */
+} UNWIND_INFO, *PUNWIND_INFO;
+
 static BOOLEAN   (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
 static BOOLEAN   (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
 static BOOLEAN   (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR);
@@ -1987,35 +2030,111 @@ static void test___C_specific_handler(void)
     ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n", dispatch.ScopeIndex);
 }
 
+static DWORD run_exception_test(void *handler, const void* context,
+                               const void *code, unsigned int code_size,
+                               DWORD access)
+{
+    unsigned char buf[8 + 6 + 8 + 8];
+    RUNTIME_FUNCTION runtime_func;
+    UNWIND_INFO *unwind = (UNWIND_INFO *)buf;
+    DWORD (*func)(void) = code_mem;
+    DWORD oldaccess, oldaccess2, result;
+
+    runtime_func.BeginAddress = 0;
+    runtime_func.EndAddress = code_size;
+    runtime_func.UnwindData = 0x1000;
+
+    unwind->Version = 1;
+    unwind->Flags = UNW_FLAG_EHANDLER;
+    unwind->SizeOfProlog = 0;
+    unwind->CountOfCodes = 0;
+    unwind->FrameRegister = 0;
+    unwind->FrameOffset = 0;
+    *(ULONG *)&buf[4] = 0x1010;
+    *(const void **)&buf[8] = context;
+
+    buf[16] = 0xff;
+    buf[17] = 0x25;
+    *(ULONG *)&buf[18] = 0;
+    *(void **)&buf[22] = handler;
+
+    memcpy((unsigned char *)code_mem + 0x1000, buf, sizeof(buf));
+    memcpy(code_mem, code, code_size);
+    if(access)
+        VirtualProtect(code_mem, code_size, access, &oldaccess);
+
+    pRtlAddFunctionTable(&runtime_func, 1, (ULONG_PTR)code_mem);
+    result = func();
+    pRtlDeleteFunctionTable(&runtime_func);
+
+    if(access)
+        VirtualProtect(code_mem, code_size, oldaccess, &oldaccess2);
+
+    return result;
+}
+
 #endif  /* __x86_64__ */
 
 #if defined(__i386__) || defined(__x86_64__)
+static const struct
+{
+    ULONG_PTR dr0, dr1, dr2, dr3, dr6, dr7;
+}
+debug_register_tests[] =
+{
+    { 0x42424240, 0, 0x126bb070, 0x0badbad0, 0, 0xffff0115 },
+    { 0x42424242, 0, 0x100f0fe7, 0x0abebabe, 0, 0x115 },
+};
+
+#if defined(__x86_64__)
+static DWORD WINAPI debug_register_handler( EXCEPTION_RECORD *rec, ULONG64 frame,
+                      CONTEXT *ctx, DISPATCHER_CONTEXT *dispatcher )
+{
+    int i = **(int **)(dispatcher->HandlerData);
+
+    if (rec->ExceptionCode != STATUS_BREAKPOINT)
+        return ExceptionContinueSearch;
+
+    ok(ctx->Dr0 == debug_register_tests[i].dr0, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr0, ctx->Dr0);
+    ok(ctx->Dr1 == debug_register_tests[i].dr1, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr1, ctx->Dr1);
+    ok(ctx->Dr2 == debug_register_tests[i].dr2, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr2, ctx->Dr2);
+    ok(ctx->Dr3 == debug_register_tests[i].dr3, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr3, ctx->Dr3);
+    ok((ctx->Dr6 &  0xf00f) == debug_register_tests[i].dr6, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr6, ctx->Dr6);
+    ok((ctx->Dr7 & ~0xdc00) == debug_register_tests[i].dr7, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr7, ctx->Dr7);
+
+    ctx->Rip += 1;
+    return ExceptionContinueExecution;
+}
+
+/* Fill stack area above red zone with 0xff, then trigger exception. */
+static const BYTE debug_register_test_code[] = {
+        0x57,                                           /* push %rdi */
+        0x48, 0xc7, 0xc1, 0x00, 0x10, 0x00, 0x00,       /* mov $0x1000, %rcx */
+        0x48, 0x8d, 0xbc, 0x24, 0x80, 0xef, 0xff, 0xff, /* lea -0x1080(%rsp), %rdi */
+        0x48, 0xc7, 0xc0, 0xff, 0x00, 0x00, 0x00,       /* mov $0xff, %rax */
+        0xf3, 0xaa,                                     /* rep stosb */
+        0xcc,                                           /* int3 */
+        0x5f,                                           /* pop %rdi */
+        0xc3,                                           /* ret */
+};
+#endif
 
 static void test_debug_registers(void)
 {
-    static const struct
-    {
-        ULONG_PTR dr0, dr1, dr2, dr3, dr6, dr7;
-    }
-    tests[] =
-    {
-        { 0x42424240, 0, 0x126bb070, 0x0badbad0, 0, 0xffff0115 },
-        { 0x42424242, 0, 0x100f0fe7, 0x0abebabe, 0, 0x115 },
-    };
     NTSTATUS status;
     CONTEXT ctx;
     int i;
 
-    for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
+    for (i = 0; i < sizeof(debug_register_tests)/sizeof(debug_register_tests[0]); i++)
     {
         memset(&ctx, 0, sizeof(ctx));
         ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
-        ctx.Dr0 = tests[i].dr0;
-        ctx.Dr1 = tests[i].dr1;
-        ctx.Dr2 = tests[i].dr2;
-        ctx.Dr3 = tests[i].dr3;
-        ctx.Dr6 = tests[i].dr6;
-        ctx.Dr7 = tests[i].dr7;
+        ctx.Dr0 = debug_register_tests[i].dr0;
+        ctx.Dr1 = debug_register_tests[i].dr1;
+        ctx.Dr2 = debug_register_tests[i].dr2;
+        ctx.Dr3 = debug_register_tests[i].dr3;
+        ctx.Dr6 = debug_register_tests[i].dr6;
+        ctx.Dr7 = debug_register_tests[i].dr7;
 
         status = pNtSetContextThread(GetCurrentThread(), &ctx);
         ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %08x\n", status);
@@ -2025,12 +2144,16 @@ static void test_debug_registers(void)
 
         status = pNtGetContextThread(GetCurrentThread(), &ctx);
         ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %08x\n", status);
-        ok(ctx.Dr0 == tests[i].dr0, "test %d: expected %lx, got %lx\n", i, tests[i].dr0, (DWORD_PTR)ctx.Dr0);
-        ok(ctx.Dr1 == tests[i].dr1, "test %d: expected %lx, got %lx\n", i, tests[i].dr1, (DWORD_PTR)ctx.Dr1);
-        ok(ctx.Dr2 == tests[i].dr2, "test %d: expected %lx, got %lx\n", i, tests[i].dr2, (DWORD_PTR)ctx.Dr2);
-        ok(ctx.Dr3 == tests[i].dr3, "test %d: expected %lx, got %lx\n", i, tests[i].dr3, (DWORD_PTR)ctx.Dr3);
-        ok((ctx.Dr6 &  0xf00f) == tests[i].dr6, "test %d: expected %lx, got %lx\n", i, tests[i].dr6, (DWORD_PTR)ctx.Dr6);
-        ok((ctx.Dr7 & ~0xdc00) == tests[i].dr7, "test %d: expected %lx, got %lx\n", i, tests[i].dr7, (DWORD_PTR)ctx.Dr7);
+        ok(ctx.Dr0 == debug_register_tests[i].dr0, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr0, (DWORD_PTR)ctx.Dr0);
+        ok(ctx.Dr1 == debug_register_tests[i].dr1, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr1, (DWORD_PTR)ctx.Dr1);
+        ok(ctx.Dr2 == debug_register_tests[i].dr2, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr2, (DWORD_PTR)ctx.Dr2);
+        ok(ctx.Dr3 == debug_register_tests[i].dr3, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr3, (DWORD_PTR)ctx.Dr3);
+        ok((ctx.Dr6 &  0xf00f) == debug_register_tests[i].dr6, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr6, (DWORD_PTR)ctx.Dr6);
+        ok((ctx.Dr7 & ~0xdc00) == debug_register_tests[i].dr7, "test %d: expected %lx, got %lx\n", i, debug_register_tests[i].dr7, (DWORD_PTR)ctx.Dr7);
+
+#if defined(__x86_64__)
+        run_exception_test(debug_register_handler, &i, debug_register_test_code, sizeof(debug_register_test_code), 0);
+#endif
     }
 }
 
-- 
2.7.4




More information about the wine-patches mailing list