Reactos
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
21ULONG
22NTAPI
23DebugPrint(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
35ULONG
36NTAPI
37DebugPrompt(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
50ULONG
51NTAPI
52vDbgPrintExWithPrefixInternal(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 */
165ULONG
166NTAPI
167vDbgPrintExWithPrefix(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 */
185ULONG
186NTAPI
187vDbgPrintEx(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 */
204ULONG
205__cdecl
206DbgPrint(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 */
227ULONG
228__cdecl
229DbgPrintEx(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 */
252ULONG
253__cdecl
254DbgPrintReturnControlC(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 */
275ULONG
276NTAPI
277DbgPrompt(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 */
299NTSTATUS
300NTAPI
301DbgQueryDebugFilterState(IN ULONG ComponentId,
302 IN ULONG Level)
303{
304 /* Call the Nt routine */
305 return NtQueryDebugFilterState(ComponentId, Level);
306}
307
308/*
309 * @implemented
310 */
311NTSTATUS
312NTAPI
313DbgSetDebugFilterState(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 */
324VOID
325NTAPI
326DbgLoadImageSymbols(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 */
359VOID
360NTAPI
361DbgUnLoadImageSymbols(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 */
379VOID
380NTAPI
381DbgCommandString(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*/
399VOID
400NTAPI
401RtlPopFrame(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*/
410VOID
411NTAPI
412RtlPushFrame(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
419PTEB_ACTIVE_FRAME
420NTAPI
421RtlGetFrame(VOID)
422{
423 /* Return the frame that's currently active */
424 return NtCurrentTeb()->ActiveFrame;
425}