[RTL/HEAP]
[reactos.git] / reactos / 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 #define NDEBUG
15 #include <debug.h>
16
17 /* PRIVATE FUNCTIONS ********************************************************/
18
19 ULONG
20 NTAPI
21 DebugPrint(IN PSTRING DebugString,
22 IN ULONG ComponentId,
23 IN ULONG Level)
24 {
25 /* Call the Debug Service */
26 return DebugService(BREAKPOINT_PRINT,
27 DebugString->Buffer,
28 UlongToPtr(DebugString->Length),
29 UlongToPtr(ComponentId),
30 UlongToPtr(Level));
31 }
32
33 ULONG
34 NTAPI
35 DebugPrompt(IN PSTRING Output,
36 IN PSTRING Input)
37 {
38 /* Call the Debug Service */
39 return DebugService(BREAKPOINT_PROMPT,
40 Output->Buffer,
41 UlongToPtr(Output->Length),
42 Input->Buffer,
43 UlongToPtr(Input->MaximumLength));
44 }
45
46 /* FUNCTIONS ****************************************************************/
47
48 ULONG
49 NTAPI
50 vDbgPrintExWithPrefixInternal(IN PCCH Prefix,
51 IN ULONG ComponentId,
52 IN ULONG Level,
53 IN PCCH Format,
54 IN va_list ap,
55 IN BOOLEAN HandleBreakpoint)
56 {
57 NTSTATUS Status;
58 STRING DebugString;
59 CHAR Buffer[512];
60 ULONG Length, PrefixLength;
61 EXCEPTION_RECORD ExceptionRecord;
62
63 /* Check if we should print it or not */
64 if ((ComponentId != MAXULONG) &&
65 (NtQueryDebugFilterState(ComponentId, Level)) != TRUE)
66 {
67 /* This message is masked */
68 return STATUS_SUCCESS;
69 }
70
71 /* For user mode, don't recursively DbgPrint */
72 if (RtlpSetInDbgPrint()) return STATUS_SUCCESS;
73
74 /* Guard against incorrect pointers */
75 _SEH2_TRY
76 {
77 /* Get the length and normalize it */
78 PrefixLength = strlen(Prefix);
79 if (PrefixLength > sizeof(Buffer)) PrefixLength = sizeof(Buffer);
80
81 /* Copy it */
82 strncpy(Buffer, Prefix, PrefixLength);
83
84 /* Do the printf */
85 Length = _vsnprintf(Buffer + PrefixLength,
86 sizeof(Buffer) - PrefixLength,
87 Format,
88 ap);
89 }
90 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
91 {
92 /* Fail */
93 _SEH2_YIELD(return _SEH2_GetExceptionCode());
94 }
95 _SEH2_END;
96
97 /* Check if we went past the buffer */
98 if (Length == MAXULONG)
99 {
100 /* Terminate it if we went over-board */
101 Buffer[sizeof(Buffer) - 1] = '\n';
102
103 /* Put maximum */
104 Length = sizeof(Buffer);
105 }
106 else
107 {
108 /* Add the prefix */
109 Length += PrefixLength;
110 }
111
112 /* Build the string */
113 DebugString.Length = Length;
114 DebugString.Buffer = Buffer;
115
116 /* First, let the debugger know as well */
117 if (RtlpCheckForActiveDebugger())
118 {
119 /* Fill out an exception record */
120 ExceptionRecord.ExceptionCode = DBG_PRINTEXCEPTION_C;
121 ExceptionRecord.ExceptionRecord = NULL;
122 ExceptionRecord.NumberParameters = 2;
123 ExceptionRecord.ExceptionFlags = 0;
124 ExceptionRecord.ExceptionInformation[0] = DebugString.Length + 1;
125 ExceptionRecord.ExceptionInformation[1] = (ULONG_PTR)DebugString.Buffer;
126
127 /* Raise the exception */
128 RtlRaiseException(&ExceptionRecord);
129
130 /* This code only runs in user-mode, so setting the flag is safe */
131 NtCurrentTeb()->InDbgPrint = FALSE;
132 return STATUS_SUCCESS;
133 }
134
135 /* Call the Debug Print routine */
136 Status = DebugPrint(&DebugString, ComponentId, Level);
137
138 /* Check if this was with Control-C */
139 if (HandleBreakpoint)
140 {
141 /* Check if we got a breakpoint */
142 if (Status == STATUS_BREAKPOINT)
143 {
144 /* Breakpoint */
145 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
146 Status = STATUS_SUCCESS;
147 }
148 }
149
150 /* In user-mode, clear the InDbgPrint Flag */
151 RtlpClearInDbgPrint();
152
153 /* Return */
154 return Status;
155 }
156
157 /*
158 * @implemented
159 */
160 ULONG
161 NTAPI
162 vDbgPrintExWithPrefix(IN PCCH Prefix,
163 IN ULONG ComponentId,
164 IN ULONG Level,
165 IN PCCH Format,
166 IN va_list ap)
167 {
168 /* Call the internal routine that also handles ControlC */
169 return vDbgPrintExWithPrefixInternal(Prefix,
170 ComponentId,
171 Level,
172 Format,
173 ap,
174 TRUE);
175 }
176
177 /*
178 * @implemented
179 */
180 ULONG
181 NTAPI
182 vDbgPrintEx(IN ULONG ComponentId,
183 IN ULONG Level,
184 IN PCCH Format,
185 IN va_list ap)
186 {
187 /* Call the internal routine that also handles ControlC */
188 return vDbgPrintExWithPrefixInternal("",
189 ComponentId,
190 Level,
191 Format,
192 ap,
193 TRUE);
194 }
195
196 /*
197 * @implemented
198 */
199 ULONG
200 __cdecl
201 DbgPrint(PCCH Format,
202 ...)
203 {
204 ULONG Status;
205 va_list ap;
206
207 /* Call the internal routine that also handles ControlC */
208 va_start(ap, Format);
209 Status = vDbgPrintExWithPrefixInternal("",
210 -1,
211 DPFLTR_ERROR_LEVEL,
212 Format,
213 ap,
214 TRUE);
215 va_end(ap);
216 return Status;
217 }
218
219 /*
220 * @implemented
221 */
222 ULONG
223 __cdecl
224 DbgPrintEx(IN ULONG ComponentId,
225 IN ULONG Level,
226 IN PCCH Format,
227 ...)
228 {
229 ULONG Status;
230 va_list ap;
231
232 /* Call the internal routine that also handles ControlC */
233 va_start(ap, Format);
234 Status = vDbgPrintExWithPrefixInternal("",
235 ComponentId,
236 Level,
237 Format,
238 ap,
239 TRUE);
240 va_end(ap);
241 return Status;
242 }
243
244 /*
245 * @implemented
246 */
247 ULONG
248 __cdecl
249 DbgPrintReturnControlC(PCCH Format,
250 ...)
251 {
252 ULONG Status;
253 va_list ap;
254
255 /* Call the internal routine that also handles ControlC */
256 va_start(ap, Format);
257 Status = vDbgPrintExWithPrefixInternal("",
258 -1,
259 DPFLTR_ERROR_LEVEL,
260 Format,
261 ap,
262 FALSE);
263 va_end(ap);
264 return Status;
265 }
266
267 /*
268 * @implemented
269 */
270 ULONG
271 NTAPI
272 DbgPrompt(IN PCCH Prompt,
273 OUT PCH Response,
274 IN ULONG MaximumResponseLength)
275 {
276 STRING Output;
277 STRING Input;
278
279 /* Setup the input string */
280 Input.MaximumLength = (USHORT)MaximumResponseLength;
281 Input.Buffer = Response;
282
283 /* Setup the output string */
284 Output.Length = strlen(Prompt);
285 Output.Buffer = (PCHAR)Prompt;
286
287 /* Call the system service */
288 return DebugPrompt(&Output, &Input);
289 }
290
291 /*
292 * @implemented
293 */
294 NTSTATUS
295 NTAPI
296 DbgQueryDebugFilterState(IN ULONG ComponentId,
297 IN ULONG Level)
298 {
299 /* Call the Nt routine */
300 return NtQueryDebugFilterState(ComponentId, Level);
301 }
302
303 /*
304 * @implemented
305 */
306 NTSTATUS
307 NTAPI
308 DbgSetDebugFilterState(IN ULONG ComponentId,
309 IN ULONG Level,
310 IN BOOLEAN State)
311 {
312 /* Call the Nt routine */
313 return NtSetDebugFilterState(ComponentId, Level, State);
314 }
315
316 /*
317 * @implemented
318 */
319 VOID
320 NTAPI
321 DbgLoadImageSymbols(IN PSTRING Name,
322 IN PVOID Base,
323 IN ULONG_PTR ProcessId)
324 {
325 PIMAGE_NT_HEADERS NtHeader;
326 KD_SYMBOLS_INFO SymbolInfo;
327
328 /* Setup the symbol data */
329 SymbolInfo.BaseOfDll = Base;
330 SymbolInfo.ProcessId = ProcessId;
331
332 /* Get NT Headers */
333 NtHeader = RtlImageNtHeader(Base);
334 if (NtHeader)
335 {
336 /* Get the rest of the data */
337 SymbolInfo.CheckSum = NtHeader->OptionalHeader.CheckSum;
338 SymbolInfo.SizeOfImage = NtHeader->OptionalHeader.SizeOfImage;
339 }
340 else
341 {
342 /* No data available */
343 SymbolInfo.CheckSum =
344 SymbolInfo.SizeOfImage = 0;
345 }
346
347 /* Load the symbols */
348 DebugService2(Name, &SymbolInfo, BREAKPOINT_LOAD_SYMBOLS);
349 }
350
351 /*
352 * @implemented
353 */
354 VOID
355 NTAPI
356 DbgUnLoadImageSymbols(IN PSTRING Name,
357 IN PVOID Base,
358 IN ULONG_PTR ProcessId)
359 {
360 KD_SYMBOLS_INFO SymbolInfo;
361
362 /* Setup the symbol data */
363 SymbolInfo.BaseOfDll = Base;
364 SymbolInfo.ProcessId = ProcessId;
365 SymbolInfo.CheckSum = SymbolInfo.SizeOfImage = 0;
366
367 /* Load the symbols */
368 DebugService2(Name, &SymbolInfo, BREAKPOINT_UNLOAD_SYMBOLS);
369 }
370
371 /*
372 * @implemented
373 */
374 VOID
375 NTAPI
376 DbgCommandString(IN PCCH Name,
377 IN PCCH Command)
378 {
379 STRING NameString, CommandString;
380
381 /* Setup the strings */
382 NameString.Buffer = (PCHAR)Name;
383 NameString.Length = strlen(Name);
384 CommandString.Buffer = (PCHAR)Command;
385 CommandString.Length = strlen(Command);
386
387 /* Send them to the debugger */
388 DebugService2(&NameString, &CommandString, BREAKPOINT_COMMAND_STRING);
389 }