xref: /reactos/sdk/lib/rtl/debug.c (revision 3cddd76f)
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
DebugPrint(IN PSTRING DebugString,IN ULONG ComponentId,IN ULONG Level)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
DebugPrompt(IN PSTRING Output,IN PSTRING Input)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
vDbgPrintExWithPrefixInternal(IN PCCH Prefix,IN ULONG ComponentId,IN ULONG Level,IN PCCH Format,IN va_list ap,IN BOOLEAN HandleBreakpoint)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) - 2] = '\n';
106         Buffer[sizeof(Buffer) - 1] = '\0';
107 
108         /* Put maximum */
109         Length = sizeof(Buffer) - 1;
110     }
111     else
112     {
113         /* Add the prefix */
114         Length += PrefixLength;
115     }
116 
117     /* Build the string */
118     DebugString.Length = (USHORT)Length;
119     DebugString.Buffer = Buffer;
120 
121     /* First, let the debugger know as well */
122     if (RtlpCheckForActiveDebugger())
123     {
124         /* Fill out an exception record */
125         ExceptionRecord.ExceptionCode = DBG_PRINTEXCEPTION_C;
126         ExceptionRecord.ExceptionRecord = NULL;
127         ExceptionRecord.NumberParameters = 2;
128         ExceptionRecord.ExceptionFlags = 0;
129         ExceptionRecord.ExceptionInformation[0] = DebugString.Length + 1;
130         ExceptionRecord.ExceptionInformation[1] = (ULONG_PTR)DebugString.Buffer;
131 
132         /* Raise the exception */
133         RtlRaiseException(&ExceptionRecord);
134 
135         /* In user-mode, clear the InDbgPrint Flag */
136         RtlpClearInDbgPrint();
137         return STATUS_SUCCESS;
138     }
139 
140     /* Call the Debug Print routine */
141     Status = DebugPrint(&DebugString, ComponentId, Level);
142 
143     /* Check if this was with Control-C */
144     if (HandleBreakpoint)
145     {
146         /* Check if we got a breakpoint */
147         if (Status == STATUS_BREAKPOINT)
148         {
149             /* Breakpoint */
150             DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
151             Status = STATUS_SUCCESS;
152         }
153     }
154 
155     /* In user-mode, clear the InDbgPrint Flag */
156     RtlpClearInDbgPrint();
157 
158     /* Return */
159     return Status;
160 }
161 
162 /*
163  * @implemented
164  */
165 ULONG
166 NTAPI
vDbgPrintExWithPrefix(IN PCCH Prefix,IN ULONG ComponentId,IN ULONG Level,IN PCCH Format,IN va_list ap)167 vDbgPrintExWithPrefix(IN PCCH Prefix,
168                       IN ULONG ComponentId,
169                       IN ULONG Level,
170                       IN PCCH Format,
171                       IN va_list ap)
172 {
173     /* Call the internal routine that also handles ControlC */
174     return vDbgPrintExWithPrefixInternal(Prefix,
175                                          ComponentId,
176                                          Level,
177                                          Format,
178                                          ap,
179                                          TRUE);
180 }
181 
182 /*
183  * @implemented
184  */
185 ULONG
186 NTAPI
vDbgPrintEx(IN ULONG ComponentId,IN ULONG Level,IN PCCH Format,IN va_list ap)187 vDbgPrintEx(IN ULONG ComponentId,
188             IN ULONG Level,
189             IN PCCH Format,
190             IN va_list ap)
191 {
192     /* Call the internal routine that also handles ControlC */
193     return vDbgPrintExWithPrefixInternal("",
194                                          ComponentId,
195                                          Level,
196                                          Format,
197                                          ap,
198                                          TRUE);
199 }
200 
201 /*
202  * @implemented
203  */
204 ULONG
205 __cdecl
DbgPrint(PCCH Format,...)206 DbgPrint(PCCH Format,
207          ...)
208 {
209     ULONG Status;
210     va_list ap;
211 
212     /* Call the internal routine that also handles ControlC */
213     va_start(ap, Format);
214     Status = vDbgPrintExWithPrefixInternal("",
215                                            -1,
216                                            DPFLTR_ERROR_LEVEL,
217                                            Format,
218                                            ap,
219                                            TRUE);
220     va_end(ap);
221     return Status;
222 }
223 
224 /*
225  * @implemented
226  */
227 ULONG
228 __cdecl
DbgPrintEx(IN ULONG ComponentId,IN ULONG Level,IN PCCH Format,...)229 DbgPrintEx(IN ULONG ComponentId,
230            IN ULONG Level,
231            IN PCCH Format,
232            ...)
233 {
234     ULONG Status;
235     va_list ap;
236 
237     /* Call the internal routine that also handles ControlC */
238     va_start(ap, Format);
239     Status = vDbgPrintExWithPrefixInternal("",
240                                            ComponentId,
241                                            Level,
242                                            Format,
243                                            ap,
244                                            TRUE);
245     va_end(ap);
246     return Status;
247 }
248 
249 /*
250  * @implemented
251  */
252 ULONG
253 __cdecl
DbgPrintReturnControlC(PCCH Format,...)254 DbgPrintReturnControlC(PCCH Format,
255                        ...)
256 {
257     ULONG Status;
258     va_list ap;
259 
260     /* Call the internal routine that also handles ControlC */
261     va_start(ap, Format);
262     Status = vDbgPrintExWithPrefixInternal("",
263                                            -1,
264                                            DPFLTR_ERROR_LEVEL,
265                                            Format,
266                                            ap,
267                                            FALSE);
268     va_end(ap);
269     return Status;
270 }
271 
272 /*
273  * @implemented
274  */
275 ULONG
276 NTAPI
DbgPrompt(IN PCCH Prompt,OUT PCH Response,IN ULONG MaximumResponseLength)277 DbgPrompt(IN PCCH Prompt,
278           OUT PCH Response,
279           IN ULONG MaximumResponseLength)
280 {
281     STRING Output;
282     STRING Input;
283 
284     /* Setup the input string */
285     Input.MaximumLength = (USHORT)MaximumResponseLength;
286     Input.Buffer = Response;
287 
288     /* Setup the output string */
289     Output.Length = (USHORT)strlen(Prompt);
290     Output.Buffer = (PCHAR)Prompt;
291 
292     /* Call the system service */
293     return DebugPrompt(&Output, &Input);
294 }
295 
296 /*
297  * @implemented
298  */
299 NTSTATUS
300 NTAPI
DbgQueryDebugFilterState(IN ULONG ComponentId,IN ULONG Level)301 DbgQueryDebugFilterState(IN ULONG ComponentId,
302                          IN ULONG Level)
303 {
304     /* Call the Nt routine */
305     return NtQueryDebugFilterState(ComponentId, Level);
306 }
307 
308 /*
309  * @implemented
310  */
311 NTSTATUS
312 NTAPI
DbgSetDebugFilterState(IN ULONG ComponentId,IN ULONG Level,IN BOOLEAN State)313 DbgSetDebugFilterState(IN ULONG ComponentId,
314                        IN ULONG Level,
315                        IN BOOLEAN State)
316 {
317     /* Call the Nt routine */
318     return NtSetDebugFilterState(ComponentId, Level, State);
319 }
320 
321 /*
322  * @implemented
323  */
324 VOID
325 NTAPI
DbgLoadImageSymbols(IN PSTRING Name,IN PVOID Base,IN ULONG_PTR ProcessId)326 DbgLoadImageSymbols(IN PSTRING Name,
327                     IN PVOID Base,
328                     IN ULONG_PTR ProcessId)
329 {
330     PIMAGE_NT_HEADERS NtHeader;
331     KD_SYMBOLS_INFO SymbolInfo;
332 
333     /* Setup the symbol data */
334     SymbolInfo.BaseOfDll = Base;
335     SymbolInfo.ProcessId = ProcessId;
336 
337     /* Get NT Headers */
338     NtHeader = RtlImageNtHeader(Base);
339     if (NtHeader)
340     {
341         /* Get the rest of the data */
342         SymbolInfo.CheckSum = NtHeader->OptionalHeader.CheckSum;
343         SymbolInfo.SizeOfImage = NtHeader->OptionalHeader.SizeOfImage;
344     }
345     else
346     {
347         /* No data available */
348         SymbolInfo.CheckSum =
349         SymbolInfo.SizeOfImage = 0;
350     }
351 
352     /* Load the symbols */
353     DebugService2(Name, &SymbolInfo, BREAKPOINT_LOAD_SYMBOLS);
354 }
355 
356 /*
357  * @implemented
358  */
359 VOID
360 NTAPI
DbgUnLoadImageSymbols(IN PSTRING Name,IN PVOID Base,IN ULONG_PTR ProcessId)361 DbgUnLoadImageSymbols(IN PSTRING Name,
362                       IN PVOID Base,
363                       IN ULONG_PTR ProcessId)
364 {
365     KD_SYMBOLS_INFO SymbolInfo;
366 
367     /* Setup the symbol data */
368     SymbolInfo.BaseOfDll = Base;
369     SymbolInfo.ProcessId = ProcessId;
370     SymbolInfo.CheckSum = SymbolInfo.SizeOfImage = 0;
371 
372     /* Load the symbols */
373     DebugService2(Name, &SymbolInfo, BREAKPOINT_UNLOAD_SYMBOLS);
374 }
375 
376 /*
377  * @implemented
378  */
379 VOID
380 NTAPI
DbgCommandString(IN PCCH Name,IN PCCH Command)381 DbgCommandString(IN PCCH Name,
382                  IN PCCH Command)
383 {
384     STRING NameString, CommandString;
385 
386     /* Setup the strings */
387     NameString.Buffer = (PCHAR)Name;
388     NameString.Length = (USHORT)strlen(Name);
389     CommandString.Buffer = (PCHAR)Command;
390     CommandString.Length = (USHORT)strlen(Command);
391 
392     /* Send them to the debugger */
393     DebugService2(&NameString, &CommandString, BREAKPOINT_COMMAND_STRING);
394 }
395 
396 /*
397 * @implemented
398 */
399 VOID
400 NTAPI
RtlPopFrame(IN PTEB_ACTIVE_FRAME Frame)401 RtlPopFrame(IN PTEB_ACTIVE_FRAME Frame)
402 {
403     /* Restore the previous frame as the active one */
404     NtCurrentTeb()->ActiveFrame = Frame->Previous;
405 }
406 
407 /*
408 * @implemented
409 */
410 VOID
411 NTAPI
RtlPushFrame(IN PTEB_ACTIVE_FRAME Frame)412 RtlPushFrame(IN PTEB_ACTIVE_FRAME Frame)
413 {
414     /* Save the current frame and set the new one as active */
415     Frame->Previous = NtCurrentTeb()->ActiveFrame;
416     NtCurrentTeb()->ActiveFrame = Frame;
417 }
418 
419 PTEB_ACTIVE_FRAME
420 NTAPI
RtlGetFrame(VOID)421 RtlGetFrame(VOID)
422 {
423     /* Return the frame that's currently active */
424     return NtCurrentTeb()->ActiveFrame;
425 }
426