2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/kd64/kdprint.c
5 * PURPOSE: KD64 Trap Handler Routines
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Stefan Ginsberg (stefan.ginsberg@reactos.org)
10 /* INCLUDES ******************************************************************/
16 /* FUNCTIONS *****************************************************************/
20 KdpPrintString(IN PSTRING Output
)
23 DBGKD_DEBUG_IO DebugIo
;
27 KdpMoveMemory(KdpMessageBuffer
,
31 /* Make sure we don't exceed the KD Packet size */
32 Length
= Output
->Length
;
33 if ((sizeof(DBGKD_DEBUG_IO
) + Length
) > PACKET_MAX_SIZE
)
35 /* Normalize length */
36 Length
= PACKET_MAX_SIZE
- sizeof(DBGKD_DEBUG_IO
);
39 /* Build the packet header */
40 DebugIo
.ApiNumber
= DbgKdPrintStringApi
;
41 DebugIo
.ProcessorLevel
= (USHORT
)KeProcessorLevel
;
42 DebugIo
.Processor
= KeGetCurrentPrcb()->Number
;
43 DebugIo
.u
.PrintString
.LengthOfString
= Length
;
44 Header
.Length
= sizeof(DBGKD_DEBUG_IO
);
45 Header
.Buffer
= (PCHAR
)&DebugIo
;
49 Data
.Buffer
= KdpMessageBuffer
;
52 KdSendPacket(PACKET_TYPE_KD_DEBUG_IO
, &Header
, &Data
, &KdpContext
);
54 /* Check if the user pressed CTRL+C */
55 return KdpPollBreakInWithPortLock();
60 KdpPromptString(IN PSTRING PromptString
,
61 IN PSTRING ResponseString
)
64 DBGKD_DEBUG_IO DebugIo
;
68 /* Copy the string to the message buffer */
69 KdpMoveMemory(KdpMessageBuffer
,
71 PromptString
->Length
);
73 /* Make sure we don't exceed the KD Packet size */
74 Length
= PromptString
->Length
;
75 if ((sizeof(DBGKD_DEBUG_IO
) + Length
) > PACKET_MAX_SIZE
)
77 /* Normalize length */
78 Length
= PACKET_MAX_SIZE
- sizeof(DBGKD_DEBUG_IO
);
81 /* Build the packet header */
82 DebugIo
.ApiNumber
= DbgKdGetStringApi
;
83 DebugIo
.ProcessorLevel
= (USHORT
)KeProcessorLevel
;
84 DebugIo
.Processor
= KeGetCurrentPrcb()->Number
;
85 DebugIo
.u
.GetString
.LengthOfPromptString
= Length
;
86 DebugIo
.u
.GetString
.LengthOfStringRead
= ResponseString
->MaximumLength
;
87 Header
.Length
= sizeof(DBGKD_DEBUG_IO
);
88 Header
.Buffer
= (PCHAR
)&DebugIo
;
92 Data
.Buffer
= KdpMessageBuffer
;
95 KdSendPacket(PACKET_TYPE_KD_DEBUG_IO
, &Header
, &Data
, &KdpContext
);
97 /* Set the maximum lengths for the receive */
98 Header
.MaximumLength
= sizeof(DBGKD_DEBUG_IO
);
99 Data
.MaximumLength
= sizeof(KdpMessageBuffer
);
101 /* Enter receive loop */
105 Status
= KdReceivePacket(PACKET_TYPE_KD_DEBUG_IO
,
111 /* Return TRUE if we need to resend */
112 if (Status
== KdPacketNeedsResend
) return TRUE
;
114 /* Loop until we succeed */
115 } while (Status
!= KdPacketReceived
);
117 /* Don't copy back a larger response than there is room for */
119 ResponseString
->MaximumLength
);
121 /* Copy back the string and return the length */
122 KdpMoveMemory(ResponseString
->Buffer
,
125 ResponseString
->Length
= (USHORT
)Length
;
127 /* Success; we don't need to resend */
133 KdpCommandString(IN PSTRING NameString
,
134 IN PSTRING CommandString
,
135 IN KPROCESSOR_MODE PreviousMode
,
136 IN PCONTEXT ContextRecord
,
137 IN PKTRAP_FRAME TrapFrame
,
138 IN PKEXCEPTION_FRAME ExceptionFrame
)
141 PKPRCB Prcb
= KeGetCurrentPrcb();
143 /* Check if we need to do anything */
144 if ((PreviousMode
!= KernelMode
) || (KdDebuggerNotPresent
)) return;
146 /* Enter the debugger */
147 Enable
= KdEnterDebugger(TrapFrame
, ExceptionFrame
);
149 /* Save the CPU Control State and save the context */
150 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
151 KdpMoveMemory(&Prcb
->ProcessorState
.ContextFrame
,
155 /* Send the command string to the debugger */
156 KdpReportCommandStringStateChange(NameString
,
158 &Prcb
->ProcessorState
.ContextFrame
);
160 /* Restore the processor state */
161 KdpMoveMemory(ContextRecord
,
162 &Prcb
->ProcessorState
.ContextFrame
,
164 KiRestoreProcessorControlState(&Prcb
->ProcessorState
);
166 /* Exit the debugger and return */
167 KdExitDebugger(Enable
);
172 KdpSymbol(IN PSTRING DllPath
,
173 IN PKD_SYMBOLS_INFO SymbolInfo
,
175 IN KPROCESSOR_MODE PreviousMode
,
176 IN PCONTEXT ContextRecord
,
177 IN PKTRAP_FRAME TrapFrame
,
178 IN PKEXCEPTION_FRAME ExceptionFrame
)
181 PKPRCB Prcb
= KeGetCurrentPrcb();
183 /* Check if we need to do anything */
184 if ((PreviousMode
!= KernelMode
) || (KdDebuggerNotPresent
)) return;
186 /* Enter the debugger */
187 Enable
= KdEnterDebugger(TrapFrame
, ExceptionFrame
);
189 /* Save the CPU Control State and save the context */
190 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
191 KdpMoveMemory(&Prcb
->ProcessorState
.ContextFrame
,
195 /* Report the new state */
196 KdpReportLoadSymbolsStateChange(DllPath
,
199 &Prcb
->ProcessorState
.ContextFrame
);
201 /* Restore the processor state */
202 KdpMoveMemory(ContextRecord
,
203 &Prcb
->ProcessorState
.ContextFrame
,
205 KiRestoreProcessorControlState(&Prcb
->ProcessorState
);
207 /* Exit the debugger and return */
208 KdExitDebugger(Enable
);
213 KdpPrompt(IN LPSTR PromptString
,
214 IN USHORT PromptLength
,
215 OUT PCHAR ResponseString
,
216 IN USHORT MaximumResponseLength
,
217 IN KPROCESSOR_MODE PreviousMode
,
218 IN PKTRAP_FRAME TrapFrame
,
219 IN PKEXCEPTION_FRAME ExceptionFrame
)
221 STRING PromptBuffer
, ResponseBuffer
;
222 BOOLEAN Enable
, Resend
;
223 PVOID CapturedPrompt
;
224 PCHAR SafeResponseString
;
226 /* Normalize the lengths */
227 PromptLength
= min(PromptLength
,
229 MaximumResponseLength
= min(MaximumResponseLength
,
232 /* Check if we need to verify the string */
233 if (PreviousMode
!= KernelMode
)
235 /* Handle user-mode buffers safely */
238 /* Probe the prompt */
239 ProbeForRead(PromptString
,
244 CapturedPrompt
= _alloca(PromptLength
);
245 KdpMoveMemory(CapturedPrompt
,
248 PromptString
= CapturedPrompt
;
250 /* Probe and make room for response */
251 ProbeForWrite(ResponseString
,
252 MaximumResponseLength
,
254 SafeResponseString
= _alloca(MaximumResponseLength
);
256 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
258 /* Bad string pointer, bail out */
259 _SEH2_YIELD(return 0);
265 SafeResponseString
= ResponseString
;
268 /* Setup the prompt and response buffers */
269 PromptBuffer
.Buffer
= PromptString
;
270 PromptBuffer
.Length
= PromptLength
;
271 ResponseBuffer
.Buffer
= SafeResponseString
;
272 ResponseBuffer
.Length
= 0;
273 ResponseBuffer
.MaximumLength
= MaximumResponseLength
;
276 //KdLogDbgPrint(&PromptBuffer);
278 /* Enter the debugger */
279 Enable
= KdEnterDebugger(TrapFrame
, ExceptionFrame
);
281 /* Enter prompt loop */
284 /* Send the prompt and receive the response */
285 Resend
= KdpPromptString(&PromptBuffer
, &ResponseBuffer
);
287 /* Loop while we need to resend */
290 /* Exit the debugger */
291 KdExitDebugger(Enable
);
293 /* Copy back response if required */
294 if (PreviousMode
!= KernelMode
)
298 /* Safely copy back response to user mode */
299 KdpMoveMemory(ResponseString
,
300 ResponseBuffer
.Buffer
,
301 ResponseBuffer
.Length
);
303 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
305 /* String became invalid after we exited, fail */
306 _SEH2_YIELD(return 0);
311 /* Return the number of characters received */
312 return ResponseBuffer
.Length
;
317 KdpPrint(IN ULONG ComponentId
,
321 IN KPROCESSOR_MODE PreviousMode
,
322 IN PKTRAP_FRAME TrapFrame
,
323 IN PKEXCEPTION_FRAME ExceptionFrame
,
324 OUT PBOOLEAN Handled
)
326 NTSTATUS ReturnStatus
;
329 PVOID CapturedString
;
334 /* Validate the mask */
335 if (Level
< 32) Level
= 1 << Level
;
336 if (!(Kd_WIN2000_Mask
& Level
) ||
337 ((ComponentId
< KdComponentTableSize
) &&
338 !(*KdComponentTable
[ComponentId
] & Level
)))
340 /* Mask validation failed */
342 return STATUS_SUCCESS
;
345 /* Normalize the length */
346 Length
= min(Length
, 512);
348 /* Check if we need to verify the buffer */
349 if (PreviousMode
!= KernelMode
)
351 /* Capture user-mode buffers */
354 /* Probe the string */
360 CapturedString
= alloca(Length
);
361 KdpMoveMemory(CapturedString
,
364 String
= CapturedString
;
366 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
368 /* Bad pointer, fail the print */
369 _SEH2_YIELD(return STATUS_ACCESS_VIOLATION
);
374 /* Setup the output string */
375 OutputString
.Buffer
= String
;
376 OutputString
.Length
= Length
;
379 //KdLogDbgPrint(&OutputString);
381 /* Check for a debugger */
382 if (KdDebuggerNotPresent
)
386 return STATUS_DEVICE_NOT_CONNECTED
;
389 /* Enter the debugger */
390 Enable
= KdEnterDebugger(TrapFrame
, ExceptionFrame
);
392 /* Print the string */
393 if (KdpPrintString(&OutputString
))
395 /* User pressed CTRL-C, breakpoint on return */
396 ReturnStatus
= STATUS_BREAKPOINT
;
400 /* String was printed */
401 ReturnStatus
= STATUS_SUCCESS
;
404 /* Exit the debugger and return */
405 KdExitDebugger(Enable
);
412 KdpDprintf(IN PCHAR Format
,
420 /* Format the string */
421 va_start(ap
, Format
);
422 Length
= (USHORT
)_vsnprintf(Buffer
,
428 String
.Buffer
= Buffer
;
429 String
.Length
= Length
+ 1;
431 /* Send it to the debugger directly */
432 KdpPrintString(&String
);