1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/kd/kdio.c 5 * PURPOSE: NT Kernel Debugger Input/Output Functions 6 * 7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #include <reactos/buildno.h> 14 #include "kd.h" 15 #include "kdterminal.h" 16 #ifdef KDBG 17 #include "../kdbg/kdb.h" 18 #endif 19 20 #define NDEBUG 21 #include <debug.h> 22 23 /* GLOBALS *******************************************************************/ 24 25 #define KdpBufferSize (1024 * 512) 26 static BOOLEAN KdpLoggingEnabled = FALSE; 27 static PCHAR KdpDebugBuffer = NULL; 28 static volatile ULONG KdpCurrentPosition = 0; 29 static volatile ULONG KdpFreeBytes = 0; 30 static KSPIN_LOCK KdpDebugLogSpinLock; 31 static KEVENT KdpLoggerThreadEvent; 32 static HANDLE KdpLogFileHandle; 33 ANSI_STRING KdpLogFileName = RTL_CONSTANT_STRING("\\SystemRoot\\debug.log"); 34 35 static KSPIN_LOCK KdpSerialSpinLock; 36 ULONG SerialPortNumber = DEFAULT_DEBUG_PORT; 37 CPPORT SerialPortInfo = {0, DEFAULT_DEBUG_BAUD_RATE, 0}; 38 39 #define KdpScreenLineLengthDefault 80 40 static CHAR KdpScreenLineBuffer[KdpScreenLineLengthDefault + 1] = ""; 41 static ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0; 42 43 KDP_DEBUG_MODE KdpDebugMode; 44 LIST_ENTRY KdProviders = {&KdProviders, &KdProviders}; 45 KD_DISPATCH_TABLE DispatchTable[KdMax] = {0}; 46 47 PKDP_INIT_ROUTINE InitRoutines[KdMax] = 48 { 49 KdpScreenInit, 50 KdpSerialInit, 51 KdpDebugLogInit, 52 #ifdef KDBG // See kdb_cli.c 53 KdpKdbgInit 54 #endif 55 }; 56 57 static ULONG KdbgNextApiNumber = DbgKdContinueApi; 58 static CONTEXT KdbgContext; 59 static EXCEPTION_RECORD64 KdbgExceptionRecord; 60 static BOOLEAN KdbgFirstChanceException; 61 static NTSTATUS KdbgContinueStatus = STATUS_SUCCESS; 62 63 /* LOCKING FUNCTIONS *********************************************************/ 64 65 KIRQL 66 NTAPI 67 KdbpAcquireLock( 68 _In_ PKSPIN_LOCK SpinLock) 69 { 70 KIRQL OldIrql; 71 72 /* Acquire the spinlock without waiting at raised IRQL */ 73 while (TRUE) 74 { 75 /* Loop until the spinlock becomes available */ 76 while (!KeTestSpinLock(SpinLock)); 77 78 /* Spinlock is free, raise IRQL to high level */ 79 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 80 81 /* Try to get the spinlock */ 82 if (KeTryToAcquireSpinLockAtDpcLevel(SpinLock)) 83 break; 84 85 /* Someone else got the spinlock, lower IRQL back */ 86 KeLowerIrql(OldIrql); 87 } 88 89 return OldIrql; 90 } 91 92 VOID 93 NTAPI 94 KdbpReleaseLock( 95 _In_ PKSPIN_LOCK SpinLock, 96 _In_ KIRQL OldIrql) 97 { 98 /* Release the spinlock */ 99 KiReleaseSpinLock(SpinLock); 100 // KeReleaseSpinLockFromDpcLevel(SpinLock); 101 102 /* Restore the old IRQL */ 103 KeLowerIrql(OldIrql); 104 } 105 106 /* FILE DEBUG LOG FUNCTIONS **************************************************/ 107 108 static VOID 109 NTAPI 110 KdpLoggerThread(PVOID Context) 111 { 112 ULONG beg, end, num; 113 IO_STATUS_BLOCK Iosb; 114 115 ASSERT(ExGetPreviousMode() == KernelMode); 116 117 KdpLoggingEnabled = TRUE; 118 119 while (TRUE) 120 { 121 KeWaitForSingleObject(&KdpLoggerThreadEvent, Executive, KernelMode, FALSE, NULL); 122 123 /* Bug */ 124 /* Keep KdpCurrentPosition and KdpFreeBytes values in local 125 * variables to avoid their possible change from Producer part, 126 * KdpPrintToLogFile function 127 */ 128 end = KdpCurrentPosition; 129 num = KdpFreeBytes; 130 131 /* Now securely calculate values, based on local variables */ 132 beg = (end + num) % KdpBufferSize; 133 num = KdpBufferSize - num; 134 135 /* Nothing to do? */ 136 if (num == 0) 137 continue; 138 139 if (end > beg) 140 { 141 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb, 142 KdpDebugBuffer + beg, num, NULL, NULL); 143 } 144 else 145 { 146 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb, 147 KdpDebugBuffer + beg, KdpBufferSize - beg, NULL, NULL); 148 149 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb, 150 KdpDebugBuffer, end, NULL, NULL); 151 } 152 153 (VOID)InterlockedExchangeAddUL(&KdpFreeBytes, num); 154 } 155 } 156 157 static VOID 158 NTAPI 159 KdpPrintToLogFile( 160 _In_ PCCH String, 161 _In_ ULONG Length) 162 { 163 KIRQL OldIrql; 164 ULONG beg, end, num; 165 166 if (KdpDebugBuffer == NULL) return; 167 168 /* Acquire the printing spinlock without waiting at raised IRQL */ 169 OldIrql = KdbpAcquireLock(&KdpDebugLogSpinLock); 170 171 beg = KdpCurrentPosition; 172 num = min(Length, KdpFreeBytes); 173 if (num != 0) 174 { 175 end = (beg + num) % KdpBufferSize; 176 KdpCurrentPosition = end; 177 KdpFreeBytes -= num; 178 179 if (end > beg) 180 { 181 RtlCopyMemory(KdpDebugBuffer + beg, String, num); 182 } 183 else 184 { 185 RtlCopyMemory(KdpDebugBuffer + beg, String, KdpBufferSize - beg); 186 RtlCopyMemory(KdpDebugBuffer, String + KdpBufferSize - beg, end); 187 } 188 } 189 190 /* Release the spinlock */ 191 KdbpReleaseLock(&KdpDebugLogSpinLock, OldIrql); 192 193 /* Signal the logger thread */ 194 if (OldIrql <= DISPATCH_LEVEL && KdpLoggingEnabled) 195 KeSetEvent(&KdpLoggerThreadEvent, IO_NO_INCREMENT, FALSE); 196 } 197 198 NTSTATUS 199 NTAPI 200 KdpDebugLogInit( 201 _In_ PKD_DISPATCH_TABLE DispatchTable, 202 _In_ ULONG BootPhase) 203 { 204 NTSTATUS Status = STATUS_SUCCESS; 205 206 if (!KdpDebugMode.File) 207 return STATUS_PORT_DISCONNECTED; 208 209 if (BootPhase == 0) 210 { 211 /* Write out the functions that we support for now */ 212 DispatchTable->KdpPrintRoutine = KdpPrintToLogFile; 213 214 /* Register for BootPhase 1 initialization and as a Provider */ 215 DispatchTable->KdpInitRoutine = KdpDebugLogInit; 216 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); 217 } 218 else if (BootPhase == 1) 219 { 220 /* Allocate a buffer for debug log */ 221 KdpDebugBuffer = ExAllocatePoolZero(NonPagedPool, 222 KdpBufferSize, 223 TAG_KDBG); 224 if (!KdpDebugBuffer) 225 { 226 KdpDebugMode.File = FALSE; 227 RemoveEntryList(&DispatchTable->KdProvidersList); 228 return STATUS_NO_MEMORY; 229 } 230 KdpFreeBytes = KdpBufferSize; 231 232 /* Initialize spinlock */ 233 KeInitializeSpinLock(&KdpDebugLogSpinLock); 234 235 /* Register for later BootPhase 2 reinitialization */ 236 DispatchTable->KdpInitRoutine = KdpDebugLogInit; 237 238 /* Announce ourselves */ 239 HalDisplayString(" File log debugging enabled\r\n"); 240 } 241 else if (BootPhase >= 2) 242 { 243 UNICODE_STRING FileName; 244 OBJECT_ATTRIBUTES ObjectAttributes; 245 IO_STATUS_BLOCK Iosb; 246 HANDLE ThreadHandle; 247 KPRIORITY Priority; 248 249 /* If we have already successfully opened the log file, bail out */ 250 if (KdpLogFileHandle != NULL) 251 return STATUS_SUCCESS; 252 253 /* Setup the log name */ 254 Status = RtlAnsiStringToUnicodeString(&FileName, &KdpLogFileName, TRUE); 255 if (!NT_SUCCESS(Status)) 256 goto Failure; 257 258 InitializeObjectAttributes(&ObjectAttributes, 259 &FileName, 260 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 261 NULL, 262 NULL); 263 264 /* Create the log file */ 265 Status = ZwCreateFile(&KdpLogFileHandle, 266 FILE_APPEND_DATA | SYNCHRONIZE, 267 &ObjectAttributes, 268 &Iosb, 269 NULL, 270 FILE_ATTRIBUTE_NORMAL, 271 FILE_SHARE_READ, 272 FILE_OPEN_IF, 273 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 274 FILE_SEQUENTIAL_ONLY | FILE_WRITE_THROUGH, 275 NULL, 276 0); 277 278 RtlFreeUnicodeString(&FileName); 279 280 if (!NT_SUCCESS(Status)) 281 { 282 DPRINT1("Failed to open log file: 0x%08lx\n", Status); 283 284 /* Schedule an I/O reinitialization if needed */ 285 if (Status == STATUS_OBJECT_NAME_NOT_FOUND || 286 Status == STATUS_OBJECT_PATH_NOT_FOUND) 287 { 288 DispatchTable->KdpInitRoutine = KdpDebugLogInit; 289 return Status; 290 } 291 goto Failure; 292 } 293 294 /** HACK for FILE_APPEND_DATA ** 295 ** Remove once CORE-18789 is fixed. ** 296 ** Enforce to go to the end of file **/ 297 { 298 FILE_STANDARD_INFORMATION FileInfo; 299 FILE_POSITION_INFORMATION FilePosInfo; 300 301 Status = ZwQueryInformationFile(KdpLogFileHandle, 302 &Iosb, 303 &FileInfo, 304 sizeof(FileInfo), 305 FileStandardInformation); 306 DPRINT("Status: 0x%08lx - EOF offset: %I64d\n", 307 Status, FileInfo.EndOfFile.QuadPart); 308 309 Status = ZwQueryInformationFile(KdpLogFileHandle, 310 &Iosb, 311 &FilePosInfo, 312 sizeof(FilePosInfo), 313 FilePositionInformation); 314 DPRINT("Status: 0x%08lx - Position: %I64d\n", 315 Status, FilePosInfo.CurrentByteOffset.QuadPart); 316 317 FilePosInfo.CurrentByteOffset.QuadPart = FileInfo.EndOfFile.QuadPart; 318 Status = ZwSetInformationFile(KdpLogFileHandle, 319 &Iosb, 320 &FilePosInfo, 321 sizeof(FilePosInfo), 322 FilePositionInformation); 323 DPRINT("ZwSetInformationFile(FilePositionInfo) returned: 0x%08lx\n", Status); 324 } 325 /** END OF HACK **/ 326 327 KeInitializeEvent(&KdpLoggerThreadEvent, SynchronizationEvent, TRUE); 328 329 /* Create the logger thread */ 330 Status = PsCreateSystemThread(&ThreadHandle, 331 THREAD_ALL_ACCESS, 332 NULL, 333 NULL, 334 NULL, 335 KdpLoggerThread, 336 NULL); 337 if (!NT_SUCCESS(Status)) 338 { 339 DPRINT1("Failed to create log file thread: 0x%08lx\n", Status); 340 ZwClose(KdpLogFileHandle); 341 goto Failure; 342 } 343 344 Priority = HIGH_PRIORITY; 345 ZwSetInformationThread(ThreadHandle, 346 ThreadPriority, 347 &Priority, 348 sizeof(Priority)); 349 350 ZwClose(ThreadHandle); 351 return Status; 352 353 Failure: 354 KdpFreeBytes = 0; 355 ExFreePoolWithTag(KdpDebugBuffer, TAG_KDBG); 356 KdpDebugBuffer = NULL; 357 KdpDebugMode.File = FALSE; 358 RemoveEntryList(&DispatchTable->KdProvidersList); 359 } 360 361 return Status; 362 } 363 364 /* SERIAL FUNCTIONS **********************************************************/ 365 366 static VOID 367 NTAPI 368 KdpSerialPrint( 369 _In_ PCCH String, 370 _In_ ULONG Length) 371 { 372 PCCH pch = String; 373 KIRQL OldIrql; 374 375 /* Acquire the printing spinlock without waiting at raised IRQL */ 376 OldIrql = KdbpAcquireLock(&KdpSerialSpinLock); 377 378 /* Output the string */ 379 while (pch < String + Length && *pch) 380 { 381 if (*pch == '\n') 382 { 383 KdPortPutByteEx(&SerialPortInfo, '\r'); 384 } 385 KdPortPutByteEx(&SerialPortInfo, *pch); 386 ++pch; 387 } 388 389 /* Release the spinlock */ 390 KdbpReleaseLock(&KdpSerialSpinLock, OldIrql); 391 } 392 393 NTSTATUS 394 NTAPI 395 KdpSerialInit( 396 _In_ PKD_DISPATCH_TABLE DispatchTable, 397 _In_ ULONG BootPhase) 398 { 399 if (!KdpDebugMode.Serial) 400 return STATUS_PORT_DISCONNECTED; 401 402 if (BootPhase == 0) 403 { 404 /* Write out the functions that we support for now */ 405 DispatchTable->KdpPrintRoutine = KdpSerialPrint; 406 407 /* Initialize the Port */ 408 if (!KdPortInitializeEx(&SerialPortInfo, SerialPortNumber)) 409 { 410 KdpDebugMode.Serial = FALSE; 411 return STATUS_DEVICE_DOES_NOT_EXIST; 412 } 413 KdComPortInUse = SerialPortInfo.Address; 414 415 /* Initialize spinlock */ 416 KeInitializeSpinLock(&KdpSerialSpinLock); 417 418 /* Register for BootPhase 1 initialization and as a Provider */ 419 DispatchTable->KdpInitRoutine = KdpSerialInit; 420 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); 421 } 422 else if (BootPhase == 1) 423 { 424 /* Announce ourselves */ 425 HalDisplayString(" Serial debugging enabled\r\n"); 426 } 427 428 return STATUS_SUCCESS; 429 } 430 431 /* SCREEN FUNCTIONS **********************************************************/ 432 433 VOID 434 KdpScreenAcquire(VOID) 435 { 436 if (InbvIsBootDriverInstalled() /* && 437 !InbvCheckDisplayOwnership() */) 438 { 439 /* Acquire ownership and reset the display */ 440 InbvAcquireDisplayOwnership(); 441 InbvResetDisplay(); 442 InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK); 443 InbvSetTextColor(BV_COLOR_WHITE); 444 InbvInstallDisplayStringFilter(NULL); 445 InbvEnableDisplayString(TRUE); 446 InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); 447 } 448 } 449 450 // extern VOID NTAPI InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned); 451 452 VOID 453 KdpScreenRelease(VOID) 454 { 455 if (InbvIsBootDriverInstalled()&& 456 InbvCheckDisplayOwnership()) 457 { 458 /* Release the display */ 459 // InbvSetDisplayOwnership(FALSE); 460 InbvNotifyDisplayOwnershipLost(NULL); 461 } 462 } 463 464 static VOID 465 NTAPI 466 KdpScreenPrint( 467 _In_ PCCH String, 468 _In_ ULONG Length) 469 { 470 PCCH pch = String; 471 472 while (pch < String + Length && *pch) 473 { 474 if (*pch == '\b') 475 { 476 /* HalDisplayString does not support '\b'. Workaround it and use '\r' */ 477 if (KdpScreenLineLength > 0) 478 { 479 /* Remove last character from buffer */ 480 KdpScreenLineBuffer[--KdpScreenLineLength] = '\0'; 481 KdpScreenLineBufferPos = KdpScreenLineLength; 482 483 /* Clear row and print line again */ 484 HalDisplayString("\r"); 485 HalDisplayString(KdpScreenLineBuffer); 486 } 487 } 488 else 489 { 490 KdpScreenLineBuffer[KdpScreenLineLength++] = *pch; 491 KdpScreenLineBuffer[KdpScreenLineLength] = '\0'; 492 } 493 494 if (*pch == '\n' || KdpScreenLineLength == KdpScreenLineLengthDefault) 495 { 496 /* Print buffered characters */ 497 if (KdpScreenLineBufferPos != KdpScreenLineLength) 498 HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos); 499 500 /* Clear line buffer */ 501 KdpScreenLineBuffer[0] = '\0'; 502 KdpScreenLineLength = KdpScreenLineBufferPos = 0; 503 } 504 505 ++pch; 506 } 507 508 /* Print buffered characters */ 509 if (KdpScreenLineBufferPos != KdpScreenLineLength) 510 { 511 HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos); 512 KdpScreenLineBufferPos = KdpScreenLineLength; 513 } 514 } 515 516 NTSTATUS 517 NTAPI 518 KdpScreenInit( 519 _In_ PKD_DISPATCH_TABLE DispatchTable, 520 _In_ ULONG BootPhase) 521 { 522 if (!KdpDebugMode.Screen) 523 return STATUS_PORT_DISCONNECTED; 524 525 if (BootPhase == 0) 526 { 527 /* Write out the functions that we support for now */ 528 DispatchTable->KdpPrintRoutine = KdpScreenPrint; 529 530 /* Register for BootPhase 1 initialization and as a Provider */ 531 DispatchTable->KdpInitRoutine = KdpScreenInit; 532 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); 533 } 534 else if (BootPhase == 1) 535 { 536 /* Take control of the display */ 537 KdpScreenAcquire(); 538 539 /* Announce ourselves */ 540 HalDisplayString(" Screen debugging enabled\r\n"); 541 } 542 543 return STATUS_SUCCESS; 544 } 545 546 547 /* GENERAL FUNCTIONS *********************************************************/ 548 549 static VOID 550 KdIoPrintString( 551 _In_ PCCH String, 552 _In_ ULONG Length) 553 { 554 PLIST_ENTRY CurrentEntry; 555 PKD_DISPATCH_TABLE CurrentTable; 556 557 /* Call the registered providers */ 558 for (CurrentEntry = KdProviders.Flink; 559 CurrentEntry != &KdProviders; 560 CurrentEntry = CurrentEntry->Flink) 561 { 562 CurrentTable = CONTAINING_RECORD(CurrentEntry, 563 KD_DISPATCH_TABLE, 564 KdProvidersList); 565 566 CurrentTable->KdpPrintRoutine(String, Length); 567 } 568 } 569 570 VOID 571 KdIoPuts( 572 _In_ PCSTR String) 573 { 574 KdIoPrintString(String, (ULONG)strlen(String)); 575 } 576 577 VOID 578 __cdecl 579 KdIoPrintf( 580 _In_ PCSTR Format, 581 ...) 582 { 583 va_list ap; 584 ULONG Length; 585 CHAR Buffer[512]; 586 587 /* Format the string */ 588 va_start(ap, Format); 589 Length = (ULONG)_vsnprintf(Buffer, 590 sizeof(Buffer), 591 Format, 592 ap); 593 va_end(ap); 594 595 /* Send it to the display providers */ 596 KdIoPrintString(Buffer, Length); 597 } 598 599 600 extern const CSTRING KdbPromptStr; 601 602 VOID 603 NTAPI 604 KdSendPacket( 605 _In_ ULONG PacketType, 606 _In_ PSTRING MessageHeader, 607 _In_opt_ PSTRING MessageData, 608 _Inout_ PKD_CONTEXT Context) 609 { 610 if (PacketType == PACKET_TYPE_KD_DEBUG_IO) 611 { 612 ULONG ApiNumber = ((PDBGKD_DEBUG_IO)MessageHeader->Buffer)->ApiNumber; 613 614 /* Validate API call */ 615 if (MessageHeader->Length != sizeof(DBGKD_DEBUG_IO)) 616 return; 617 if ((ApiNumber != DbgKdPrintStringApi) && 618 (ApiNumber != DbgKdGetStringApi)) 619 { 620 return; 621 } 622 if (!MessageData) 623 return; 624 625 /* NOTE: MessageData->Length should be equal to 626 * DebugIo.u.PrintString.LengthOfString, or to 627 * DebugIo.u.GetString.LengthOfPromptString */ 628 629 if (!KdpDebugMode.Value) 630 return; 631 632 /* Print the string proper */ 633 KdIoPrintString(MessageData->Buffer, MessageData->Length); 634 return; 635 } 636 else if (PacketType == PACKET_TYPE_KD_STATE_CHANGE64) 637 { 638 PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange = (PDBGKD_ANY_WAIT_STATE_CHANGE)MessageHeader->Buffer; 639 if (WaitStateChange->NewState == DbgKdLoadSymbolsStateChange) 640 { 641 #ifdef KDBG 642 PLDR_DATA_TABLE_ENTRY LdrEntry; 643 /* Load symbols. Currently implemented only for KDBG! */ 644 if (KdbpSymFindModule((PVOID)(ULONG_PTR)WaitStateChange->u.LoadSymbols.BaseOfDll, -1, &LdrEntry)) 645 { 646 KdbSymProcessSymbols(LdrEntry, !WaitStateChange->u.LoadSymbols.UnloadSymbols); 647 } 648 #endif 649 return; 650 } 651 else if (WaitStateChange->NewState == DbgKdExceptionStateChange) 652 { 653 KdbgNextApiNumber = DbgKdGetContextApi; 654 KdbgExceptionRecord = WaitStateChange->u.Exception.ExceptionRecord; 655 KdbgFirstChanceException = WaitStateChange->u.Exception.FirstChance; 656 return; 657 } 658 } 659 else if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE) 660 { 661 PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer; 662 if (ManipulateState->ApiNumber == DbgKdGetContextApi) 663 { 664 KD_CONTINUE_TYPE Result; 665 666 #ifdef KDBG 667 /* Check if this is an assertion failure */ 668 if (KdbgExceptionRecord.ExceptionCode == STATUS_ASSERTION_FAILURE) 669 { 670 /* Bump EIP to the instruction following the int 2C */ 671 KeSetContextPc(&KdbgContext, KeGetContextPc(&KdbgContext) + 2); 672 } 673 674 Result = KdbEnterDebuggerException(&KdbgExceptionRecord, 675 KdbgContext.SegCs & 1, 676 &KdbgContext, 677 KdbgFirstChanceException); 678 #else 679 /* We'll manually dump the stack for the user... */ 680 KeRosDumpStackFrames(NULL, 0); 681 Result = kdHandleException; 682 #endif 683 if (Result != kdHandleException) 684 KdbgContinueStatus = STATUS_SUCCESS; 685 else 686 KdbgContinueStatus = STATUS_UNSUCCESSFUL; 687 KdbgNextApiNumber = DbgKdSetContextApi; 688 return; 689 } 690 else if (ManipulateState->ApiNumber == DbgKdSetContextApi) 691 { 692 KdbgNextApiNumber = DbgKdContinueApi; 693 return; 694 } 695 } 696 UNIMPLEMENTED; 697 } 698 699 KDSTATUS 700 NTAPI 701 KdReceivePacket( 702 _In_ ULONG PacketType, 703 _Out_ PSTRING MessageHeader, 704 _Out_ PSTRING MessageData, 705 _Out_ PULONG DataLength, 706 _Inout_ PKD_CONTEXT Context) 707 { 708 #ifdef KDBG 709 STRING ResponseString; 710 PDBGKD_DEBUG_IO DebugIo; 711 CHAR MessageBuffer[512]; 712 #endif 713 714 if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE) 715 { 716 PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer; 717 RtlZeroMemory(MessageHeader->Buffer, MessageHeader->MaximumLength); 718 if (KdbgNextApiNumber == DbgKdGetContextApi) 719 { 720 ManipulateState->ApiNumber = DbgKdGetContextApi; 721 MessageData->Length = 0; 722 MessageData->Buffer = (PCHAR)&KdbgContext; 723 return KdPacketReceived; 724 } 725 else if (KdbgNextApiNumber == DbgKdSetContextApi) 726 { 727 ManipulateState->ApiNumber = DbgKdSetContextApi; 728 MessageData->Length = sizeof(KdbgContext); 729 MessageData->Buffer = (PCHAR)&KdbgContext; 730 return KdPacketReceived; 731 } 732 else if (KdbgNextApiNumber != DbgKdContinueApi) 733 { 734 UNIMPLEMENTED; 735 } 736 ManipulateState->ApiNumber = DbgKdContinueApi; 737 ManipulateState->u.Continue.ContinueStatus = KdbgContinueStatus; 738 739 /* Prepare for next time */ 740 KdbgNextApiNumber = DbgKdContinueApi; 741 KdbgContinueStatus = STATUS_SUCCESS; 742 743 return KdPacketReceived; 744 } 745 746 if (PacketType != PACKET_TYPE_KD_DEBUG_IO) 747 return KdPacketTimedOut; 748 749 #ifdef KDBG 750 DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer; 751 752 /* Validate API call */ 753 if (MessageHeader->MaximumLength != sizeof(DBGKD_DEBUG_IO)) 754 return KdPacketNeedsResend; 755 if (DebugIo->ApiNumber != DbgKdGetStringApi) 756 return KdPacketNeedsResend; 757 758 /* NOTE: We cannot use directly MessageData->Buffer here as it points 759 * to the temporary KdpMessageBuffer scratch buffer that is being 760 * shared with all the possible I/O KD operations that may happen. */ 761 ResponseString.Buffer = MessageBuffer; 762 ResponseString.Length = 0; 763 ResponseString.MaximumLength = min(sizeof(MessageBuffer), 764 MessageData->MaximumLength); 765 ResponseString.MaximumLength = min(ResponseString.MaximumLength, 766 DebugIo->u.GetString.LengthOfStringRead); 767 768 /* The prompt string has been printed by KdSendPacket; go to 769 * new line and print the kdb prompt -- for SYSREG2 support. */ 770 KdIoPrintString("\n", 1); 771 KdIoPuts(KdbPromptStr.Buffer); // Alternatively, use "Input> " 772 773 if (!(KdbDebugState & KD_DEBUG_KDSERIAL)) 774 KbdDisableMouse(); 775 776 /* 777 * Read a NULL-terminated line of user input and retrieve its length. 778 * Official documentation states that DbgPrompt() includes a terminating 779 * newline character but does not NULL-terminate. However, experiments 780 * show that this behaviour is left at the discretion of WinDbg itself. 781 * WinDbg NULL-terminates the string unless its buffer is too short, 782 * in which case the string is simply truncated without NULL-termination. 783 */ 784 ResponseString.Length = 785 (USHORT)KdIoReadLine(ResponseString.Buffer, 786 ResponseString.MaximumLength); 787 788 if (!(KdbDebugState & KD_DEBUG_KDSERIAL)) 789 KbdEnableMouse(); 790 791 /* Adjust and return the string length */ 792 *DataLength = min(ResponseString.Length + sizeof(ANSI_NULL), 793 DebugIo->u.GetString.LengthOfStringRead); 794 MessageData->Length = DebugIo->u.GetString.LengthOfStringRead = *DataLength; 795 796 /* Only now we can copy back the data into MessageData->Buffer */ 797 RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, *DataLength); 798 #endif 799 800 return KdPacketReceived; 801 } 802 803 /* EOF */ 804