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