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