[SDK] Reset InDbgPrint state when an exception occurs
[reactos.git] / sdk / lib / rtl / debug.c
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 }