Reactos

[NTOS:KD] Supplement minimal handling in KdSend/ReceivePacket when no kernel debugger is present. CORE-20107

Improve the minimal handling done in the fall-back KdSend/ReceivePacket()
routines when they are invoked by KD64 (in Release build).

Part of my `kdbg_tests_kdio_split` branch for splitting kd/kdio.c
into a separate KD dll.

KdSendPacket:
- Silently ignore PACKET_TYPE_KD_STATE_CHANGE32/64 DbgKdLoadSymbolsStateChange notification.
- Partially manage and log the unhandled PACKET_TYPE_KD_STATE_CHANGE DbgKdExceptionStateChange notification.
- Log other unhandled PACKET_TYPE_KD_STATE_CHANGE32/64 and PACKET_TYPE_KD_STATE_MANIPULATE notifications.

When KdSendPacket receives the DbgKdExceptionStateChange notification,
it cannot handle it (no debugger is there!). However, we need to claim
the debugger to be present, so that its KD64 caller: KdpSendWaitContinue(),
can call back KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE), which,
in turn, informs KD that the exception cannot be handled, by returning
a failure code in the ManipulateState's ContinueStatus.

During bugchecks, this allows KiBugCheckDebugBreak() to not loop infinitely,
but instead fall back into calling HalHaltSystem() to halt the computer.

+74 -20
+74 -20
ntoskrnl/kd/kdio.c
··· 607 607 { 608 608 PDBGKD_DEBUG_IO DebugIo; 609 609 610 - if (PacketType != PACKET_TYPE_KD_DEBUG_IO) 610 + if (PacketType == PACKET_TYPE_KD_STATE_CHANGE32 || 611 + PacketType == PACKET_TYPE_KD_STATE_CHANGE64) 611 612 { 612 - #ifndef KDBG 613 - if (PacketType == PACKET_TYPE_KD_STATE_CHANGE64) 613 + PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange = (PDBGKD_ANY_WAIT_STATE_CHANGE)MessageHeader->Buffer; 614 + 615 + if (WaitStateChange->NewState == DbgKdLoadSymbolsStateChange) 616 + return; // Ignore: invoked anytime a new module is loaded. 617 + 618 + /* We should not get there, unless an exception has been raised */ 619 + if (WaitStateChange->NewState == DbgKdExceptionStateChange) 614 620 { 615 - // KdIoPrintf("%s: PacketType %d is ignored without KDBG\n", __FUNCTION__, PacketType); 621 + PEXCEPTION_RECORD64 ExceptionRecord = &WaitStateChange->u.Exception.ExceptionRecord; 622 + 623 + /* 624 + * Claim the debugger to be present, so that KdpSendWaitContinue() 625 + * can call back KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE), 626 + * which, in turn, informs KD that the exception cannot be handled. 627 + */ 628 + KD_DEBUGGER_NOT_PRESENT = FALSE; 629 + SharedUserData->KdDebuggerEnabled |= 0x00000002; 630 + 631 + KdIoPrintf("%s: Got exception 0x%08lx @ 0x%p, Flags 0x%08x, %s - Info[0]: 0x%p\n", 632 + __FUNCTION__, 633 + ExceptionRecord->ExceptionCode, 634 + (PVOID)(ULONG_PTR)ExceptionRecord->ExceptionAddress, 635 + ExceptionRecord->ExceptionFlags, 636 + WaitStateChange->u.Exception.FirstChance ? "FirstChance" : "LastChance", 637 + ExceptionRecord->ExceptionInformation[0]); 638 + #if defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64) 639 + extern VOID NTAPI RtlpBreakWithStatusInstruction(VOID); 640 + if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) && 641 + ((PVOID)(ULONG_PTR)ExceptionRecord->ExceptionAddress == (PVOID)RtlpBreakWithStatusInstruction)) 642 + { 643 + PCONTEXT ContextRecord = &KeGetCurrentPrcb()->ProcessorState.ContextFrame; 644 + ULONG Status = 645 + #if defined(_M_IX86) 646 + ContextRecord->Eax; 647 + #elif defined(_M_AMD64) 648 + (ULONG)ContextRecord->Rcx; 649 + #elif defined(_M_ARM) 650 + ContextRecord->R0; 651 + #else // defined(_M_ARM64) 652 + (ULONG)ContextRecord->X0; 653 + #endif 654 + KdIoPrintf("STATUS_BREAKPOINT Status 0x%08lx\n", Status); 655 + } 656 + // #else 657 + // #error Unknown architecture 658 + #endif 616 659 return; 617 660 } 618 - #endif 619 661 662 + KdIoPrintf("%s: PACKET_TYPE_KD_STATE_CHANGE32/64 NewState %d is UNIMPLEMENTED\n", 663 + __FUNCTION__, WaitStateChange->NewState); 664 + return; 665 + } 666 + else 667 + if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE) 668 + { 669 + PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer; 670 + KdIoPrintf("%s: PACKET_TYPE_KD_STATE_MANIPULATE for ApiNumber %lu\n", 671 + __FUNCTION__, ManipulateState->ApiNumber); 672 + return; 673 + } 674 + 675 + if (PacketType != PACKET_TYPE_KD_DEBUG_IO) 676 + { 620 677 KdIoPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType); 621 678 return; 622 679 } ··· 660 717 CHAR MessageBuffer[512]; 661 718 #endif 662 719 663 - #ifndef KDBG 664 - // Polling happens regularly, so check it first. 665 720 if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN) 666 721 { 667 - // KdIoPrintf("%s: PacketType %d is refused without KDBG\n", __FUNCTION__, PacketType); 722 + /* We don't support breaks-in */ 668 723 return KdPacketTimedOut; 669 724 } 670 - #endif 671 725 672 - if (PacketType != PACKET_TYPE_KD_DEBUG_IO) 726 + if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE) 673 727 { 674 - #ifndef KDBG 675 - if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE) 676 - { 677 - PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer; 728 + PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer; 729 + RtlZeroMemory(MessageHeader->Buffer, MessageHeader->MaximumLength); 678 730 679 - // KdIoPrintf("%s: PacketType %d is ignored without KDBG\n", __FUNCTION__, PacketType); 680 - ManipulateState->ApiNumber = DbgKdContinueApi; 681 - ManipulateState->u.Continue.ContinueStatus = STATUS_SUCCESS; 682 - return KdPacketReceived; 683 - } 684 - #endif 731 + /* The exception (notified via DbgKdExceptionStateChange in 732 + * KdSendPacket()) cannot be handled: return a failure code */ 733 + ManipulateState->ApiNumber = DbgKdContinueApi; 734 + ManipulateState->u.Continue.ContinueStatus = DBG_EXCEPTION_NOT_HANDLED; 735 + return KdPacketReceived; 736 + } 685 737 738 + if (PacketType != PACKET_TYPE_KD_DEBUG_IO) 739 + { 686 740 KdIoPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType); 687 741 return KdPacketTimedOut; 688 742 }