[NTDLL_APITEST] Implement NtContinue test for x64

This commit is contained in:
Timo Kreuzer 2022-08-21 16:21:10 +02:00
parent f7024d6c72
commit 6744368755
3 changed files with 122 additions and 18 deletions

View file

@ -100,6 +100,8 @@ list(APPEND SOURCE
if(ARCH STREQUAL "i386") if(ARCH STREQUAL "i386")
add_asm_files(ntdll_apitest_asm i386/NtContinue.S) add_asm_files(ntdll_apitest_asm i386/NtContinue.S)
elseif(ARCH STREQUAL "amd64")
add_asm_files(ntdll_apitest_asm amd64/NtContinue.S)
endif() endif()
list(APPEND PCH_SKIP_SOURCE list(APPEND PCH_SKIP_SOURCE

View file

@ -10,6 +10,15 @@
#include <setjmp.h> #include <setjmp.h>
#include <time.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 #ifdef _M_IX86
#define NTC_SEGMENT_BITS (0xFFFF) #define NTC_SEGMENT_BITS (0xFFFF)
#define NTC_EFLAGS_BITS (0x3C0CD5) #define NTC_EFLAGS_BITS (0x3C0CD5)
@ -121,6 +130,51 @@ void check(CONTEXT * pContext)
ok((pContext->SegSs & NTC_SEGMENT_BITS) == ok((pContext->SegSs & NTC_SEGMENT_BITS) ==
(continueContext.SegSs & NTC_SEGMENT_BITS), (continueContext.SegSs & NTC_SEGMENT_BITS),
"SegSs: 0x%lx != 0x%lx\n", pContext->SegSs, continueContext.SegSs); "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 #endif
/* Return where we came from */ /* Return where we came from */
@ -129,16 +183,16 @@ void check(CONTEXT * pContext)
START_TEST(NtContinue) START_TEST(NtContinue)
{ {
#ifdef __RUNTIME_CHECKS__
skip("This test breaks MSVC runtime checks!\n");
return;
#endif /* __RUNTIME_CHECKS__ */
initrand(); initrand();
RtlFillMemory(&continueContext, sizeof(continueContext), 0xBBBBBBBB);
/* First time */ /* First time */
if(setjmp(jmpbuf) == 0) if(setjmp(jmpbuf) == 0)
{ {
CONTEXT bogus; CONTEXT bogus[2];
RtlFillMemory(&bogus, sizeof(bogus), 0xCCCCCCCC);
continueContext.ContextFlags = CONTEXT_FULL; continueContext.ContextFlags = CONTEXT_FULL;
GetThreadContext(GetCurrentThread(), &continueContext); GetThreadContext(GetCurrentThread(), &continueContext);
@ -167,28 +221,38 @@ START_TEST(NtContinue)
/* Can't do a lot about segments */ /* Can't do a lot about segments */
#elif defined(_M_AMD64) #elif defined(_M_AMD64)
continueContext.ContextFlags = CONTEXT_FULL; continueContext.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
/* Fill the integer registers with random values */ /* Fill the integer registers with random values */
continueContext.Rdi = randULONG64(); PULONG64 Registers = &continueContext.Rax;
continueContext.Rsi = randULONG64(); for (ULONG i = 0; i < 16; i++)
continueContext.Rbx = randULONG64(); {
continueContext.Rdx = randULONG64(); Registers[i] = randULONG64();
continueContext.Rcx = randULONG64(); }
continueContext.Rax = randULONG64();
continueContext.Rbp = 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) */ /* Randomize all the allowed flags (determined experimentally with WinDbg) */
continueContext.EFlags = randULONG64() & 0x3C0CD5; continueContext.EFlags = randULONG64() & 0x3C0CD5;
/* Randomize the stack pointer as much as possible */ /* Randomize the stack pointer as much as possible */
continueContext.Rsp = (((ULONG_PTR)&bogus)) + continueContext.Rsp = (((ULONG_PTR)&bogus)) + (randULONG() & 0xF) * 16;
sizeof(bogus) - (randULONG() & 0xF) * 4; continueContext.Rsp = ALIGN_DOWN_BY(continueContext.Rsp, 16);
/* continuePoint() is implemented in assembler */ /* continuePoint() is implemented in assembler */
//continueContext.Rip = ((ULONG_PTR)continuePoint); continueContext.Rip = ((ULONG_PTR)continuePoint);
skip("NtContinue test does not yet work on x64.");
return;
#endif #endif
NtContinue(&continueContext, FALSE); NtContinue(&continueContext, FALSE);

View file

@ -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 <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