c491a46906b9b09c5c50dd3e9a6b7950f81047fc
[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 NTSTATUS
20 NTAPI
21 DebugPrint(IN PANSI_STRING DebugString,
22 IN ULONG ComponentId,
23 IN ULONG Level)
24 {
25 /* Call the INT2D Service */
26 return DebugService(BREAKPOINT_PRINT,
27 DebugString->Buffer,
28 DebugString->Length,
29 UlongToPtr(ComponentId),
30 UlongToPtr(Level));
31 }
32
33 NTSTATUS
34 NTAPI
35 DebugPrompt(IN PCSTRING Output,
36 IN PSTRING Input)
37 {
38 /* Call the INT2D Service */
39 return DebugService(BREAKPOINT_PROMPT,
40 Output->Buffer,
41 Output->Length,
42 Input->Buffer,
43 UlongToPtr(Input->MaximumLength));
44 }
45
46 /* FUNCTIONS ****************************************************************/
47
48 ULONG
49 NTAPI
50 vDbgPrintExWithPrefixInternal(IN LPCSTR Prefix,
51 IN ULONG ComponentId,
52 IN ULONG Level,
53 IN LPCSTR Format,
54 IN va_list ap,
55 IN BOOLEAN HandleBreakpoint)
56 {
57 NTSTATUS Status = STATUS_SUCCESS;
58 ANSI_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 != -1U) &&
65 !(NtQueryDebugFilterState(ComponentId, Level)))
66 {
67 /* This message is masked */
68 return Status;
69 }
70
71 /* For user mode, don't recursively DbgPrint */
72 if (RtlpSetInDbgPrint(TRUE)) return Status;
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 Length = PrefixLength = 0;
94 Status = _SEH2_GetExceptionCode();
95 }
96 _SEH2_END;
97 if (!NT_SUCCESS(Status)) return Status;
98
99 /* Check if we went past the buffer */
100 if (Length == -1U)
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 = Length;
116 DebugString.Buffer = Buffer;
117
118 /* First, let the debugger know as well */
119 if (RtlpCheckForActiveDebugger(FALSE))
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, remove the InDbgPrint Flag */
153 RtlpSetInDbgPrint(FALSE);
154
155 /* Return */
156 return Status;
157 }
158
159 /*
160 * @implemented
161 */
162 ULONG
163 NTAPI
164 vDbgPrintExWithPrefix(IN LPCSTR Prefix,
165 IN ULONG ComponentId,
166 IN ULONG Level,
167 IN LPCSTR 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 LPCSTR 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 n;
207 va_list ap;
208
209 /* Call the internal routine that also handles ControlC */
210 va_start(ap, Format);
211 n = vDbgPrintExWithPrefixInternal("",
212 -1,
213 DPFLTR_ERROR_LEVEL,
214 Format,
215 ap,
216 TRUE);
217 va_end(ap);
218 return n;
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 n;
232 va_list ap;
233
234 /* Call the internal routine that also handles ControlC */
235 va_start(ap, Format);
236 n = vDbgPrintExWithPrefixInternal("",
237 ComponentId,
238 Level,
239 Format,
240 ap,
241 TRUE);
242 va_end(ap);
243 return n;
244 }
245
246 /*
247 * @implemented
248 */
249 ULONG
250 __cdecl
251 DbgPrintReturnControlC(PCH Format,
252 ...)
253 {
254 ULONG n;
255 va_list ap;
256
257 /* Call the internal routine that also handles ControlC */
258 va_start(ap, Format);
259 n = vDbgPrintExWithPrefixInternal("",
260 -1,
261 DPFLTR_ERROR_LEVEL,
262 Format,
263 ap,
264 FALSE);
265 va_end(ap);
266 return n;
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 CSTRING 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 = strlen(Prompt);
287 Output.Buffer = 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 NTSTATUS
322 NTAPI
323 DbgLoadImageSymbols(IN PANSI_STRING 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 = (ULONG)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 = SymbolInfo.SizeOfImage = 0;
346 }
347
348 /* Load the symbols */
349 DebugService2(Name, &SymbolInfo, BREAKPOINT_LOAD_SYMBOLS);
350 return STATUS_SUCCESS;
351 }
352
353 /*
354 * @implemented
355 */
356 VOID
357 NTAPI
358 DbgUnLoadImageSymbols(IN PANSI_STRING 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 = (ULONG)ProcessId;
367 SymbolInfo.CheckSum = SymbolInfo.SizeOfImage = 0;
368
369 /* Load the symbols */
370 DebugService2(Name, &SymbolInfo, BREAKPOINT_UNLOAD_SYMBOLS);
371 }