diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt b/modules/rostests/apitests/ntdll/CMakeLists.txt index c2ec474a5a0..2e38c4ec7b5 100644 --- a/modules/rostests/apitests/ntdll/CMakeLists.txt +++ b/modules/rostests/apitests/ntdll/CMakeLists.txt @@ -100,6 +100,8 @@ list(APPEND SOURCE if(ARCH STREQUAL "i386") add_asm_files(ntdll_apitest_asm i386/NtContinue.S) +elseif(ARCH STREQUAL "amd64") + add_asm_files(ntdll_apitest_asm amd64/NtContinue.S) endif() list(APPEND PCH_SKIP_SOURCE diff --git a/modules/rostests/apitests/ntdll/NtContinue.c b/modules/rostests/apitests/ntdll/NtContinue.c index 334c85056a2..f159c7bf3f7 100644 --- a/modules/rostests/apitests/ntdll/NtContinue.c +++ b/modules/rostests/apitests/ntdll/NtContinue.c @@ -10,6 +10,15 @@ #include #include +#ifdef _MSC_VER +#pragma runtime_checks("s", off) +#endif + +#define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected) +#define ok_eq_hex(value, expected) ok_eq_print(value, expected, "%lx") +#define ok_eq_hex64(value, expected) ok_eq_print(value, expected, "%I64x") +#define ok_eq_xmm(value, expected) ok((value).Low == (expected).Low, #value " = %I64x'%08I64x, expected %I64x'%08I64x\n", (value).Low, (value).High, (expected).Low, (expected).High) + #ifdef _M_IX86 #define NTC_SEGMENT_BITS (0xFFFF) #define NTC_EFLAGS_BITS (0x3C0CD5) @@ -121,6 +130,51 @@ void check(CONTEXT * pContext) ok((pContext->SegSs & NTC_SEGMENT_BITS) == (continueContext.SegSs & NTC_SEGMENT_BITS), "SegSs: 0x%lx != 0x%lx\n", pContext->SegSs, continueContext.SegSs); +#else + ok_eq_hex64(pContext->ContextFlags, CONTEXT_FULL | CONTEXT_SEGMENTS); + ok_eq_hex(pContext->MxCsr, continueContext.MxCsr); + ok_eq_hex(pContext->SegCs, continueContext.SegCs); + ok_eq_hex(pContext->SegDs, 0x2B); + ok_eq_hex(pContext->SegEs, 0x2B); + ok_eq_hex(pContext->SegFs, 0x53); + ok_eq_hex(pContext->SegGs, 0x2B); + ok_eq_hex(pContext->SegSs, continueContext.SegSs); + ok_eq_hex(pContext->EFlags, (continueContext.EFlags & ~0x1C0000) | 0x202); + + ok_eq_hex64(pContext->Rax, continueContext.Rax); + ok_eq_hex64(pContext->Rdx, continueContext.Rdx); + ok_eq_hex64(pContext->Rbx, continueContext.Rbx); + ok_eq_hex64(pContext->Rsp, continueContext.Rsp); + ok_eq_hex64(pContext->Rbp, continueContext.Rbp); + ok_eq_hex64(pContext->Rsi, continueContext.Rsi); + ok_eq_hex64(pContext->Rdi, continueContext.Rdi); + ok_eq_hex64(pContext->R8, continueContext.R8); + ok_eq_hex64(pContext->R9, continueContext.R9); + ok_eq_hex64(pContext->R10, continueContext.R10); + ok_eq_hex64(pContext->R11, continueContext.R11); + ok_eq_hex64(pContext->R12, continueContext.R12); + ok_eq_hex64(pContext->R13, continueContext.R13); + ok_eq_hex64(pContext->R14, continueContext.R14); + ok_eq_hex64(pContext->R15, continueContext.R15); + ok_eq_xmm(pContext->Xmm0, continueContext.Xmm0); + ok_eq_xmm(pContext->Xmm1, continueContext.Xmm1); + ok_eq_xmm(pContext->Xmm2, continueContext.Xmm2); + ok_eq_xmm(pContext->Xmm3, continueContext.Xmm3); + ok_eq_xmm(pContext->Xmm4, continueContext.Xmm4); + ok_eq_xmm(pContext->Xmm5, continueContext.Xmm5); + ok_eq_xmm(pContext->Xmm6, continueContext.Xmm6); + ok_eq_xmm(pContext->Xmm7, continueContext.Xmm7); + ok_eq_xmm(pContext->Xmm8, continueContext.Xmm8); + ok_eq_xmm(pContext->Xmm9, continueContext.Xmm9); + ok_eq_xmm(pContext->Xmm10, continueContext.Xmm10); + ok_eq_xmm(pContext->Xmm11, continueContext.Xmm11); + ok_eq_xmm(pContext->Xmm12, continueContext.Xmm12); + ok_eq_xmm(pContext->Xmm13, continueContext.Xmm13); + ok_eq_xmm(pContext->Xmm14, continueContext.Xmm14); + ok_eq_xmm(pContext->Xmm15, continueContext.Xmm15); + + // Clear the frame register to prevent unwinding, which is broken + ((_JUMP_BUFFER*)&jmpbuf)->Frame = 0; #endif /* Return where we came from */ @@ -129,16 +183,16 @@ void check(CONTEXT * pContext) START_TEST(NtContinue) { -#ifdef __RUNTIME_CHECKS__ - skip("This test breaks MSVC runtime checks!\n"); - return; -#endif /* __RUNTIME_CHECKS__ */ initrand(); + RtlFillMemory(&continueContext, sizeof(continueContext), 0xBBBBBBBB); + /* First time */ if(setjmp(jmpbuf) == 0) { - CONTEXT bogus; + CONTEXT bogus[2]; + + RtlFillMemory(&bogus, sizeof(bogus), 0xCCCCCCCC); continueContext.ContextFlags = CONTEXT_FULL; GetThreadContext(GetCurrentThread(), &continueContext); @@ -167,28 +221,38 @@ START_TEST(NtContinue) /* Can't do a lot about segments */ #elif defined(_M_AMD64) - continueContext.ContextFlags = CONTEXT_FULL; + continueContext.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; /* Fill the integer registers with random values */ - continueContext.Rdi = randULONG64(); - continueContext.Rsi = randULONG64(); - continueContext.Rbx = randULONG64(); - continueContext.Rdx = randULONG64(); - continueContext.Rcx = randULONG64(); - continueContext.Rax = randULONG64(); - continueContext.Rbp = randULONG64(); + PULONG64 Registers = &continueContext.Rax; + for (ULONG i = 0; i < 16; i++) + { + Registers[i] = randULONG64(); + } + + /* Fill the XMM registers with random values */ + Registers = (PULONG64)&continueContext.Xmm0; + for (ULONG i = 0; i < 32; i++) + { + Registers[i] = randULONG64(); + } + + continueContext.Dr0 = randULONG64() & 0xFFFF; + continueContext.Dr1 = randULONG64() & 0xFFFF; + continueContext.Dr2 = randULONG64() & 0xFFFF; + continueContext.Dr3 = randULONG64() & 0xFFFF; + continueContext.Dr6 = randULONG64() & 0xFFFF; + continueContext.Dr7 = randULONG64() & 0xFFFF; /* Randomize all the allowed flags (determined experimentally with WinDbg) */ continueContext.EFlags = randULONG64() & 0x3C0CD5; /* Randomize the stack pointer as much as possible */ - continueContext.Rsp = (((ULONG_PTR)&bogus)) + - sizeof(bogus) - (randULONG() & 0xF) * 4; + continueContext.Rsp = (((ULONG_PTR)&bogus)) + (randULONG() & 0xF) * 16; + continueContext.Rsp = ALIGN_DOWN_BY(continueContext.Rsp, 16); /* continuePoint() is implemented in assembler */ - //continueContext.Rip = ((ULONG_PTR)continuePoint); - skip("NtContinue test does not yet work on x64."); - return; + continueContext.Rip = ((ULONG_PTR)continuePoint); #endif NtContinue(&continueContext, FALSE); diff --git a/modules/rostests/apitests/ntdll/amd64/NtContinue.S b/modules/rostests/apitests/ntdll/amd64/NtContinue.S new file mode 100644 index 00000000000..40304d94122 --- /dev/null +++ b/modules/rostests/apitests/ntdll/amd64/NtContinue.S @@ -0,0 +1,38 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Helper functions for NtContinue test + * COPYRIGHT: Copyright 2022 Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +#include +#include + +.code64 + +EXTERN RtlCaptureContext:PROC +EXTERN check:PROC + +PUBLIC continuePoint +.PROC continuePoint + + // Allocate space for a CONTEXT structure + .ALLOCSTACK CONTEXT_FRAME_LENGTH + 8 + .ENDPROLOG + + // Capture the current CONTEXT + mov rcx, rsp + call RtlCaptureContext + + // Call the function that will compare the current context with the expected one + cld + mov rcx, rsp + call check + + // check() must not return + int 3 + +.ENDP + +// EOF +END