1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Test for RtlQueryProcessBackTraceInformation & RtlLogStackBackTrace 5 * COPYRIGHT: Copyright 2020 Mark Jansen (mark.jansen@reactos.org) 6 */ 7 8 #include "loadconfig.h" 9 10 11 // This test serves 2 purposes: 12 // 1. It tests RtlQueryProcessBackTraceInformation & RtlLogStackBackTrace 13 // 2. It tests the correct activation of IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG (see also common.c) 14 15 NTSTATUS NTAPI RtlQueryProcessBackTraceInformation(IN OUT PRTL_DEBUG_INFORMATION Buffer); 16 17 18 // Seems that this struct is wrong in our sdk? 19 typedef struct _RTL_PROCESS_BACKTRACE_INFORMATION_32 20 { 21 PVOID SymbolicBackTrace; 22 ULONG TraceCount; 23 USHORT Index; 24 USHORT Depth; 25 PVOID BackTrace[32]; 26 } RTL_PROCESS_BACKTRACE_INFORMATION_32, *PRTL_PROCESS_BACKTRACE_INFORMATION_32; 27 28 29 static PVOID g_Call_Address; 30 static PVOID g_PreviousReturnAddress; 31 32 __declspec(noinline) 33 PVOID GetFunctionAddress() 34 { 35 return _ReturnAddress(); 36 } 37 38 __declspec(noinline) 39 USHORT Call_Backtrace_2() 40 { 41 USHORT Index; 42 Index = RtlLogStackBackTrace(); 43 ok(Index != 0, "RtlLogStackBackTrace failed\n"); 44 return Index; 45 } 46 47 48 __declspec(noinline) 49 USHORT Call_Backtrace_1() 50 { 51 USHORT Index; 52 // It seems that the function calling RtlLogStackBackTrace is skipped, 53 // so we wrap it in a deeper nested function to be able to check it 54 g_Call_Address = GetFunctionAddress(); 55 g_PreviousReturnAddress = _ReturnAddress(); 56 Index = Call_Backtrace_2(); 57 return Index; 58 } 59 60 static void Check_Stacktrace(PVOID* BackTrace, USHORT Depth) 61 { 62 ok(Depth > 2, "Unexpected Depth: %lu\n", (ULONG)Depth); 63 if (Depth > 2) 64 { 65 ULONG_PTR EndAddress = ((ULONG_PTR)g_Call_Address + 0x20); 66 ok(BackTrace[0] >= g_Call_Address && (ULONG_PTR)BackTrace[0] < EndAddress, 67 "Unexpected return: %p, expected between %p and %p\n", BackTrace[0], g_Call_Address, (PVOID)EndAddress); 68 ok(BackTrace[1] == g_PreviousReturnAddress, "Unexpected return: %p, expected: %p\n", 69 BackTrace[1], g_PreviousReturnAddress); 70 } 71 } 72 73 static void test_QueryBacktrace(PRTL_DEBUG_INFORMATION Buffer1, PRTL_DEBUG_INFORMATION Buffer2) 74 { 75 NTSTATUS Status; 76 USHORT StackTrace; 77 PRTL_PROCESS_BACKTRACES Backtraces; 78 ULONG OldNumberOfBackTraces, n; 79 PRTL_PROCESS_BACKTRACE_INFORMATION_32 FirstBacktrace; 80 int found = 0; 81 82 Status = RtlQueryProcessBackTraceInformation(Buffer1); 83 ok_hex(Status, STATUS_SUCCESS); 84 if (Status != STATUS_SUCCESS) 85 return; 86 87 Backtraces = Buffer1->BackTraces; 88 ok(Backtraces != NULL, "No BackTraces\n"); 89 if (!Backtraces) 90 return; 91 92 OldNumberOfBackTraces = Backtraces->NumberOfBackTraces; 93 // Capture a stacktrace 94 StackTrace = Call_Backtrace_1(); 95 96 // Show that the old debugbuffer is not changed 97 ok(OldNumberOfBackTraces == Backtraces->NumberOfBackTraces, "Debug buffer changed! (%lu => %lu)\n", 98 OldNumberOfBackTraces, Backtraces->NumberOfBackTraces); 99 100 // Ask for a new snapshot 101 Status = RtlQueryProcessBackTraceInformation(Buffer2); 102 ok_hex(Status, STATUS_SUCCESS); 103 if (Status != STATUS_SUCCESS) 104 return; 105 106 Backtraces = Buffer2->BackTraces; 107 ok(Backtraces != NULL, "No BackTraces\n"); 108 if (!Backtraces) 109 return; 110 111 ok(OldNumberOfBackTraces+1 == Backtraces->NumberOfBackTraces, "Stacktrace not added! (%lu => %lu)\n", 112 OldNumberOfBackTraces, Backtraces->NumberOfBackTraces); 113 114 FirstBacktrace = (PRTL_PROCESS_BACKTRACE_INFORMATION_32)&Backtraces->BackTraces[0]; 115 trace("NumberOfBackTraces=%lu\n", Backtraces->NumberOfBackTraces); 116 for (n = 0; n < Backtraces->NumberOfBackTraces; ++n) 117 { 118 PRTL_PROCESS_BACKTRACE_INFORMATION_32 Info = FirstBacktrace + n; 119 #if 0 120 USHORT j; 121 122 trace("BackTraces[%02lu]->SymbolicBackTrace = %p\n", n, Info->SymbolicBackTrace); 123 trace("BackTraces[%02lu]->TraceCount = %lu\n", n, Info->TraceCount); 124 trace("BackTraces[%02lu]->Index = %lu\n", n, (ULONG)Info->Index); 125 trace("BackTraces[%02lu]->Depth = %lu\n", n, (ULONG)Info->Depth); 126 for (j = 0; j < Info->Depth; ++j) 127 { 128 trace("BackTraces[%02lu]->BackTrace[%02u] = %p\n", n, j, Info->BackTrace[j]); 129 } 130 trace("\n"); 131 #endif 132 if (Info->Index == StackTrace) 133 { 134 found = 1; 135 Check_Stacktrace(Info->BackTrace, Info->Depth); 136 } 137 } 138 ok(found, "Stacktrace not found :(\n"); 139 } 140 141 142 START_TEST(stacktrace) 143 { 144 PRTL_DEBUG_INFORMATION Buffer1, Buffer2; 145 146 if (!check_loadconfig()) 147 return; 148 149 skip("QueryBacktrace not implemented yet\n"); 150 return; 151 152 Buffer1 = RtlCreateQueryDebugBuffer(0, FALSE); 153 ok(Buffer1 != NULL, "Failed!\n"); 154 if (Buffer1) 155 { 156 Buffer2 = RtlCreateQueryDebugBuffer(0, FALSE); 157 ok(Buffer2 != NULL, "Failed!\n"); 158 if (Buffer2) 159 { 160 test_QueryBacktrace(Buffer1, Buffer2); 161 RtlDestroyQueryDebugBuffer(Buffer2); 162 } 163 164 RtlDestroyQueryDebugBuffer(Buffer1); 165 } 166 } 167