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 if (NtQueryDebugFilterState(ComponentId, Level) == (NTSTATUS)FALSE) 347 { 348 /* Mask validation failed */ 349 *Handled = TRUE; 350 return STATUS_SUCCESS; 351 } 352 353 /* Assume failure */ 354 *Handled = FALSE; 355 356 /* Normalize the length */ 357 Length = min(Length, sizeof(CapturedString)); 358 359 /* Check if we need to verify the string */ 360 if (PreviousMode != KernelMode) 361 { 362 /* Capture user-mode buffers */ 363 _SEH2_TRY 364 { 365 /* Probe and capture the string */ 366 ProbeForRead(String, Length, 1); 367 KdpMoveMemory(CapturedString, String, Length); 368 String = CapturedString; 369 } 370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 371 { 372 /* Bad string pointer, bail out */ 373 _SEH2_YIELD(return STATUS_ACCESS_VIOLATION); 374 } 375 _SEH2_END; 376 } 377 378 /* Setup the output string */ 379 OutputString.Buffer = String; 380 OutputString.Length = OutputString.MaximumLength = Length; 381 382 /* Log the print */ 383 //KdLogDbgPrint(&OutputString); 384 385 /* Check for a debugger */ 386 if (KdDebuggerNotPresent) 387 { 388 /* Fail */ 389 *Handled = TRUE; 390 return STATUS_DEVICE_NOT_CONNECTED; 391 } 392 393 /* Enter the debugger */ 394 Enable = KdEnterDebugger(TrapFrame, ExceptionFrame); 395 396 /* Print the string */ 397 if (KdpPrintString(&OutputString)) 398 { 399 /* User pressed CTRL-C, breakpoint on return */ 400 Status = STATUS_BREAKPOINT; 401 } 402 else 403 { 404 /* String was printed */ 405 Status = STATUS_SUCCESS; 406 } 407 408 /* Exit the debugger and return */ 409 KdExitDebugger(Enable); 410 *Handled = TRUE; 411 return Status; 412 } 413 414 VOID 415 __cdecl 416 KdpDprintf( 417 _In_ PCHAR Format, 418 ...) 419 { 420 STRING String; 421 USHORT Length; 422 va_list ap; 423 CHAR Buffer[100]; 424 425 /* Format the string */ 426 va_start(ap, Format); 427 Length = (USHORT)_vsnprintf(Buffer, 428 sizeof(Buffer), 429 Format, 430 ap); 431 va_end(ap); 432 433 /* Set it up */ 434 String.Buffer = Buffer; 435 String.Length = String.MaximumLength = Length; 436 437 /* Send it to the debugger directly */ 438 KdpPrintString(&String); 439 } 440