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