https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bdf52a986814f4b3ae333a...
commit bdf52a986814f4b3ae333aca99225750e084a2ad Author: Timo Kreuzer timo.kreuzer@reactos.org AuthorDate: Sat May 20 09:36:13 2023 +0300 Commit: Timo Kreuzer timo.kreuzer@reactos.org CommitDate: Fri Nov 10 19:00:41 2023 +0200
[RTL_APITEST] Add rtl_unittest
First test is RtlCaptureContext --- modules/rostests/apitests/CMakeLists.txt | 1 + modules/rostests/apitests/ntdll/CMakeLists.txt | 5 +- modules/rostests/apitests/ntdll/testlist.c | 4 + modules/rostests/apitests/rtl/CMakeLists.txt | 56 +++++ .../apitests/rtl/amd64/RtlCaptureContext-asm.s | 182 +++++++++++++++ .../apitests/rtl/amd64/RtlCaptureContext.c | 243 +++++++++++++++++++++ .../rostests/apitests/rtl/i386/RtlCaptureContext.c | 18 ++ modules/rostests/apitests/rtl/ldrstubs.c | 17 ++ modules/rostests/apitests/rtl/rtltests.h | 12 + modules/rostests/apitests/rtl/testlist.c | 15 ++ modules/rostests/kmtests/CMakeLists.txt | 10 + modules/rostests/kmtests/include/rtltests.h | 5 + modules/rostests/kmtests/kmtest/testlist.c | 4 + modules/rostests/kmtests/kmtest_drv/testlist.c | 4 + 14 files changed, 574 insertions(+), 2 deletions(-)
diff --git a/modules/rostests/apitests/CMakeLists.txt b/modules/rostests/apitests/CMakeLists.txt index ebc0bdfd4b5..4bb4e2ef024 100644 --- a/modules/rostests/apitests/CMakeLists.txt +++ b/modules/rostests/apitests/CMakeLists.txt @@ -40,6 +40,7 @@ add_subdirectory(ole32) add_subdirectory(opengl32) add_subdirectory(pefile) add_subdirectory(powrprof) +add_subdirectory(rtl) add_subdirectory(sdk) add_subdirectory(setupapi) add_subdirectory(sfc) diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt b/modules/rostests/apitests/ntdll/CMakeLists.txt index b6ce3a1cf4d..acc24d45a3e 100644 --- a/modules/rostests/apitests/ntdll/CMakeLists.txt +++ b/modules/rostests/apitests/ntdll/CMakeLists.txt @@ -101,7 +101,8 @@ list(APPEND SOURCE StackOverflow.c SystemInfo.c UserModeException.c - Timer.c) + Timer.c + precomp.h)
if(ARCH STREQUAL "i386") add_asm_files(ntdll_apitest_asm i386/NtContinue.S) @@ -126,7 +127,7 @@ set_target_properties(ntdll_apitest ENABLE_EXPORTS TRUE DEFINE_SYMBOL "")
-target_link_libraries(ntdll_apitest wine uuid ${PSEH_LIB}) +target_link_libraries(ntdll_apitest rtl_test_lib wine uuid ${PSEH_LIB}) set_module_type(ntdll_apitest win32cui) add_importlibs(ntdll_apitest msvcrt advapi32 kernel32 ntdll) add_pch(ntdll_apitest precomp.h "${PCH_SKIP_SOURCE}") diff --git a/modules/rostests/apitests/ntdll/testlist.c b/modules/rostests/apitests/ntdll/testlist.c index 438cc56a172..cc19972f5aa 100644 --- a/modules/rostests/apitests/ntdll/testlist.c +++ b/modules/rostests/apitests/ntdll/testlist.c @@ -54,6 +54,7 @@ extern void func_NtUnloadDriver(void); extern void func_NtWriteFile(void); extern void func_RtlAllocateHeap(void); extern void func_RtlBitmap(void); +extern void func_RtlCaptureContext(void); extern void func_RtlComputePrivatizedDllName_U(void); extern void func_RtlCopyMappedMemory(void); extern void func_RtlCriticalSection(void); @@ -194,6 +195,9 @@ const struct test winetest_testlist[] = { "StackOverflow", func_StackOverflow }, { "TimerResolution", func_TimerResolution }, { "UserModeException", func_UserModeException }, +#ifdef _M_AMD64 + { "RtlCaptureContext", func_RtlCaptureContext }, +#endif
{ 0, 0 } }; diff --git a/modules/rostests/apitests/rtl/CMakeLists.txt b/modules/rostests/apitests/rtl/CMakeLists.txt new file mode 100644 index 00000000000..7c74792dfd5 --- /dev/null +++ b/modules/rostests/apitests/rtl/CMakeLists.txt @@ -0,0 +1,56 @@ + + +list(APPEND SOURCE + # To be filled +) + +if(ARCH STREQUAL "i386") + list(APPEND SOURCE + i386/RtlCaptureContext.c + ) +elseif(ARCH STREQUAL "amd64") + list(APPEND ASM_SOURCE + amd64/RtlCaptureContext-asm.s + ) + list(APPEND SOURCE + amd64/RtlCaptureContext.c + ) +elseif(ARCH STREQUAL "arm") + list(APPEND SOURCE + # To be filled + ) +endif() + +add_asm_files(rtl_test_asm ${ASM_SOURCE}) + +add_library(rtl_test_lib + ${SOURCE} + ${rtl_test_asm} +) + +target_compile_definitions(rtl_test_lib PRIVATE _RTL_TEST _NTSYSTEM_) + +add_dependencies(rtl_test_lib asm) + +if(NOT MSVC) + set_source_files_properties(RtlGetFullPathName_UstrEx.c PROPERTIES COMPILE_FLAGS "-Wno-format") + + # Avoid "universal character names are only valid in C++ and C99" error. + set_property(TARGET rtl_test_lib PROPERTY C_STANDARD 99) +endif() + +# RTL tests with static linkage (called unittest, so it won't run in rosautotest) +add_executable(rtl_unittest + testlist.c + ldrstubs.c) +target_compile_definitions(rtl_unittest PRIVATE _RTL_TEST _NTSYSTEM_) +target_link_libraries(rtl_unittest rtl_test_lib rtl rtl_um rtl_vista wine uuid ${PSEH_LIB}) +set_module_type(rtl_unittest win32cui) +add_importlibs(rtl_unittest msvcrt advapi32 kernel32 ntdll) +target_compile_definitions(rtl_unittest PRIVATE KMT_USER_MODE NTDDI_VERSION=NTDDI_WS03SP1) + +add_rostests_file(TARGET rtl_unittest) + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_compile_options(rtl_unittest PRIVATE -Wno-format) +endif() diff --git a/modules/rostests/apitests/rtl/amd64/RtlCaptureContext-asm.s b/modules/rostests/apitests/rtl/amd64/RtlCaptureContext-asm.s new file mode 100644 index 00000000000..35eb91169bf --- /dev/null +++ b/modules/rostests/apitests/rtl/amd64/RtlCaptureContext-asm.s @@ -0,0 +1,182 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Test helper for x64 RtlCaptureContext + * COPYRIGHT: Copyright 2022 Timo Kreuzer timo.kreuzer@reactos.org + */ + +#include <asm.inc> +#include <ksamd64.inc> + +.code64 + +EXTERN RtlCaptureContext:PROC + +FUNC ZeroContext + + pushfq + .ALLOCSTACK 8 + push rax + .PUSHREG rax + push rcx + .PUSHREG rcx + push rdi + .PUSHREG rdi + .ENDPROLOG + + mov rdi, rcx + mov rcx, CONTEXT_FRAME_LENGTH + xor eax, eax + cld + rep stosb + + pop rdi + pop rcx + pop rax + popfq + ret + +ENDFUNC + +// +// VOID +// RtlCaptureContextWrapper ( +// _Inout_ PCONTEXT InOutContext, +// _Out_ PCONTEXT CapturedContext); +// +PUBLIC RtlCaptureContextWrapper +FUNC RtlCaptureContextWrapper + + // Generate a KEXCEPTION_FRAME on the stack + GENERATE_EXCEPTION_FRAME + + // Save parameters + mov [rsp + ExP1Home], rcx + mov [rsp + ExP2Home], rdx + + // Save current EFlags + pushfq + pop qword ptr [rsp + ExP3Home] + + // Load integer registers from InOutContext + mov rax, [rcx + CxRax] + mov rdx, [rcx + CxRdx] + mov rbx, [rcx + CxRbx] + mov rbp, [rcx + CxRbp] + mov rsi, [rcx + CxRsi] + mov rdi, [rcx + CxRdi] + mov r8, [rcx + CxR8] + mov r9, [rcx + CxR9] + mov r10, [rcx + CxR10] + mov r11, [rcx + CxR11] + mov r12, [rcx + CxR12] + mov r13, [rcx + CxR13] + mov r14, [rcx + CxR14] + mov r15, [rcx + CxR15] + + // Load floating point registers from InOutContext + fxrstor [rcx + CxFltSave] + + // Load MxCsr (this overwrites the value from FltSave) + ldmxcsr [rcx + CxMxCsr] + + // Load XMM registers + movaps xmm0, [rcx + CxXmm0] + movaps xmm1, [rcx + CxXmm1] + movaps xmm2, [rcx + CxXmm2] + movaps xmm3, [rcx + CxXmm3] + movaps xmm4, [rcx + CxXmm4] + movaps xmm5, [rcx + CxXmm5] + movaps xmm6, [rcx + CxXmm6] + movaps xmm7, [rcx + CxXmm7] + movaps xmm8, [rcx + CxXmm8] + movaps xmm9, [rcx + CxXmm9] + movaps xmm10, [rcx + CxXmm10] + movaps xmm11, [rcx + CxXmm11] + movaps xmm12, [rcx + CxXmm12] + movaps xmm13, [rcx + CxXmm13] + movaps xmm14, [rcx + CxXmm14] + movaps xmm15, [rcx + CxXmm15] + + // Load EFlags + push qword ptr [rcx + CxEFlags] + popfq + + // Capture the context + mov rcx, [rsp + ExP2Home] + call RtlCaptureContext +ReturnAddress: + + // Save the returned rcx + mov [rsp + ExP4Home], rcx + + // Restore original rcx + mov rcx, [rsp + ExP1Home] + + // Zero out the context (this does not clobber any registers/flags) + call ZeroContext + + // Save returned Eflags + pushfq + pop qword ptr [rcx + CxEFlags] + + // Restore original EFLags + push qword ptr [rsp + ExP3Home] + popfq + + // Save returned integer registers to InOutContext + mov [rcx + CxRax], rax + mov [rcx + CxRdx], rdx + mov [rcx + CxRbx], rbx + mov [rcx + CxRbp], rbp + mov [rcx + CxRsi], rsi + mov [rcx + CxRdi], rdi + mov [rcx + CxR8], r8 + mov [rcx + CxR9], r9 + mov [rcx + CxR10], r10 + mov [rcx + CxR11], r11 + mov [rcx + CxR12], r12 + mov [rcx + CxR13], r13 + mov [rcx + CxR14], r14 + mov [rcx + CxR15], r15 + + // Save the returned rcx in the context + mov rax, [rsp + ExP4Home] + mov [rcx + CxRcx], rax + + // Save returned floating point registers to InOutContext + stmxcsr [rcx + CxMxCsr] + fxsave [rcx + CxFltSave] + movaps [rcx + CxXmm0], xmm0 + movaps [rcx + CxXmm1], xmm1 + movaps [rcx + CxXmm2], xmm2 + movaps [rcx + CxXmm3], xmm3 + movaps [rcx + CxXmm4], xmm4 + movaps [rcx + CxXmm5], xmm5 + movaps [rcx + CxXmm6], xmm6 + movaps [rcx + CxXmm7], xmm7 + movaps [rcx + CxXmm8], xmm8 + movaps [rcx + CxXmm9], xmm9 + movaps [rcx + CxXmm10], xmm10 + movaps [rcx + CxXmm11], xmm11 + movaps [rcx + CxXmm12], xmm12 + movaps [rcx + CxXmm13], xmm13 + movaps [rcx + CxXmm14], xmm14 + movaps [rcx + CxXmm15], xmm15 + + // Save the expected return address + lea rax, ReturnAddress[rip] + mov [rcx + CxRip], rax + + // Save the expected stored rsp + mov [rcx + CxRsp], rsp + + // Restore the registers from the KEXCEPTION_FRAME + RESTORE_EXCEPTION_STATE + + ret + +ENDFUNC + + +END diff --git a/modules/rostests/apitests/rtl/amd64/RtlCaptureContext.c b/modules/rostests/apitests/rtl/amd64/RtlCaptureContext.c new file mode 100644 index 00000000000..80917428485 --- /dev/null +++ b/modules/rostests/apitests/rtl/amd64/RtlCaptureContext.c @@ -0,0 +1,243 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Test for x64 RtlCaptureContext + * COPYRIGHT: Copyright 2022 Timo Kreuzer timo.kreuzer@reactos.org + */ + +#include <rtltests.h> + +VOID +RtlCaptureContextWrapper( + _Inout_ PCONTEXT InOutContext, + _Out_ PCONTEXT CapturedContext); + +START_TEST(RtlCaptureContext) +{ + CONTEXT OriginalContext, InOutContext, CapturedContext; + SIZE_T Index, MaxIndex; + PUSHORT Buffer; + + /* Initialize a pattern */ + MaxIndex = sizeof(OriginalContext) / sizeof(USHORT); + Buffer = (PUSHORT)&OriginalContext; + for (Index = 0; Index < MaxIndex; Index++) + { + Buffer[Index] = Index; + } + + /* Set all valid bits in EFlags */ + OriginalContext.EFlags = 0xE7F; + + /* Set up a valid floating point state */ + OriginalContext.FltSave.ControlWord = 0x27f; + OriginalContext.FltSave.StatusWord = 0x1234; + OriginalContext.FltSave.TagWord = 0xab; + OriginalContext.FltSave.Reserved1 = 0x75; + OriginalContext.FltSave.MxCsr = 0x1f80; // Valid Mask is 2FFFF + OriginalContext.FltSave.MxCsr_Mask = 0xabcde; + + /* Set up a unique MxCsr. This one will overwrite FltSave.MxCsr */ + OriginalContext.MxCsr = 0xffff; // Valid Mask is 0xFFFF + + /* Copy the original buffer */ + InOutContext = OriginalContext; + + /* Fill the output buffer with bogus */ + RtlFillMemory(&CapturedContext, sizeof(CapturedContext), 0xCC); + + /* Call the wrapper function */ + RtlCaptureContextWrapper(&InOutContext, &CapturedContext); + + /* These fields are not changed */ + ok_eq_hex64(CapturedContext.P1Home, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.P2Home, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.P3Home, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.P4Home, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.P5Home, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.P6Home, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.Dr0, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.Dr1, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.Dr2, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.Dr3, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.Dr6, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.Dr7, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.VectorControl, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.DebugControl, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.LastBranchToRip, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.LastBranchFromRip, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.LastExceptionToRip, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.LastExceptionFromRip, 0xccccccccccccccccULL); + for (Index = 0; Index < ARRAYSIZE(CapturedContext.FltSave.Reserved4); Index++) + { + ok_eq_hex64(CapturedContext.FltSave.Reserved4[Index], 0xcc); + } + for (Index = 0; Index < ARRAYSIZE(CapturedContext.VectorRegister); Index++) + { + ok_eq_hex64(CapturedContext.VectorRegister[Index].Low, 0xccccccccccccccccULL); + ok_eq_hex64(CapturedContext.VectorRegister[Index].High, 0xccccccccccccccccULL); + } + + /* ContextFlags is set */ + ok_eq_hex(CapturedContext.ContextFlags, CONTEXT_FULL | CONTEXT_SEGMENTS); + + /* These vallues are as passed in */ + ok_eq_hex(CapturedContext.MxCsr, OriginalContext.MxCsr); + ok_eq_hex64(CapturedContext.Rax, OriginalContext.Rax); + ok_eq_hex64(CapturedContext.Rcx, (ULONG64)&CapturedContext); + ok_eq_hex64(CapturedContext.Rdx, OriginalContext.Rdx); + ok_eq_hex64(CapturedContext.Rbx, OriginalContext.Rbx); + ok_eq_hex64(CapturedContext.Rbp, OriginalContext.Rbp); + ok_eq_hex64(CapturedContext.Rsi, OriginalContext.Rsi); + ok_eq_hex64(CapturedContext.Rdi, OriginalContext.Rdi); + ok_eq_hex64(CapturedContext.R8, OriginalContext.R8); + ok_eq_hex64(CapturedContext.R9, OriginalContext.R9); + ok_eq_hex64(CapturedContext.R10, OriginalContext.R10); + ok_eq_hex64(CapturedContext.R11, OriginalContext.R11); + ok_eq_hex64(CapturedContext.R12, OriginalContext.R12); + ok_eq_hex64(CapturedContext.R13, OriginalContext.R13); + ok_eq_hex64(CapturedContext.R14, OriginalContext.R14); + ok_eq_hex64(CapturedContext.R15, OriginalContext.R15); + + ok_eq_xmm(CapturedContext.Xmm0, OriginalContext.Xmm0); + ok_eq_xmm(CapturedContext.Xmm1, OriginalContext.Xmm1); + ok_eq_xmm(CapturedContext.Xmm2, OriginalContext.Xmm2); + ok_eq_xmm(CapturedContext.Xmm3, OriginalContext.Xmm3); + ok_eq_xmm(CapturedContext.Xmm4, OriginalContext.Xmm4); + ok_eq_xmm(CapturedContext.Xmm5, OriginalContext.Xmm5); + ok_eq_xmm(CapturedContext.Xmm6, OriginalContext.Xmm6); + ok_eq_xmm(CapturedContext.Xmm7, OriginalContext.Xmm7); + ok_eq_xmm(CapturedContext.Xmm8, OriginalContext.Xmm8); + ok_eq_xmm(CapturedContext.Xmm9, OriginalContext.Xmm9); + ok_eq_xmm(CapturedContext.Xmm10, OriginalContext.Xmm10); + ok_eq_xmm(CapturedContext.Xmm11, OriginalContext.Xmm11); + ok_eq_xmm(CapturedContext.Xmm12, OriginalContext.Xmm12); + ok_eq_xmm(CapturedContext.Xmm13, OriginalContext.Xmm13); + ok_eq_xmm(CapturedContext.Xmm14, OriginalContext.Xmm14); + ok_eq_xmm(CapturedContext.Xmm15, OriginalContext.Xmm15); + + /* Some EFlags fields are cleared */ + ok_eq_hex64(CapturedContext.EFlags, OriginalContext.EFlags & ~0x28); + +#ifndef KMT_KERNEL_MODE // User mode + ok_eq_hex(CapturedContext.FltSave.ControlWord, 0x27f); + ok_eq_hex(CapturedContext.FltSave.StatusWord, OriginalContext.FltSave.StatusWord); + ok_eq_hex(CapturedContext.FltSave.TagWord, OriginalContext.FltSave.TagWord); + ok_eq_hex(CapturedContext.FltSave.Reserved1, 0x00); + ok_eq_hex(CapturedContext.FltSave.MxCsr_Mask, 0xffff); + ok_eq_hex(CapturedContext.FltSave.ErrorOpcode, 0x00000083); + ok_eq_hex(CapturedContext.FltSave.ErrorOffset, 0x00850084); + ok_eq_hex(CapturedContext.FltSave.ErrorSelector, 0x0086); + ok_eq_hex(CapturedContext.FltSave.Reserved2, 0x0000); + ok_eq_hex(CapturedContext.FltSave.DataOffset, 0x00890088); + ok_eq_hex(CapturedContext.FltSave.DataSelector, 0x008a); + ok_eq_hex(CapturedContext.FltSave.Reserved3, 0x0000); +#else + ok_eq_hex(CapturedContext.FltSave.ControlWord, 0xcccc); + ok_eq_hex(CapturedContext.FltSave.StatusWord, 0xcccc); + ok_eq_hex(CapturedContext.FltSave.TagWord, 0xcc); + ok_eq_hex(CapturedContext.FltSave.Reserved1, 0xcc); + ok_eq_hex(CapturedContext.FltSave.MxCsr_Mask, 0xcccccccc); + ok_eq_hex(CapturedContext.FltSave.ErrorOpcode, 0xcccc); + ok_eq_hex(CapturedContext.FltSave.ErrorOffset, 0xcccccccc); + ok_eq_hex(CapturedContext.FltSave.ErrorSelector, 0xcccc); + ok_eq_hex(CapturedContext.FltSave.Reserved2, 0xcccc); + ok_eq_hex(CapturedContext.FltSave.DataOffset, 0xcccccccc); + ok_eq_hex(CapturedContext.FltSave.DataSelector, 0xcccc); + ok_eq_hex(CapturedContext.FltSave.Reserved3, 0xcccc); +#endif + + /* We get the value from OriginalContext.MxCsr, since we set that later in the wrapper */ + ok_eq_hex(CapturedContext.FltSave.MxCsr, OriginalContext.MxCsr); + + /* Legacy floating point registers are truncated to 10 bytes */ + ok_eq_hex64(CapturedContext.Legacy[0].Low, OriginalContext.Legacy[0].Low); + ok_eq_hex64(CapturedContext.Legacy[0].High, OriginalContext.Legacy[0].High & 0xFF); + ok_eq_hex64(CapturedContext.Legacy[1].Low, OriginalContext.Legacy[1].Low); + ok_eq_hex64(CapturedContext.Legacy[1].High, OriginalContext.Legacy[1].High & 0xFF); + ok_eq_hex64(CapturedContext.Legacy[2].Low, OriginalContext.Legacy[2].Low); + ok_eq_hex64(CapturedContext.Legacy[2].High, OriginalContext.Legacy[2].High & 0xFF); + ok_eq_hex64(CapturedContext.Legacy[3].Low, OriginalContext.Legacy[3].Low); + ok_eq_hex64(CapturedContext.Legacy[3].High, OriginalContext.Legacy[3].High & 0xFF); + ok_eq_hex64(CapturedContext.Legacy[4].Low, OriginalContext.Legacy[4].Low); + ok_eq_hex64(CapturedContext.Legacy[4].High, OriginalContext.Legacy[4].High & 0xFF); + ok_eq_hex64(CapturedContext.Legacy[5].Low, OriginalContext.Legacy[5].Low); + ok_eq_hex64(CapturedContext.Legacy[5].High, OriginalContext.Legacy[5].High & 0xFF); + ok_eq_hex64(CapturedContext.Legacy[6].Low, OriginalContext.Legacy[6].Low); + ok_eq_hex64(CapturedContext.Legacy[6].High, OriginalContext.Legacy[6].High & 0xFF); + ok_eq_hex64(CapturedContext.Legacy[7].Low, OriginalContext.Legacy[7].Low); + ok_eq_hex64(CapturedContext.Legacy[7].High, OriginalContext.Legacy[7].High & 0xFF); + + /* We don't pass in segments, but expect the default values */ + ok_eq_hex(CapturedContext.SegCs, 0x33); + ok_eq_hex(CapturedContext.SegDs, 0x2b); + ok_eq_hex(CapturedContext.SegEs, 0x2b); + ok_eq_hex(CapturedContext.SegFs, 0x53); + ok_eq_hex(CapturedContext.SegGs, 0x2b); + ok_eq_hex(CapturedContext.SegSs, 0x2b); + + /* For Rsp and Rip we get the expected value back from the asm wrapper */ + ok_eq_hex64(CapturedContext.Rsp, InOutContext.Rsp); + ok_eq_hex64(CapturedContext.Rip, InOutContext.Rip); + + /* Check that these registers are not modified by RtlCaptureContext */ + ok_eq_xmm(InOutContext.Xmm0, OriginalContext.Xmm0); + ok_eq_xmm(InOutContext.Xmm1, OriginalContext.Xmm1); + ok_eq_xmm(InOutContext.Xmm2, OriginalContext.Xmm2); + ok_eq_xmm(InOutContext.Xmm3, OriginalContext.Xmm3); + ok_eq_xmm(InOutContext.Xmm4, OriginalContext.Xmm4); + ok_eq_xmm(InOutContext.Xmm5, OriginalContext.Xmm5); + ok_eq_xmm(InOutContext.Xmm6, OriginalContext.Xmm6); + ok_eq_xmm(InOutContext.Xmm7, OriginalContext.Xmm7); + ok_eq_xmm(InOutContext.Xmm8, OriginalContext.Xmm8); + ok_eq_xmm(InOutContext.Xmm9, OriginalContext.Xmm9); + ok_eq_xmm(InOutContext.Xmm10, OriginalContext.Xmm10); + ok_eq_xmm(InOutContext.Xmm11, OriginalContext.Xmm11); + ok_eq_xmm(InOutContext.Xmm12, OriginalContext.Xmm12); + ok_eq_xmm(InOutContext.Xmm13, OriginalContext.Xmm13); + ok_eq_xmm(InOutContext.Xmm14, OriginalContext.Xmm14); + ok_eq_xmm(InOutContext.Xmm15, OriginalContext.Xmm15); + ok_eq_hex64(InOutContext.Rdx, OriginalContext.Rdx); + ok_eq_hex64(InOutContext.Rbx, OriginalContext.Rbx); + ok_eq_hex64(InOutContext.Rbp, OriginalContext.Rbp); + ok_eq_hex64(InOutContext.Rsi, OriginalContext.Rsi); + ok_eq_hex64(InOutContext.Rdi, OriginalContext.Rdi); + ok_eq_hex64(InOutContext.R8, OriginalContext.R8); + ok_eq_hex64(InOutContext.R9, OriginalContext.R9); + ok_eq_hex64(InOutContext.R10, OriginalContext.R10); + ok_eq_hex64(InOutContext.R11, OriginalContext.R11); + ok_eq_hex64(InOutContext.R12, OriginalContext.R12); + ok_eq_hex64(InOutContext.R13, OriginalContext.R13); + ok_eq_hex64(InOutContext.R14, OriginalContext.R14); + ok_eq_hex64(InOutContext.R15, OriginalContext.R15); + + /* Eflags is changed (parity is flaky) */ + ok_eq_hex64(InOutContext.EFlags & ~0x04, OriginalContext.EFlags & 0x782); + + /* MxCsr is the one we passed in in OriginalContext.MxCsr */ + ok_eq_hex(InOutContext.MxCsr, OriginalContext.MxCsr); + ok_eq_hex(InOutContext.FltSave.MxCsr, OriginalContext.MxCsr); + + /* Rcx still points to the captured context */ + ok_eq_hex64(InOutContext.Rcx, (ULONG64)&CapturedContext); + + /* Rax contains eflags */ + ok_eq_hex64(InOutContext.Rax, CapturedContext.EFlags); + + /* Second run with minimal EFLags/MxCsr */ + OriginalContext.EFlags = 0x200; + OriginalContext.MxCsr = 0x0000; + InOutContext = OriginalContext; + RtlFillMemory(&CapturedContext, sizeof(CapturedContext), 0xCC); + RtlCaptureContextWrapper(&InOutContext, &CapturedContext); + + /* Captured Eflags has reserved flag set (which is always 1) */ + ok_eq_hex64(CapturedContext.EFlags, OriginalContext.EFlags | 2); + + /* Parity flag is flaky */ + ok_eq_hex64(InOutContext.EFlags & ~4, CapturedContext.EFlags); + + /* MxCsr is captured/returned as passed in */ + ok_eq_hex64(InOutContext.MxCsr, CapturedContext.MxCsr); + ok_eq_hex64(CapturedContext.MxCsr, OriginalContext.MxCsr); +} diff --git a/modules/rostests/apitests/rtl/i386/RtlCaptureContext.c b/modules/rostests/apitests/rtl/i386/RtlCaptureContext.c new file mode 100644 index 00000000000..eccf129b633 --- /dev/null +++ b/modules/rostests/apitests/rtl/i386/RtlCaptureContext.c @@ -0,0 +1,18 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Test for x86 RtlCaptureContext + * COPYRIGHT: Copyright 2022 Timo Kreuzer timo.kreuzer@reactos.org + */ + +#include <rtltests.h> + +VOID +RtlCaptureContextWrapper( + _Inout_ PCONTEXT InOutContext, + _Out_ PCONTEXT CapturedContext); + +START_TEST(RtlCaptureContext) +{ + // TODO +} diff --git a/modules/rostests/apitests/rtl/ldrstubs.c b/modules/rostests/apitests/rtl/ldrstubs.c new file mode 100644 index 00000000000..c04ac0837bb --- /dev/null +++ b/modules/rostests/apitests/rtl/ldrstubs.c @@ -0,0 +1,17 @@ +#include <rtltests.h> +#include <pseh/pseh2.h> +#include <compat_undoc.h> +#include <compatguid_undoc.h> + +#define NDEBUG +#include <debug.h> + +BOOLEAN LdrpShutdownInProgress; +HANDLE LdrpShutdownThreadId; + +VOID +NTAPI +LdrpInitializeProcessCompat(PVOID pProcessActctx, PVOID* pOldShimData) +{ +} + diff --git a/modules/rostests/apitests/rtl/rtltests.h b/modules/rostests/apitests/rtl/rtltests.h new file mode 100644 index 00000000000..f6bf7c007e8 --- /dev/null +++ b/modules/rostests/apitests/rtl/rtltests.h @@ -0,0 +1,12 @@ + +#pragma once + +#include <stdio.h> + +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H + +#include <apitest.h> +#include <ndk/ntndk.h> +#include <strsafe.h> diff --git a/modules/rostests/apitests/rtl/testlist.c b/modules/rostests/apitests/rtl/testlist.c new file mode 100644 index 00000000000..ca7ad4c2a50 --- /dev/null +++ b/modules/rostests/apitests/rtl/testlist.c @@ -0,0 +1,15 @@ +#define __ROS_LONG64__ + +#define STANDALONE +#include <apitest.h> + +extern void func_RtlCaptureContext(void); + +const struct test winetest_testlist[] = +{ +#ifdef _M_AMD64 + { "RtlCaptureContext", func_RtlCaptureContext }, +#endif + + { 0, 0 } +}; diff --git a/modules/rostests/kmtests/CMakeLists.txt b/modules/rostests/kmtests/CMakeLists.txt index da4d3288342..4dd5572b13a 100644 --- a/modules/rostests/kmtests/CMakeLists.txt +++ b/modules/rostests/kmtests/CMakeLists.txt @@ -26,6 +26,16 @@ list(APPEND COMMON_SOURCE rtl/RtlStrSafe.c rtl/RtlUnicodeString.c)
+if(ARCH STREQUAL "i386") + +elseif(ARCH STREQUAL "amd64") + add_asm_files(kmtest_common_asm ../apitests/rtl/amd64/RtlCaptureContext-asm.s) + list(APPEND COMMON_SOURCE + ../apitests/rtl/amd64/RtlCaptureContext.c + ${kmtest_common_asm} + ) +endif() + # # kmtest_drv.sys driver # diff --git a/modules/rostests/kmtests/include/rtltests.h b/modules/rostests/kmtests/include/rtltests.h new file mode 100644 index 00000000000..ec53f937fd7 --- /dev/null +++ b/modules/rostests/kmtests/include/rtltests.h @@ -0,0 +1,5 @@ + +#pragma once + +#define KMT_EMULATE_KERNEL +#include <kmt_test.h> diff --git a/modules/rostests/kmtests/kmtest/testlist.c b/modules/rostests/kmtests/kmtest/testlist.c index 5461e2ffe37..9f9197e3bff 100644 --- a/modules/rostests/kmtests/kmtest/testlist.c +++ b/modules/rostests/kmtests/kmtest/testlist.c @@ -25,6 +25,7 @@ KMT_TESTFUNC Test_MmMapLockedPagesSpecifyCache; KMT_TESTFUNC Test_NtCreateSection; KMT_TESTFUNC Test_PoIrp; KMT_TESTFUNC Test_RtlAvlTree; +KMT_TESTFUNC Test_RtlCaptureContext; KMT_TESTFUNC Test_RtlException; KMT_TESTFUNC Test_RtlIntSafe; KMT_TESTFUNC Test_RtlMemory; @@ -69,5 +70,8 @@ const KMT_TEST TestList[] = { "RtlUnicodeString", Test_RtlUnicodeString }, { "TcpIpTdi", Test_TcpIpTdi }, { "TcpIpConnect", Test_TcpIpConnect }, +#ifdef _M_AMD64 + { "RtlCaptureContext", Test_RtlCaptureContext }, +#endif { NULL, NULL }, }; diff --git a/modules/rostests/kmtests/kmtest_drv/testlist.c b/modules/rostests/kmtests/kmtest_drv/testlist.c index 73daeba02df..1bc9fd00336 100644 --- a/modules/rostests/kmtests/kmtest_drv/testlist.c +++ b/modules/rostests/kmtests/kmtest_drv/testlist.c @@ -71,6 +71,7 @@ KMT_TESTFUNC Test_SeLogonSession; KMT_TESTFUNC Test_SeQueryInfoToken; KMT_TESTFUNC Test_SeTokenFiltering; KMT_TESTFUNC Test_RtlAvlTree; +KMT_TESTFUNC Test_RtlCaptureContext; KMT_TESTFUNC Test_RtlException; KMT_TESTFUNC Test_RtlIntSafe; KMT_TESTFUNC Test_RtlIsValidOemCharacter; @@ -167,5 +168,8 @@ const KMT_TEST TestList[] = { "ZwCreateSection", Test_ZwCreateSection }, { "ZwMapViewOfSection", Test_ZwMapViewOfSection }, { "ZwWaitForMultipleObjects", Test_ZwWaitForMultipleObjects}, +#ifdef _M_AMD64 + { "RtlCaptureContext", Test_RtlCaptureContext }, +#endif { NULL, NULL } };