Reactos
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
15NTSTATUS NTAPI RtlQueryProcessBackTraceInformation(IN OUT PRTL_DEBUG_INFORMATION Buffer);
16
17
18// Seems that this struct is wrong in our sdk?
19typedef 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
29static PVOID g_Call_Address;
30static PVOID g_PreviousReturnAddress;
31
32__declspec(noinline)
33PVOID GetFunctionAddress()
34{
35 return _ReturnAddress();
36}
37
38__declspec(noinline)
39USHORT 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)
49USHORT 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
60static 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
73static 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
142START_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}