[LOADCONFIG_APITEST] Add apitest using the load config section

For now, the only test is related to a user trace stack db.
The entire test application is disabled for gcc,
since it is unable to generate this load config info.
The stacktrace test is disabled until it is implemented.
This commit is contained in:
Mark Jansen 2020-04-11 22:30:47 +02:00
parent d778d04a16
commit f1e5bc3d74
No known key found for this signature in database
GPG Key ID: B39240EE84BEAE8B
6 changed files with 279 additions and 0 deletions

View File

@ -22,6 +22,11 @@ add_subdirectory(gdi32)
add_subdirectory(gditools)
add_subdirectory(iphlpapi)
add_subdirectory(kernel32)
if(NOT GCC)
# gcc / binutils are unable to add an IMAGE_LOAD_CONFIG_DIRECTORY
# So maybe we should resuscitate sdk/tools/pefixup.c
add_subdirectory(loadconfig)
endif()
add_subdirectory(localspl)
add_subdirectory(mountmgr)
add_subdirectory(msgina)

View File

@ -0,0 +1,12 @@
list(APPEND SOURCE
common.c
stacktrace.c
loadconfig.h)
add_executable(loadconfig_apitest ${SOURCE} testlist.c)
target_link_libraries(loadconfig_apitest wine ${PSEH_LIB})
set_module_type(loadconfig_apitest win32cui)
add_importlibs(loadconfig_apitest msvcrt kernel32 ntdll)
add_pch(loadconfig_apitest loadconfig.h SOURCE)
add_rostests_file(TARGET loadconfig_apitest)

View File

@ -0,0 +1,70 @@
/*
* PROJECT: ReactOS API tests
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: LOAD_CONFIG validation / registration
* COPYRIGHT: Copyright 2020 Mark Jansen (mark.jansen@reactos.org)
*/
#include "loadconfig.h"
// Tell the linker we want a LOAD_CONFIG
const IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used =
{
sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
0, // TimeDateStamp
0, // MajorVersion
0, // MinorVersion
0, // GlobalFlagsClear
FLG_USER_STACK_TRACE_DB, // GlobalFlagsSet
0, // CriticalSectionDefaultTimeout
0, // DeCommitFreeBlockThreshold
0, // DeCommitTotalFreeThreshold
0, // LockPrefixTable
0, // MaximumAllocationSize
0, // VirtualMemoryThreshold
0, // ProcessHeapFlags
0, // ProcessAffinityMask
0, // CSDVersion
0, // Reserved1
0, // EditList
0, // SecurityCookie
};
BOOL check_loadconfig()
{
BOOL Result;
PPEB Peb = NtCurrentPeb();
ULONG ConfigSize = 0;
ULONG MinimalSize;
PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
// Validate the required flag for the 'stacktrace' test
ok(Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB, "NtGlobalFlag: 0x%lx\n", Peb->NtGlobalFlag);
Result = (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB) != 0;
// Now validate our LOAD_CONFIG entry
LoadConfig = (PIMAGE_LOAD_CONFIG_DIRECTORY)RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
TRUE,
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
&ConfigSize);
MinimalSize = FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie) + sizeof(LoadConfig->SecurityCookie);
if (!LoadConfig || ConfigSize < MinimalSize)
{
ok(0, "Invalid IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: %p, %lu (%lu)\n",
LoadConfig, ConfigSize, MinimalSize);
}
else
{
ok(LoadConfig->GlobalFlagsSet & FLG_USER_STACK_TRACE_DB,
"Invalid GlobalFlagsSet: %lx\n", LoadConfig->GlobalFlagsSet);
ok(!(LoadConfig->GlobalFlagsClear & FLG_USER_STACK_TRACE_DB),
"Invalid GlobalFlagsClear: %lx\n", LoadConfig->GlobalFlagsClear);
ok(LoadConfig->Size == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
"Unexpected size difference: %lu vs %u\n", LoadConfig->Size, sizeof(IMAGE_LOAD_CONFIG_DIRECTORY));
}
return Result;
}

View File

@ -0,0 +1,14 @@
#pragma once
#define WIN32_NO_STATUS
#define _INC_WINDOWS
#define COM_NO_WINDOWS_H
#include <apitest.h>
#include <apitest_guard.h>
#include <ndk/ntndk.h>
#include <strsafe.h>
/* common.c */
BOOL check_loadconfig();

View File

