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