https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6744368755d3ae2ab0d2a…
commit 6744368755d3ae2ab0d2af5bd3cbd27679b62e3e
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Sun Aug 21 16:21:10 2022 +0200
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Thu Nov 24 21:17:58 2022 +0200
[NTDLL_APITEST] Implement NtContinue test for x64
---
modules/rostests/apitests/ntdll/CMakeLists.txt | 2 +
modules/rostests/apitests/ntdll/NtContinue.c | 100 +++++++++++++++++----
modules/rostests/apitests/ntdll/amd64/NtContinue.S | 38 ++++++++
3 files changed, 122 insertions(+), 18 deletions(-)
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 <setjmp.h>
#include <time.h>
+#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(a)reactos.org)
+ */
+
+#include <asm.inc>
+#include <ksamd64.inc>
+
+.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