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)
10 /* INCLUDES *****************************************************************/
14 #include <ndk/kdfuncs.h>
19 /* PRIVATE FUNCTIONS ********************************************************/
23 DebugPrint(IN PSTRING DebugString
,
27 /* Call the Debug Service */
28 return DebugService(BREAKPOINT_PRINT
,
30 UlongToPtr(DebugString
->Length
),
31 UlongToPtr(ComponentId
),
37 DebugPrompt(IN PSTRING Output
,
40 /* Call the Debug Service */
41 return DebugService(BREAKPOINT_PROMPT
,
43 UlongToPtr(Output
->Length
),
45 UlongToPtr(Input
->MaximumLength
));
48 /* FUNCTIONS ****************************************************************/
52 vDbgPrintExWithPrefixInternal(IN PCCH Prefix
,
57 IN BOOLEAN HandleBreakpoint
)
62 SIZE_T Length
, PrefixLength
;
63 EXCEPTION_RECORD ExceptionRecord
;
65 /* Check if we should print it or not */
66 if ((ComponentId
!= MAXULONG
) &&
67 (NtQueryDebugFilterState(ComponentId
, Level
)) != (NTSTATUS
)TRUE
)
69 /* This message is masked */
70 return STATUS_SUCCESS
;
73 /* For user mode, don't recursively DbgPrint */
74 if (RtlpSetInDbgPrint()) return STATUS_SUCCESS
;
76 /* Guard against incorrect pointers */
79 /* Get the length and normalize it */
80 PrefixLength
= strlen(Prefix
);
81 if (PrefixLength
> sizeof(Buffer
)) PrefixLength
= sizeof(Buffer
);
84 strncpy(Buffer
, Prefix
, PrefixLength
);
87 Length
= _vsnprintf(Buffer
+ PrefixLength
,
88 sizeof(Buffer
) - PrefixLength
,
92 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
95 _SEH2_YIELD(return _SEH2_GetExceptionCode());
99 /* Check if we went past the buffer */
100 if (Length
== MAXULONG
)
102 /* Terminate it if we went over-board */
103 Buffer
[sizeof(Buffer
) - 1] = '\n';
106 Length
= sizeof(Buffer
);
111 Length
+= PrefixLength
;
114 /* Build the string */
115 DebugString
.Length
= (USHORT
)Length
;
116 DebugString
.Buffer
= Buffer
;
118 /* First, let the debugger know as well */
119 if (RtlpCheckForActiveDebugger())
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
;
129 /* Raise the exception */
130 RtlRaiseException(&ExceptionRecord
);
132 /* This code only runs in user-mode, so setting the flag is safe */
133 NtCurrentTeb()->InDbgPrint
= FALSE
;
134 return STATUS_SUCCESS
;
137 /* Call the Debug Print routine */
138 Status
= DebugPrint(&DebugString
, ComponentId
, Level
);
140 /* Check if this was with Control-C */
141 if (HandleBreakpoint
)
143 /* Check if we got a breakpoint */
144 if (Status
== STATUS_BREAKPOINT
)
147 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C
);
148 Status
= STATUS_SUCCESS
;
152 /* In user-mode, clear the InDbgPrint Flag */
153 RtlpClearInDbgPrint();
164 vDbgPrintExWithPrefix(IN PCCH Prefix
,
165 IN ULONG ComponentId
,
170 /* Call the internal routine that also handles ControlC */
171 return vDbgPrintExWithPrefixInternal(Prefix
,
184 vDbgPrintEx(IN ULONG ComponentId
,
189 /* Call the internal routine that also handles ControlC */
190 return vDbgPrintExWithPrefixInternal("",
203 DbgPrint(PCCH Format
,
209 /* Call the internal routine that also handles ControlC */
210 va_start(ap
, Format
);
211 Status
= vDbgPrintExWithPrefixInternal("",
226 DbgPrintEx(IN ULONG ComponentId
,
234 /* Call the internal routine that also handles ControlC */
235 va_start(ap
, Format
);
236 Status
= vDbgPrintExWithPrefixInternal("",
251 DbgPrintReturnControlC(PCCH Format
,
257 /* Call the internal routine that also handles ControlC */
258 va_start(ap
, Format
);
259 Status
= vDbgPrintExWithPrefixInternal("",
274 DbgPrompt(IN PCCH Prompt
,
276 IN ULONG MaximumResponseLength
)
281 /* Setup the input string */
282 Input
.MaximumLength
= (USHORT
)MaximumResponseLength
;
283 Input
.Buffer
= Response
;
285 /* Setup the output string */
286 Output
.Length
= (USHORT
)strlen(Prompt
);
287 Output
.Buffer
= (PCHAR
)Prompt
;
289 /* Call the system service */
290 return DebugPrompt(&Output
, &Input
);
298 DbgQueryDebugFilterState(IN ULONG ComponentId
,
301 /* Call the Nt routine */
302 return NtQueryDebugFilterState(ComponentId
, Level
);
310 DbgSetDebugFilterState(IN ULONG ComponentId
,
314 /* Call the Nt routine */
315 return NtSetDebugFilterState(ComponentId
, Level
, State
);
323 DbgLoadImageSymbols(IN PSTRING Name
,
325 IN ULONG_PTR ProcessId
)
327 PIMAGE_NT_HEADERS NtHeader
;
328 KD_SYMBOLS_INFO SymbolInfo
;
330 /* Setup the symbol data */
331 SymbolInfo
.BaseOfDll
= Base
;
332 SymbolInfo
.ProcessId
= ProcessId
;
335 NtHeader
= RtlImageNtHeader(Base
);
338 /* Get the rest of the data */
339 SymbolInfo
.CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
340 SymbolInfo
.SizeOfImage
= NtHeader
->OptionalHeader
.SizeOfImage
;
344 /* No data available */
345 SymbolInfo
.CheckSum
=
346 SymbolInfo
.SizeOfImage
= 0;
349 /* Load the symbols */
350 DebugService2(Name
, &SymbolInfo
, BREAKPOINT_LOAD_SYMBOLS
);
358 DbgUnLoadImageSymbols(IN PSTRING Name
,
360 IN ULONG_PTR ProcessId
)
362 KD_SYMBOLS_INFO SymbolInfo
;
364 /* Setup the symbol data */
365 SymbolInfo
.BaseOfDll
= Base
;
366 SymbolInfo
.ProcessId
= ProcessId
;
367 SymbolInfo
.CheckSum
= SymbolInfo
.SizeOfImage
= 0;
369 /* Load the symbols */
370 DebugService2(Name
, &SymbolInfo
, BREAKPOINT_UNLOAD_SYMBOLS
);
378 DbgCommandString(IN PCCH Name
,
381 STRING NameString
, CommandString
;
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
);
389 /* Send them to the debugger */
390 DebugService2(&NameString
, &CommandString
, BREAKPOINT_COMMAND_STRING
);
398 RtlPopFrame(IN PTEB_ACTIVE_FRAME Frame
)
400 /* Restore the previous frame as the active one */
401 NtCurrentTeb()->ActiveFrame
= Frame
->Previous
;
409 RtlPushFrame(IN PTEB_ACTIVE_FRAME Frame
)
411 /* Save the current frame and set the new one as active */
412 Frame
->Previous
= NtCurrentTeb()->ActiveFrame
;
413 NtCurrentTeb()->ActiveFrame
= Frame
;
420 /* Return the frame that's currently active */
421 return NtCurrentTeb()->ActiveFrame
;