reactos/modules/rostests/apitests/loadconfig/stacktrace.c

167 lines
5 KiB
C
Raw Normal View History

/*
* 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);
}
}