[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