mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 17:12:57 +00:00
[RTL_APITEST] Add rtl_unittest
First test is RtlCaptureContext
This commit is contained in:
parent
51b5d846e9
commit
bdf52a9868
14 changed files with 574 additions and 2 deletions
|
@ -40,6 +40,7 @@ add_subdirectory(ole32)
|
||||||
add_subdirectory(opengl32)
|
add_subdirectory(opengl32)
|
||||||
add_subdirectory(pefile)
|
add_subdirectory(pefile)
|
||||||
add_subdirectory(powrprof)
|
add_subdirectory(powrprof)
|
||||||
|
add_subdirectory(rtl)
|
||||||
add_subdirectory(sdk)
|
add_subdirectory(sdk)
|
||||||
add_subdirectory(setupapi)
|
add_subdirectory(setupapi)
|
||||||
add_subdirectory(sfc)
|
add_subdirectory(sfc)
|
||||||
|
|
|
@ -101,7 +101,8 @@ list(APPEND SOURCE
|
||||||
StackOverflow.c
|
StackOverflow.c
|
||||||
SystemInfo.c
|
SystemInfo.c
|
||||||
UserModeException.c
|
UserModeException.c
|
||||||
Timer.c)
|
Timer.c
|
||||||
|
precomp.h)
|
||||||
|
|
||||||
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)
|
||||||
|
@ -126,7 +127,7 @@ set_target_properties(ntdll_apitest
|
||||||
ENABLE_EXPORTS TRUE
|
ENABLE_EXPORTS TRUE
|
||||||
DEFINE_SYMBOL "")
|
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)
|
set_module_type(ntdll_apitest win32cui)
|
||||||
add_importlibs(ntdll_apitest msvcrt advapi32 kernel32 ntdll)
|
add_importlibs(ntdll_apitest msvcrt advapi32 kernel32 ntdll)
|
||||||
add_pch(ntdll_apitest precomp.h "${PCH_SKIP_SOURCE}")
|
add_pch(ntdll_apitest precomp.h "${PCH_SKIP_SOURCE}")
|
||||||
|
|
|
@ -54,6 +54,7 @@ extern void func_NtUnloadDriver(void);
|
||||||
extern void func_NtWriteFile(void);
|
extern void func_NtWriteFile(void);
|
||||||
extern void func_RtlAllocateHeap(void);
|
extern void func_RtlAllocateHeap(void);
|
||||||
extern void func_RtlBitmap(void);
|
extern void func_RtlBitmap(void);
|
||||||
|
extern void func_RtlCaptureContext(void);
|
||||||
extern void func_RtlComputePrivatizedDllName_U(void);
|
extern void func_RtlComputePrivatizedDllName_U(void);
|
||||||
extern void func_RtlCopyMappedMemory(void);
|
extern void func_RtlCopyMappedMemory(void);
|
||||||
extern void func_RtlCriticalSection(void);
|
extern void func_RtlCriticalSection(void);
|
||||||
|
@ -194,6 +195,9 @@ const struct test winetest_testlist[] =
|
||||||
{ "StackOverflow", func_StackOverflow },
|
{ "StackOverflow", func_StackOverflow },
|
||||||
{ "TimerResolution", func_TimerResolution },
|
{ "TimerResolution", func_TimerResolution },
|
||||||
{ "UserModeException", func_UserModeException },
|
{ "UserModeException", func_UserModeException },
|
||||||
|
#ifdef _M_AMD64
|
||||||
|
{ "RtlCaptureContext", func_RtlCaptureContext },
|
||||||
|
#endif
|
||||||
|
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
56
modules/rostests/apitests/rtl/CMakeLists.txt
Normal file
56
modules/rostests/apitests/rtl/CMakeLists.txt
Normal file
|
@ -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()
|
182
modules/rostests/apitests/rtl/amd64/RtlCaptureContext-asm.s
Normal file
182
modules/rostests/apitests/rtl/amd64/RtlCaptureContext-asm.s
Normal file
|
@ -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
|
243
modules/rostests/apitests/rtl/amd64/RtlCaptureContext.c
Normal file
243
modules/rostests/apitests/rtl/amd64/RtlCaptureContext.c
Normal file
|
@ -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);
|
||||||
|
}
|
18
modules/rostests/apitests/rtl/i386/RtlCaptureContext.c
Normal file
18
modules/rostests/apitests/rtl/i386/RtlCaptureContext.c
Normal file
|
@ -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
|
||||||
|
}
|
17
modules/rostests/apitests/rtl/ldrstubs.c
Normal file
17
modules/rostests/apitests/rtl/ldrstubs.c
Normal file
|
@ -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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
12
modules/rostests/apitests/rtl/rtltests.h
Normal file
12
modules/rostests/apitests/rtl/rtltests.h
Normal file
|
@ -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>
|
15
modules/rostests/apitests/rtl/testlist.c
Normal file
15
modules/rostests/apitests/rtl/testlist.c
Normal file
|
@ -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 }
|
||||||
|
};
|
|
@ -26,6 +26,16 @@ list(APPEND COMMON_SOURCE
|
||||||
rtl/RtlStrSafe.c
|
rtl/RtlStrSafe.c
|
||||||
rtl/RtlUnicodeString.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
|
# kmtest_drv.sys driver
|
||||||
#
|
#
|
||||||
|
|
5
modules/rostests/kmtests/include/rtltests.h
Normal file
5
modules/rostests/kmtests/include/rtltests.h
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define KMT_EMULATE_KERNEL
|
||||||
|
#include <kmt_test.h>
|
|
@ -25,6 +25,7 @@ KMT_TESTFUNC Test_MmMapLockedPagesSpecifyCache;
|
||||||
KMT_TESTFUNC Test_NtCreateSection;
|
KMT_TESTFUNC Test_NtCreateSection;
|
||||||
KMT_TESTFUNC Test_PoIrp;
|
KMT_TESTFUNC Test_PoIrp;
|
||||||
KMT_TESTFUNC Test_RtlAvlTree;
|
KMT_TESTFUNC Test_RtlAvlTree;
|
||||||
|
KMT_TESTFUNC Test_RtlCaptureContext;
|
||||||
KMT_TESTFUNC Test_RtlException;
|
KMT_TESTFUNC Test_RtlException;
|
||||||
KMT_TESTFUNC Test_RtlIntSafe;
|
KMT_TESTFUNC Test_RtlIntSafe;
|
||||||
KMT_TESTFUNC Test_RtlMemory;
|
KMT_TESTFUNC Test_RtlMemory;
|
||||||
|
@ -69,5 +70,8 @@ const KMT_TEST TestList[] =
|
||||||
{ "RtlUnicodeString", Test_RtlUnicodeString },
|
{ "RtlUnicodeString", Test_RtlUnicodeString },
|
||||||
{ "TcpIpTdi", Test_TcpIpTdi },
|
{ "TcpIpTdi", Test_TcpIpTdi },
|
||||||
{ "TcpIpConnect", Test_TcpIpConnect },
|
{ "TcpIpConnect", Test_TcpIpConnect },
|
||||||
|
#ifdef _M_AMD64
|
||||||
|
{ "RtlCaptureContext", Test_RtlCaptureContext },
|
||||||
|
#endif
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,6 +71,7 @@ KMT_TESTFUNC Test_SeLogonSession;
|
||||||
KMT_TESTFUNC Test_SeQueryInfoToken;
|
KMT_TESTFUNC Test_SeQueryInfoToken;
|
||||||
KMT_TESTFUNC Test_SeTokenFiltering;
|
KMT_TESTFUNC Test_SeTokenFiltering;
|
||||||
KMT_TESTFUNC Test_RtlAvlTree;
|
KMT_TESTFUNC Test_RtlAvlTree;
|
||||||
|
KMT_TESTFUNC Test_RtlCaptureContext;
|
||||||
KMT_TESTFUNC Test_RtlException;
|
KMT_TESTFUNC Test_RtlException;
|
||||||
KMT_TESTFUNC Test_RtlIntSafe;
|
KMT_TESTFUNC Test_RtlIntSafe;
|
||||||
KMT_TESTFUNC Test_RtlIsValidOemCharacter;
|
KMT_TESTFUNC Test_RtlIsValidOemCharacter;
|
||||||
|
@ -167,5 +168,8 @@ const KMT_TEST TestList[] =
|
||||||
{ "ZwCreateSection", Test_ZwCreateSection },
|
{ "ZwCreateSection", Test_ZwCreateSection },
|
||||||
{ "ZwMapViewOfSection", Test_ZwMapViewOfSection },
|
{ "ZwMapViewOfSection", Test_ZwMapViewOfSection },
|
||||||
{ "ZwWaitForMultipleObjects", Test_ZwWaitForMultipleObjects},
|
{ "ZwWaitForMultipleObjects", Test_ZwWaitForMultipleObjects},
|
||||||
|
#ifdef _M_AMD64
|
||||||
|
{ "RtlCaptureContext", Test_RtlCaptureContext },
|
||||||
|
#endif
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue