* Sync with trunk r64401.
[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 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
217 /* Normalize the lengths */
218 PromptLength = min(PromptLength, 512);
219 MaximumResponseLength = min(MaximumResponseLength, 512);
220
221 /* Check if we need to verify the string */
222 if (PreviousMode != KernelMode)
223 {
224 /* FIXME: Handle user-mode */
225 }
226
227 /* Setup the prompt and response buffers */
228 PromptBuffer.Buffer = PromptString;
229 PromptBuffer.Length = PromptLength;
230 ResponseBuffer.Buffer = ResponseString;
231 ResponseBuffer.Length = 0;
232 ResponseBuffer.MaximumLength = MaximumResponseLength;
233
234 /* Log the print */
235 //KdLogDbgPrint(&PromptBuffer);
236
237 /* Enter the debugger */
238 Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
239
240 /* Enter prompt loop */
241 do
242 {
243 /* Send the prompt and receive the response */
244 Resend = KdpPromptString(&PromptBuffer, &ResponseBuffer);
245
246 /* Loop while we need to resend */
247 } while (Resend);
248
249 /* Exit the debugger */
250 KdExitDebugger(Enable);
251
252 /* Return the number of characters received */
253 return ResponseBuffer.Length;
254 }
255
256 NTSTATUS
257 NTAPI
258 KdpPrint(IN ULONG ComponentId,
259 IN ULONG Level,
260 IN LPSTR String,
261 IN USHORT Length,
262 IN KPROCESSOR_MODE PreviousMode,
263 IN PKTRAP_FRAME TrapFrame,
264 IN PKEXCEPTION_FRAME ExceptionFrame,
265 OUT PBOOLEAN Handled)
266 {
267 NTSTATUS ReturnStatus;
268 BOOLEAN Enable;
269 STRING OutputString;
270
271 /* Assume failure */
272 *Handled = FALSE;
273
274 /* Validate the mask */
275 if (Level < 32) Level = 1 << Level;
276 if (!(Kd_WIN2000_Mask & Level) ||
277 ((ComponentId < KdComponentTableSize) &&
278 !(*KdComponentTable[ComponentId] & Level)))
279 {
280 /* Mask validation failed */
281 *Handled = TRUE;
282 return STATUS_SUCCESS;
283 }
284
285 /* Normalize the length */
286 Length = min(Length, 512);
287
288 /* Check if we need to verify the buffer */
289 if (PreviousMode != KernelMode)
290 {
291 /* FIXME: Support user-mode */
292 }
293
294 /* Setup the output string */
295 OutputString.Buffer = String;
296 OutputString.Length = Length;
297
298 /* Log the print */
299 //KdLogDbgPrint(&OutputString);
300
301 /* Check for a debugger */
302 if (KdDebuggerNotPresent)
303 {
304 /* Fail */
305 *Handled = TRUE;
306 return STATUS_DEVICE_NOT_CONNECTED;
307 }
308
309 /* Enter the debugger */
310 Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
311
312 /* Print the string */
313 if (KdpPrintString(&OutputString))
314 {
315 /* User pressed CTRL-C, breakpoint on return */
316 ReturnStatus = STATUS_BREAKPOINT;
317 }
318 else
319 {
320 /* String was printed */
321 ReturnStatus = STATUS_SUCCESS;
322 }
323
324 /* Exit the debugger and return */
325 KdExitDebugger(Enable);
326 *Handled = TRUE;
327 return ReturnStatus;
328 }
329
330 VOID
331 __cdecl
332 KdpDprintf(IN PCHAR Format,
333 ...)
334 {
335 STRING String;
336 CHAR Buffer[100];
337 USHORT Length;
338 va_list ap;
339
340 /* Format the string */
341 va_start(ap, Format);
342 Length = (USHORT)_vsnprintf(Buffer,
343 sizeof(Buffer),
344 Format,
345 ap);
346
347 /* Set it up */
348 String.Buffer = Buffer;
349 String.Length = Length + 1;
350
351 /* Send it to the debugger directly */
352 KdpPrintString(&String);
353 va_end(ap);
354 }