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