From: Andrew Wesie Subject: [v4 2/4] ntdll/tests: Test values of debug regs in handler. Message-Id: <1486939283-85934-2-git-send-email-awesie@gmail.com> Date: Sun, 12 Feb 2017 16:41:21 -0600 In-Reply-To: <1486939283-85934-1-git-send-email-awesie@gmail.com> References: <1486939283-85934-1-git-send-email-awesie@gmail.com> Signed-off-by: Andrew Wesie --- 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