4d35bf6df76852fdb25fb3c7487f46b2159885db
[reactos.git] / ntoskrnl / kd64 / kdprint.c
1 /*
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)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FUNCTIONS *****************************************************************/
17
18 #ifdef _WINKD_
19
20 BOOLEAN
21 NTAPI
22 KdpPrintString(
23 _In_ PSTRING Output)
24 {
25 STRING Data, Header;
26 DBGKD_DEBUG_IO DebugIo;
27 USHORT Length;
28
29 /* Copy the string */
30 KdpMoveMemory(KdpMessageBuffer,
31 Output->Buffer,
32 Output->Length);
33
34 /* Make sure we don't exceed the KD Packet size */
35 Length = Output->Length;
36 if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE)
37 {
38 /* Normalize length */
39 Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
40 }
41
42 /* Build the packet header */
43 DebugIo.ApiNumber = DbgKdPrintStringApi;
44 DebugIo.ProcessorLevel = (USHORT)KeProcessorLevel;
45 DebugIo.Processor = KeGetCurrentPrcb()->Number;
46 DebugIo.u.PrintString.LengthOfString = Length;
47 Header.Length = sizeof(DBGKD_DEBUG_IO);
48 Header.Buffer = (PCHAR)&DebugIo;
49
50 /* Build the data */
51 Data.Length = Length;
52 Data.Buffer = KdpMessageBuffer;
53
54 /* Send the packet */
55 KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &Header, &Data, &KdpContext);
56
57 /* Check if the user pressed CTRL+C */
58 return KdpPollBreakInWithPortLock();
59 }
60
61 BOOLEAN
62 NTAPI
63 KdpPromptString(
64 _In_ PSTRING PromptString,
65 _In_ PSTRING ResponseString)
66 {
67 STRING Data, Header;
68 DBGKD_DEBUG_IO DebugIo;
69 ULONG Length;
70 KDSTATUS Status;
71
72 /* Copy the string to the message buffer */
73 KdpMoveMemory(KdpMessageBuffer,
74 PromptString->Buffer,
75 PromptString->Length);
76
77 /* Make sure we don't exceed the KD Packet size */
78 Length = PromptString->Length;
79 if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE)
80 {
81 /* Normalize length */
82 Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
83 }
84
85 /* Build the packet header */
86 DebugIo.ApiNumber = DbgKdGetStringApi;
87 DebugIo.ProcessorLevel = (USHORT)KeProcessorLevel;
88 DebugIo.Processor = KeGetCurrentPrcb()->Number;
89 DebugIo.u.GetString.LengthOfPromptString = Length;
90 DebugIo.u.GetString.LengthOfStringRead = ResponseString->MaximumLength;
91 Header.Length = sizeof(DBGKD_DEBUG_IO);
92 Header.Buffer = (PCHAR)&DebugIo;
93
94 /* Build the data */
95 Data.Length = Length;
96 Data.Buffer = KdpMessageBuffer;
97
98 /* Send the packet */
99 KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &Header, &Data, &KdpContext);
100
101 /* Set the maximum lengths for the receive */
102 Header.MaximumLength = sizeof(DBGKD_DEBUG_IO);
103 Data.MaximumLength = sizeof(KdpMessageBuffer);
104
105 /* Enter receive loop */
106 do
107 {
108 /* Get our reply */
109 Status = KdReceivePacket(PACKET_TYPE_KD_DEBUG_IO,
110 &Header,
111 &Data,
112 &Length,
113 &KdpContext);
114
115 /* Return TRUE if we need to resend */
116 if (Status == KdPacketNeedsResend) return TRUE;
117
118 /* Loop until we succeed */
119 } while (Status != KdPacketReceived);
120
121 /* Don't copy back a larger response than there is room for */
122 Length = min(Length,
123 ResponseString->MaximumLength);
124
125 /* Copy back the string and return the length */
126 KdpMoveMemory(ResponseString->Buffer,
127 KdpMessageBuffer,
128 Length);
129 ResponseString->Length = (USHORT)Length;
130
131 /* Success; we don't need to resend */
132 return FALSE;
133 }
134
135 VOID
136 NTAPI
137 KdpCommandString(IN PSTRING NameString,
138 IN PSTRING CommandString,
139 IN KPROCESSOR_MODE PreviousMode,
140 IN PCONTEXT ContextRecord,
141 IN PKTRAP_FRAME TrapFrame,
142 IN PKEXCEPTION_FRAME ExceptionFrame)
143 {
144 BOOLEAN Enable;
145 PKPRCB Prcb = KeGetCurrentPrcb();
146
147 /* Check if we need to do anything */
148 if ((PreviousMode != KernelMode) || (KdDebuggerNotPresent)) return;
149
150 /* Enter the debugger */
151 Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
152
153 /* Save the CPU Control State and save the context */
154 KiSaveProcessorControlState(&Prcb->ProcessorState);
155 KdpMoveMemory(&Prcb->ProcessorState.ContextFrame,
156 ContextRecord,
157 sizeof(CONTEXT));
158
159 /* Send the command string to the debugger */
160 KdpReportCommandStringStateChange(NameString,
161 CommandString,
162 &Prcb->ProcessorState.ContextFrame);
163
164 /* Restore the processor state */
165 KdpMoveMemory(ContextRecord,
166 &Prcb->ProcessorState.ContextFrame,
167 sizeof(CONTEXT));
168 KiRestoreProcessorControlState(&Prcb->ProcessorState);
169
170 /* Exit the debugger and return */
171 KdExitDebugger(Enable);
172 }
173
174 VOID
175 NTAPI
176 KdpSymbol(IN PSTRING DllPath,
177 IN PKD_SYMBOLS_INFO SymbolInfo,
178 IN BOOLEAN Unload,
179 IN KPROCESSOR_MODE PreviousMode,
180 IN PCONTEXT ContextRecord,
181 IN PKTRAP_FRAME TrapFrame,
182 IN PKEXCEPTION_FRAME ExceptionFrame)
183 {
184 BOOLEAN Enable;
185 PKPRCB Prcb = KeGetCurrentPrcb();
186
187 /* Check if we need to do anything */
188 if ((PreviousMode != KernelMode) || (KdDebuggerNotPresent)) return;
189
190 /* Enter the debugger */
191 Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
192
193 /* Save the CPU Control State and save the context */
194 KiSaveProcessorControlState(&Prcb->ProcessorState);
195 KdpMoveMemory(&Prcb->ProcessorState.ContextFrame,
196 ContextRecord,
197 sizeof(CONTEXT));
198
199 /* Report the new state */
200 KdpReportLoadSymbolsStateChange(DllPath,
201 SymbolInfo,
202 Unload,
203 &Prcb->ProcessorState.ContextFrame);
204
205 /* Restore the processor state */
206 KdpMoveMemory(ContextRecord,
207 &Prcb->ProcessorState.ContextFrame,
208 sizeof(CONTEXT));
209 KiRestoreProcessorControlState(&Prcb->ProcessorState);
210
211 /* Exit the debugger and return */
212 KdExitDebugger(Enable);
213 }
214
215 #else
216
217 extern
218 BOOLEAN
219 NTAPI
220 KdpPrintString(
221 _In_ PSTRING Output);
222
223 extern
224 BOOLEAN
225 NTAPI
226 KdpPromptString(
227 _In_ PSTRING PromptString,
228 _In_ PSTRING ResponseString);
229
230 #endif // _WINKD_
231
232 USHORT
233 NTAPI
234 KdpPrompt(
235 _In_reads_bytes_(PromptLength) PCHAR PromptString,
236 _In_ USHORT PromptLength,
237 _Out_writes_bytes_(MaximumResponseLength) PCHAR ResponseString,
238 _In_ USHORT MaximumResponseLength,
239 _In_ KPROCESSOR_MODE PreviousMode,
240 _In_ PKTRAP_FRAME TrapFrame,
241 _In_ PKEXCEPTION_FRAME ExceptionFrame)
242 {
243 STRING PromptBuffer, ResponseBuffer;
244 BOOLEAN Enable, Resend;
245 PCHAR SafeResponseString;
246 CHAR CapturedPrompt[512];
247 CHAR SafeResponseBuffer[512];
248
249 /* Normalize the lengths */
250 PromptLength = min(PromptLength,
251 sizeof(CapturedPrompt));
252 MaximumResponseLength = min(MaximumResponseLength,
253 sizeof(SafeResponseBuffer));
254
255 /* Check if we need to verify the string */
256 if (PreviousMode != KernelMode)
257 {
258 /* Handle user-mode buffers safely */
259 _SEH2_TRY
260 {
261 /* Probe and capture the prompt */
262 ProbeForRead(PromptString, PromptLength, 1);
263 KdpMoveMemory(CapturedPrompt, PromptString, PromptLength);
264 PromptString = CapturedPrompt;
265
266 /* Probe and make room for the response */
267 ProbeForWrite(ResponseString, MaximumResponseLength, 1);
268 SafeResponseString = SafeResponseBuffer;
269 }
270 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
271 {
272 /* Bad string pointer, bail out */
273 _SEH2_YIELD(return 0);
274 }
275 _SEH2_END;
276 }
277 else
278 {
279 SafeResponseString = ResponseString;
280 }
281
282 /* Setup the prompt and response buffers */
283 PromptBuffer.Buffer = PromptString;
284 PromptBuffer.Length = PromptBuffer.MaximumLength = PromptLength;
285 ResponseBuffer.Buffer = SafeResponseString;
286 ResponseBuffer.Length = 0;
287 ResponseBuffer.MaximumLength = MaximumResponseLength;
288
289 /* Log the print */
290 //KdLogDbgPrint(&PromptBuffer);
291
292 /* Enter the debugger */
293 Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
294
295 /* Enter prompt loop */
296 do
297 {
298 /* Send the prompt and receive the response */
299 Resend = KdpPromptString(&PromptBuffer, &ResponseBuffer);
300
301 /* Loop while we need to resend */
302 } while (Resend);
303
304 /* Exit the debugger */
305 KdExitDebugger(Enable);
306
307 /* Copy back the response if required */
308 if (PreviousMode != KernelMode)
309 {
310 _SEH2_TRY
311 {
312 /* Safely copy back the response to user mode */
313 KdpMoveMemory(ResponseString,
314 ResponseBuffer.Buffer,
315 ResponseBuffer.Length);
316 }
317 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
318 {
319 /* String became invalid after we exited, fail */
320 _SEH2_YIELD(return 0);
321 }
322 _SEH2_END;
323 }
324
325 /* Return the number of characters received */
326 return ResponseBuffer.Length;
327 }
328
329 NTSTATUS
330 NTAPI
331 KdpPrint(
332 _In_ ULONG ComponentId,
333 _In_ ULONG Level,
334 _In_reads_bytes_(Length) PCHAR String,
335 _In_ USHORT Length,
336 _In_ KPROCESSOR_MODE PreviousMode,
337 _In_ PKTRAP_FRAME TrapFrame,
338 _In_ PKEXCEPTION_FRAME ExceptionFrame,
339 _Out_ PBOOLEAN Handled)
340 {
341 NTSTATUS Status;
342 BOOLEAN Enable;
343 STRING OutputString;
344 CHAR CapturedString[512];
345
346 /* Assume failure */
347 *Handled = FALSE;
348
349 #if (NTDDI_VERSION >= NTDDI_VISTA)
350 if ((ComponentId >= KdComponentTableSize) && (ComponentId < MAXULONG))
351 {
352 /* Use the default component ID */
353 Mask = &Kd_DEFAULT_Mask;
354 // Level = DPFLTR_INFO_LEVEL; // Override the Level.
355 }
356 #endif
357 /* Convert Level to bit field if required */
358 if (Level < 32) Level = 1 << Level;
359 Level &= ~DPFLTR_MASK;
360
361 /* Validate the mask */
362 if (!(Kd_WIN2000_Mask & Level) ||
363 ((ComponentId < KdComponentTableSize) &&
364 !(*KdComponentTable[ComponentId] & Level)))
365 {
366 /* Mask validation failed */
367 *Handled = TRUE;
368 return STATUS_SUCCESS;
369 }
370
371 /* Normalize the length */
372 Length = min(Length, sizeof(CapturedString));
373
374 /* Check if we need to verify the string */
375 if (PreviousMode != KernelMode)
376 {
377 /* Capture user-mode buffers */
378 _SEH2_TRY
379 {
380 /* Probe and capture the string */
381 ProbeForRead(String, Length, 1);
382 KdpMoveMemory(CapturedString, String, Length);
383 String = CapturedString;
384 }
385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
386 {
387 /* Bad string pointer, bail out */
388 _SEH2_YIELD(return STATUS_ACCESS_VIOLATION);
389 }
390 _SEH2_END;
391 }
392
393 /* Setup the output string */
394 OutputString.Buffer = String;
395 OutputString.Length = OutputString.MaximumLength = Length;
396
397 /* Log the print */
398 //KdLogDbgPrint(&OutputString);
399
400 /* Check for a debugger */
401 if (KdDebuggerNotPresent)
402 {
403 /* Fail */
404 *Handled = TRUE;
405 return STATUS_DEVICE_NOT_CONNECTED;
406 }
407
408 /* Enter the debugger */
409 Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
410
411 /* Print the string */
412 if (KdpPrintString(&OutputString))
413 {
414 /* User pressed CTRL-C, breakpoint on return */
415 Status = STATUS_BREAKPOINT;
416 }
417 else
418 {
419 /* String was printed */
420 Status = STATUS_SUCCESS;
421 }
422
423 /* Exit the debugger and return */
424 KdExitDebugger(Enable);
425 *Handled = TRUE;
426 return Status;
427 }
428
429 VOID
430 __cdecl
431 KdpDprintf(
432 _In_ PCHAR Format,
433 ...)
434 {
435 STRING String;
436 USHORT Length;
437 va_list ap;
438 CHAR Buffer[100];
439
440 /* Format the string */
441 va_start(ap, Format);
442 Length = (USHORT)_vsnprintf(Buffer,
443 sizeof(Buffer),
444 Format,
445 ap);
446 va_end(ap);
447
448 /* Set it up */
449 String.Buffer = Buffer;
450 String.Length = String.MaximumLength = Length;
451
452 /* Send it to the debugger directly */
453 KdpPrintString(&String);
454 }