xref: /reactos/sdk/lib/rtl/debug.c (revision 02e84521)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Run-Time Library
4  * FILE:            lib/rtl/debug.c
5  * PURPOSE:         Debug Print and Prompt routines
6  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
7  *                  Royce Mitchel III
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include <rtl.h>
13 
14 #include <ndk/kdfuncs.h>
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 /* PRIVATE FUNCTIONS ********************************************************/
20 
21 ULONG
22 NTAPI
23 DebugPrint(IN PSTRING DebugString,
24            IN ULONG ComponentId,
25            IN ULONG Level)
26 {
27     /* Call the Debug Service */
28     return DebugService(BREAKPOINT_PRINT,
29                         DebugString->Buffer,
30                         UlongToPtr(DebugString->Length),
31                         UlongToPtr(ComponentId),
32                         UlongToPtr(Level));
33 }
34 
35 ULONG
36 NTAPI
37 DebugPrompt(IN PSTRING Output,
38             IN PSTRING Input)
39 {
40     /* Call the Debug Service */
41     return DebugService(BREAKPOINT_PROMPT,
42                         Output->Buffer,
43                         UlongToPtr(Output->Length),
44                         Input->Buffer,
45                         UlongToPtr(Input->MaximumLength));
46 }
47 
48 /* FUNCTIONS ****************************************************************/
49 
50 ULONG
51 NTAPI
52 vDbgPrintExWithPrefixInternal(IN PCCH Prefix,
53                               IN ULONG ComponentId,
54                               IN ULONG Level,
55                               IN PCCH Format,
56                               IN va_list ap,
57                               IN BOOLEAN HandleBreakpoint)
58 {
59     NTSTATUS Status;
60     STRING DebugString;
61     CHAR Buffer[512];
62     SIZE_T Length, PrefixLength;
63     EXCEPTION_RECORD ExceptionRecord;
64 
65     /* Check if we should print it or not */
66     if ((ComponentId != MAXULONG) &&
67         (NtQueryDebugFilterState(ComponentId, Level)) != (NTSTATUS)TRUE)
68     {
69         /* This message is masked */
70         return STATUS_SUCCESS;
71     }
72 
73     /* For user mode, don't recursively DbgPrint */
74     if (RtlpSetInDbgPrint()) return STATUS_SUCCESS;
75 
76     /* Guard against incorrect pointers */
77     _SEH2_TRY
78     {
79         /* Get the length and normalize it */
80         PrefixLength = strlen(Prefix);
81         if (PrefixLength > sizeof(Buffer)) PrefixLength = sizeof(Buffer);
82 
83         /* Copy it */
84         strncpy(Buffer, Prefix, PrefixLength);
85 
86         /* Do the printf */
87         Length = _vsnprintf(Buffer + PrefixLength,
88                             sizeof(Buffer) - PrefixLength,
89                             Format,
90                             ap);
91     }
92     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
93     {
94         /* In user-mode, clear the InDbgPrint Flag */
95         RtlpClearInDbgPrint();
96         /* Fail */
97         _SEH2_YIELD(return _SEH2_GetExceptionCode());
98     }
99     _SEH2_END;
100 
101     /* Check if we went past the buffer */
102     if (Length == MAXULONG)
103     {
104         /* Terminate it if we went over-board */
105         Buffer[sizeof(Buffer) - 1] = '\n';
106 
107         /* Put maximum */
108         Length = sizeof(Buffer);
109     }
110     else
111     {
112         /* Add the prefix */
113         Length += PrefixLength;
114     }
115 
116     /* Build the string */
117     DebugString.Length = (USHORT)Length;
118     DebugString.Buffer = Buffer;
119 
120     /* First, let the debugger know as well */
121     if (RtlpCheckForActiveDebugger())
122     {
123         /* Fill out an exception record */
124         ExceptionRecord.ExceptionCode = DBG_PRINTEXCEPTION_C;
125         ExceptionRecord.ExceptionRecord = NULL;
126         ExceptionRecord.NumberParameters = 2;
127         ExceptionRecord.ExceptionFlags = 0;
128         ExceptionRecord.ExceptionInformation[0] = DebugString.Length + 1;
129         ExceptionRecord.ExceptionInformation[1] = (ULONG_PTR)DebugString.Buffer;
130 
131         /* Raise the exception */
132         RtlRaiseException(&ExceptionRecord);
133 
134         /* In user-mode, clear the InDbgPrint Flag */
135         RtlpClearInDbgPrint();
136         return STATUS_SUCCESS;
137     }
138 
139     /* Call the Debug Print routine */
140     Status = DebugPrint(&DebugString, ComponentId, Level);
141 
142     /* Check if this was with Control-C */
143     if (HandleBreakpoint)
144     {
145         /* Check if we got a breakpoint */
146         if (Status == STATUS_BREAKPOINT)
147         {
148             /* Breakpoint */
149             DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
150             Status = STATUS_SUCCESS;
151         }
152     }
153 
154     /* In user-mode, clear the InDbgPrint Flag */
155     RtlpClearInDbgPrint();
156 
157     /* Return */
158     return Status;
159 }
160 
161 /*
162  * @implemented
163  */
164 ULONG
165 NTAPI
166 vDbgPrintExWithPrefix(IN PCCH Prefix,
167                       IN ULONG ComponentId,
168                       IN ULONG Level,
169                       IN PCCH Format,
170                       IN va_list ap)
171 {
172     /* Call the internal routine that also handles ControlC */
173     return vDbgPrintExWithPrefixInternal(Prefix,
174                                          ComponentId,
175                                          Level,
176                                          Format,
177                                          ap,
178                                          TRUE);
179 }
180 
181 /*
182  * @implemented
183  */
184 ULONG
185 NTAPI
186 vDbgPrintEx(IN ULONG ComponentId,
187             IN ULONG Level,
188             IN PCCH Format,
189             IN va_list ap)
190 {
191     /* Call the internal routine that also handles ControlC */
192     return vDbgPrintExWithPrefixInternal("",
193                                          ComponentId,
194                                          Level,
195                                          Format,
196                                          ap,
197                                          TRUE);
198 }
199 
200 /*
201  * @implemented
202  */
203 ULONG
204 __cdecl
205 DbgPrint(PCCH Format,
206          ...)
207 {
208     ULONG Status;
209     va_list ap;
210 
211     /* Call the internal routine that also handles ControlC */
212     va_start(ap, Format);
213     Status = vDbgPrintExWithPrefixInternal("",
214                                            -1,
215                                            DPFLTR_ERROR_LEVEL,
216                                            Format,
217                                            ap,
218                                            TRUE);
219     va_end(ap);
220     return Status;
221 }
222 
223 /*
224  * @implemented
225  */
226 ULONG
227 __cdecl
228 DbgPrintEx(IN ULONG ComponentId,
229            IN ULONG Level,
230            IN PCCH Format,
231            ...)
232 {
233     ULONG Status;
234     va_list ap;
235 
236     /* Call the internal routine that also handles ControlC */
237     va_start(ap, Format);
238     Status = vDbgPrintExWithPrefixInternal("",
239                                            ComponentId,
240                                            Level,
241                                            Format,
242                                            ap,
243                                            TRUE);
244     va_end(ap);
245     return Status;
246 }
247 
248 /*
249  * @implemented
250  */
251 ULONG
252 __cdecl
253 DbgPrintReturnControlC(PCCH Format,
254                        ...)
255 {
256     ULONG Status;
257     va_list ap;
258 
259     /* Call the internal routine that also handles ControlC */
260     va_start(ap, Format);
261     Status = vDbgPrintExWithPrefixInternal("",
262                                            -1,
263                                            DPFLTR_ERROR_LEVEL,
264                                            Format,
265                                            ap,
266                                            FALSE);
267     va_end(ap);
268     return Status;
269 }
270 
271 /*
272  * @implemented
273  */
274 ULONG
275 NTAPI
276 DbgPrompt(IN PCCH Prompt,
277           OUT PCH Response,
278           IN ULONG MaximumResponseLength)
279 {
280     STRING Output;
281     STRING Input;
282 
283     /* Setup the input string */
284     Input.MaximumLength = (USHORT)MaximumResponseLength;
285     Input.Buffer = Response;
286 
287     /* Setup the output string */
288     Output.Length = (USHORT)strlen(Prompt);
289     Output.Buffer = (PCHAR)Prompt;
290 
291     /* Call the system service */
292     return DebugPrompt(&Output, &Input);
293 }
294 
295 /*
296  * @implemented
297  */
298 NTSTATUS
299 NTAPI
300 DbgQueryDebugFilterState(IN ULONG ComponentId,
301                          IN ULONG Level)
302 {
303     /* Call the Nt routine */
304     return NtQueryDebugFilterState(ComponentId, Level);
305 }
306 
307 /*
308  * @implemented
309  */
310 NTSTATUS
311 NTAPI
312 DbgSetDebugFilterState(IN ULONG ComponentId,
313                        IN ULONG Level,
314                        IN BOOLEAN State)
315 {
316     /* Call the Nt routine */
317     return NtSetDebugFilterState(ComponentId, Level, State);
318 }
319 
320 /*
321  * @implemented
322  */
323 VOID
324 NTAPI
325 DbgLoadImageSymbols(IN PSTRING Name,
326                     IN PVOID Base,
327                     IN ULONG_PTR ProcessId)
328 {
329     PIMAGE_NT_HEADERS NtHeader;
330     KD_SYMBOLS_INFO SymbolInfo;
331 
332     /* Setup the symbol data */
333     SymbolInfo.BaseOfDll = Base;
334     SymbolInfo.ProcessId = ProcessId;
335 
336     /* Get NT Headers */
337     NtHeader = RtlImageNtHeader(Base);
338     if (NtHeader)
339     {
340         /* Get the rest of the data */
341         SymbolInfo.CheckSum = NtHeader->OptionalHeader.CheckSum;
342         SymbolInfo.SizeOfImage = NtHeader->OptionalHeader.SizeOfImage;
343     }
344     else
345     {
346         /* No data available */
347         SymbolInfo.CheckSum =
348         SymbolInfo.SizeOfImage = 0;
349     }
350 
351     /* Load the symbols */
352     DebugService2(Name, &SymbolInfo, BREAKPOINT_LOAD_SYMBOLS);
353 }
354 
355 /*
356  * @implemented
357  */
358 VOID
359 NTAPI
360 DbgUnLoadImageSymbols(IN PSTRING Name,
361                       IN PVOID Base,
362                       IN ULONG_PTR ProcessId)
363 {
364     KD_SYMBOLS_INFO SymbolInfo;
365 
366     /* Setup the symbol data */
367     SymbolInfo.BaseOfDll = Base;
368     SymbolInfo.ProcessId = ProcessId;
369     SymbolInfo.CheckSum = SymbolInfo.SizeOfImage = 0;
370 
371     /* Load the symbols */
372     DebugService2(Name, &SymbolInfo, BREAKPOINT_UNLOAD_SYMBOLS);
373 }
374 
375 /*
376  * @implemented
377  */
378 VOID
379 NTAPI
380 DbgCommandString(IN PCCH Name,
381                  IN PCCH Command)
382 {
383     STRING NameString, CommandString;
384 
385     /* Setup the strings */
386     NameString.Buffer = (PCHAR)Name;
387     NameString.Length = (USHORT)strlen(Name);
388     CommandString.Buffer = (PCHAR)Command;
389     CommandString.Length = (USHORT)strlen(Command);
390 
391     /* Send them to the debugger */
392     DebugService2(&NameString, &CommandString, BREAKPOINT_COMMAND_STRING);
393 }
394 
395 /*
396 * @implemented
397 */
398 VOID
399 NTAPI
400 RtlPopFrame(IN PTEB_ACTIVE_FRAME Frame)
401 {
402     /* Restore the previous frame as the active one */
403     NtCurrentTeb()->ActiveFrame = Frame->Previous;
404 }
405 
406 /*
407 * @implemented
408 */
409 VOID
410 NTAPI
411 RtlPushFrame(IN PTEB_ACTIVE_FRAME Frame)
412 {
413     /* Save the current frame and set the new one as active */
414     Frame->Previous = NtCurrentTeb()->ActiveFrame;
415     NtCurrentTeb()->ActiveFrame = Frame;
416 }
417 
418 PTEB_ACTIVE_FRAME
419 NTAPI
420 RtlGetFrame(VOID)
421 {
422     /* Return the frame that's currently active */
423     return NtCurrentTeb()->ActiveFrame;
424 }
425