mirror of
https://github.com/reactos/reactos.git
synced 2024-11-02 04:37:32 +00:00
f1e5bc3d74
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.
167 lines
5 KiB
C
167 lines
5 KiB
C
/*
|
|
* 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);
|
|
}
|
|
}
|