@ -0,0 +1,166 @@
/*
* PROJECT: ReactOS API tests
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Test for RtlQueryProcessBackTraceInformation & RtlLogStackBackTrace
* COPYRIGHT: Copyright 2020 Mark Jansen (mark.jansen@reactos.org)
*/
#include "loadconfig.h"
// This test serves 2 purposes:
// 1. It tests RtlQueryProcessBackTraceInformation & RtlLogStackBackTrace
// 2. It tests the correct activation of IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG (see also common.c)
NTSTATUS NTAPI RtlQueryProcessBackTraceInformation(IN OUT PRTL_DEBUG_INFORMATION Buffer);
// Seems that this struct is wrong in our sdk?
typedef struct _RTL_PROCESS_BACKTRACE_INFORMATION_32
{
PVOID SymbolicBackTrace;
ULONG TraceCount;
USHORT Index;
USHORT Depth;
PVOID BackTrace[32];
} RTL_PROCESS_BACKTRACE_INFORMATION_32, *PRTL_PROCESS_BACKTRACE_INFORMATION_32;
static PVOID g_Call_Address;
static PVOID g_PreviousReturnAddress;
__declspec(noinline)
PVOID GetFunctionAddress()
{
return _ReturnAddress();
}
__declspec(noinline)
USHORT Call_Backtrace_2()
{
USHORT Index;
Index = RtlLogStackBackTrace();
ok(Index != 0, "RtlLogStackBackTrace failed\n");
return Index;
}
__declspec(noinline)
USHORT Call_Backtrace_1()
{
USHORT Index;
// It seems that the function calling RtlLogStackBackTrace is skipped,
// so we wrap it in a deeper nested function to be able to check it
g_Call_Address = GetFunctionAddress();
g_PreviousReturnAddress = _ReturnAddress();
Index = Call_Backtrace_2();
return Index;
}
static void Check_Stacktrace(PVOID* BackTrace, USHORT Depth)
{
ok(Depth > 2, "Unexpected Depth: %lu\n", (ULONG)Depth);
if (Depth > 2)
{
ULONG_PTR EndAddress = ((ULONG_PTR)g_Call_Address + 0x20);
ok(BackTrace[0] >= g_Call_Address && (ULONG_PTR)BackTrace[0] < EndAddress,
"Unexpected return: %p, expected between %p and %p\n", BackTrace[0], g_Call_Address, (PVOID)EndAddress);
ok(BackTrace[1] == g_PreviousReturnAddress, "Unexpected return: %p, expected: %p\n",
BackTrace[1], g_PreviousReturnAddress);
}
}
static void test_QueryBacktrace(PRTL_DEBUG_INFORMATION Buffer1, PRTL_DEBUG_INFORMATION Buffer2)
{
NTSTATUS Status;
USHORT StackTrace;
PRTL_PROCESS_BACKTRACES Backtraces;
ULONG OldNumberOfBackTraces, n;
PRTL_PROCESS_BACKTRACE_INFORMATION_32 FirstBacktrace;
int found = 0;
Status = RtlQueryProcessBackTraceInformation(Buffer1);
ok_hex(Status, STATUS_SUCCESS);
if (Status != STATUS_SUCCESS)
return;
Backtraces = Buffer1->BackTraces;
ok(Backtraces != NULL, "No BackTraces\n");
if (!Backtraces)
return;
OldNumberOfBackTraces = Backtraces->NumberOfBackTraces;
// Capture a stacktrace
StackTrace = Call_Backtrace_1();
// Show that the old debugbuffer is not changed
ok(OldNumberOfBackTraces == Backtraces->NumberOfBackTraces, "Debug buffer changed! (%lu => %lu)\n",
OldNumberOfBackTraces, Backtraces->NumberOfBackTraces);
// Ask for a new snapshot
Status = RtlQueryProcessBackTraceInformation(Buffer2);
ok_hex(Status, STATUS_SUCCESS);
if (Status != STATUS_SUCCESS)
return;
Backtraces = Buffer2->BackTraces;
ok(Backtraces != NULL, "No BackTraces\n");
if (!Backtraces)
return;
ok(OldNumberOfBackTraces+1 == Backtraces->NumberOfBackTraces, "Stacktrace not added! (%lu => %lu)\n",
OldNumberOfBackTraces, Backtraces->NumberOfBackTraces);
FirstBacktrace = (PRTL_PROCESS_BACKTRACE_INFORMATION_32)&Backtraces->BackTraces[0];
trace("NumberOfBackTraces=%lu\n", Backtraces->NumberOfBackTraces);
for (n = 0; n < Backtraces->NumberOfBackTraces; ++n)
{
PRTL_PROCESS_BACKTRACE_INFORMATION_32 Info = FirstBacktrace + n;
#if 0
USHORT j;
trace("BackTraces[%02lu]->SymbolicBackTrace = %p\n", n, Info->SymbolicBackTrace);
trace("BackTraces[%02lu]->TraceCount = %lu\n", n, Info->TraceCount);
trace("BackTraces[%02lu]->Index = %lu\n", n, (ULONG)Info->Index);
trace("BackTraces[%02lu]->Depth = %lu\n", n, (ULONG)Info->Depth);
for (j = 0; j < Info->Depth; ++j)
{
trace("BackTraces[%02lu]->BackTrace[%02u] = %p\n", n, j, Info->BackTrace[j]);
}
trace("\n");
#endif
if (Info->Index == StackTrace)
{
found = 1;
Check_Stacktrace(Info->BackTrace, Info->Depth);
}
}
ok(found, "Stacktrace not found :(\n");
}
START_TEST(stacktrace)
{
PRTL_DEBUG_INFORMATION Buffer1, Buffer2;
if (!check_loadconfig())
return;
skip("QueryBacktrace not implemented yet\n");
return;
Buffer1 = RtlCreateQueryDebugBuffer(0, FALSE);
ok(Buffer1 != NULL, "Failed!\n");
if (Buffer1)
{
Buffer2 = RtlCreateQueryDebugBuffer(0, FALSE);
ok(Buffer2 != NULL, "Failed!\n");
if (Buffer2)
{
test_QueryBacktrace(Buffer1, Buffer2);
RtlDestroyQueryDebugBuffer(Buffer2);
}
RtlDestroyQueryDebugBuffer(Buffer1);
}
}

View File

@ -0,0 +1,12 @@
#define STANDALONE
#include <apitest.h>
extern void func_stacktrace(void);
const struct test winetest_testlist[] =
{
{ "stacktrace", func_stacktrace },
{ 0, 0 }
};