From: Dāvis Mosāns davispuh@gmail.com
--- dlls/ntdll/tests/exception.c | 131 ++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 06d700a5873..5e4bdc1dac4 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -9118,12 +9118,115 @@ static void test_continue(void) NTSTATUS (*func_ptr)( struct context_pair *, void *arg2, void *continue_func, void *capture_func ) = code_mem;
#ifdef __x86_64__ - /* FIXME */ static const BYTE call_func[] = { + /* need to preserve these */ + 0x53, /* push rbx */ + 0x55, /* push rbp */ + 0x56, /* push rsi */ + 0x57, /* push rdi */ + 0x41, 0x54, /* push r12 */ + 0x41, 0x55, /* push r13 */ + 0x41, 0x56, /* push r14 */ + 0x41, 0x57, /* push r15 */ + + 0x48, 0x83, 0xec, 0x28, /* sub rsp, 8*5; stack space */ + 0x48, 0x89, 0x24, 0x24, /* mov [rsp+8*0], rsp; for validation */ + + /* save args */ + 0x48, 0x89, 0x4c, 0x24, 0x08, /* mov [rsp+8*1], rcx */ + 0x48, 0x89, 0x54, 0x24, 0x10, /* mov [rsp+8*2], rdx */ + 0x4c, 0x89, 0x44, 0x24, 0x18, /* mov [rsp+8*3], r8 */ + 0x4c, 0x89, 0x4c, 0x24, 0x20, /* mov [rsp+8*4], r9 */ + + /* invoke capture context */ + 0x41, 0xff, 0xd1, /* call r9 */ + + /* overwrite general registers */ + 0x48, 0xb8, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, /* mov rax, 0xdeadbeefdeadbeef */ + 0x48, 0x89, 0xc1, /* mov rcx, rax */ + 0x48, 0x89, 0xc2, /* mov rdx, rax */ + 0x48, 0x89, 0xc3, /* mov rbx, rax */ + 0x48, 0x89, 0xc5, /* mov rbp, rax */ + 0x48, 0x89, 0xc6, /* mov rsi, rax */ + 0x48, 0x89, 0xc7, /* mov rdi, rax */ + 0x49, 0x89, 0xc0, /* mov r8, rax */ + 0x49, 0x89, 0xc1, /* mov r9, rax */ + 0x49, 0x89, 0xc2, /* mov r10, rax */ + 0x49, 0x89, 0xc3, /* mov r11, rax */ + 0x49, 0x89, 0xc4, /* mov r12, rax */ + 0x49, 0x89, 0xc5, /* mov r13, rax */ + 0x49, 0x89, 0xc6, /* mov r14, rax */ + 0x49, 0x89, 0xc7, /* mov r15, rax */ + + /* overwrite SSE registers */ + 0x66, 0x48, 0x0f, 0x6e, 0xc0, /* movq xmm0, rax */ + 0x66, 0x0f, 0x6c, 0xc0, /* punpcklqdq xmm0,xmm0; extend to high quadword */ + 0x0f, 0x28, 0xc8, /* movaps xmm1, xmm0 */ + 0x0f, 0x28, 0xd0, /* movaps xmm2, xmm0 */ + 0x0f, 0x28, 0xd8, /* movaps xmm3, xmm0 */ + 0x0f, 0x28, 0xe0, /* movaps xmm4, xmm0 */ + 0x0f, 0x28, 0xe8, /* movaps xmm5, xmm0 */ + 0x0f, 0x28, 0xf0, /* movaps xmm6, xmm0 */ + 0x0f, 0x28, 0xf8, /* movaps xmm7, xmm0 */ + 0x44, 0x0f, 0x28, 0xc0, /* movaps xmm8, xmm0 */ + 0x44, 0x0f, 0x28, 0xc8, /* movaps xmm9, xmm0 */ + 0x44, 0x0f, 0x28, 0xd0, /* movaps xmm10, xmm0 */ + 0x44, 0x0f, 0x28, 0xd8, /* movaps xmm11, xmm0 */ + 0x44, 0x0f, 0x28, 0xe0, /* movaps xmm12, xmm0 */ + 0x44, 0x0f, 0x28, 0xe8, /* movaps xmm13, xmm0 */ + 0x44, 0x0f, 0x28, 0xf0, /* movaps xmm14, xmm0 */ + 0x44, 0x0f, 0x28, 0xf8, /* movaps xmm15, xmm0 */ + + /* FIXME: overwrite debug, x87 FPU and AVX registers to test those */ + + /* load args */ + 0x48, 0x8b, 0x4c, 0x24, 0x08, /* mov rcx, [rsp+8*1]; context */ + 0x48, 0x8b, 0x54, 0x24, 0x10, /* mov rdx, [rsp+8*2]; arg2 */ + 0x48, 0x83, 0xec, 0x70, /* sub rsp, 0x70; change stack */ + + /* setup context to return to label 1 */ + 0x48, 0x8d, 0x05, 0x1b, 0x00, 0x00, 0x00, /* lea rax, [rel 1] (0x1b) */ + 0x48, 0x89, 0x81, 0xf8, 0x00, 0x00, 0x00, /* mov [rcx + 0xf8 (context.Rip)], rax */ + + /* trash EFLAGS */ + 0x9c, /* pushfq */ + 0x58, /* pop rax */ + 0x48, 0x0d, 0x00, 0x45, 0x00, 0x00, /* or rax, 0x0100 + 0x4400; set trap flag so it's cleared. + FIXME: also clearing Direction Flag and Nested Task as those break Wine */ + + 0x48, 0xf7, 0xd0, /* not rax */ + 0x50, /* push rax */ + 0x9d, /* popfq */ + + /* invoke NtContinue... */ + 0xff, 0x94, 0x24, 0x88, 0x00, 0x00, 0x00, /* call [rsp+8*3+0x70] */ + + /* validate stack pointer */ + 0x48, 0x8b, 0x0c, 0x24, /* 1: mov rcx, [rsp] */ + 0x48, 0x39, 0xe1, /* cmp rcx, rsp */ + 0x74, 0x02, /* je 2; jump over ud2 */ + 0x0f, 0x0b, /* ud2; stack pointer invalid, let's crash */ + + /* invoke capture context */ + 0x48, 0x8b, 0x4c, 0x24, 0x08, /* mov rcx, [rsp+8*1]; context */ + 0x48, 0x81, 0xc1, 0xd0, 0x04, 0x00, 0x00, /* add rcx, 0x4d0; +sizeof(CONTEXT) to get context->after */ + 0xff, 0x54, 0x24, 0x20, /* call [rsp+8*4] */ + + /* free stack */ + 0x48, 0x83, 0xc4, 0x28, /* 2: add rsp, 8*5 */ + + /* restore back */ + 0x41, 0x5f, /* pop r15 */ + 0x41, 0x5e, /* pop r14 */ + 0x41, 0x5d, /* pop r13 */ + 0x41, 0x5c, /* pop r12 */ + 0x5f, /* pop rdi */ + 0x5e, /* pop rsi */ + 0x5d, /* pop rbp */ + 0x5b, /* pop rbx */ + 0xc3 /* ret */ }; - skip("test for NtContinue() not implemented\n"); - return; #elif defined(__aarch64__) static const DWORD call_func[] = { @@ -9226,6 +9329,28 @@ static void test_continue(void) func_ptr( &contexts, FALSE, NtContinue, pRtlCaptureContext );
#ifdef __x86_64__ +#define COMPARE(reg) \ + ok( contexts.before.reg == contexts.after.reg, "wrong " #reg " %p/%p\n", (void *)(ULONG64)contexts.before.reg, (void *)(ULONG64)contexts.after.reg ) + + COMPARE( Rax ); + COMPARE( Rdx ); + COMPARE( Rbx ); + COMPARE( Rbp ); + COMPARE( Rsi ); + COMPARE( Rdi ); + COMPARE( R8 ); + COMPARE( R9 ); + COMPARE( R10 ); + COMPARE( R11 ); + COMPARE( R12 ); + COMPARE( R13 ); + COMPARE( R14 ); + COMPARE( R15 ); + + ok(memcmp(&contexts.before.Xmm0, &contexts.after.Xmm0, &contexts.before.Xmm15 - &contexts.before.Xmm0) == 0, + "wrong some SSE register, Xmm0 %lld/%lld Xmm15 %lld/%lld", contexts.before.Xmm0.Low, contexts.after.Xmm0.Low, + contexts.before.Xmm15.High, contexts.after.Xmm15.High); + #elif defined(__aarch64__) #define COMPARE(reg) \ ok( contexts.before.reg == contexts.after.reg, "wrong " #reg " %p/%p\n", (void *)(ULONG64)contexts.before.reg, (void *)(ULONG64)contexts.after.reg )