USHORT NTAPI KdpPrompt(IN LPSTR PromptString, IN USHORT PromptLength, OUT LPSTR ResponseString, IN USHORT MaximumResponseLength, IN KPROCESSOR_MODE PreviousMode, IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame) { STRING PromptBuffer, ResponseBuffer; BOOLEAN Enable, Resend; /* Normalize the lengths */ PromptLength = min(PromptLength, 512); MaximumResponseLength = min(MaximumResponseLength, 512); /* Check if we need to verify the string */ if (PreviousMode != KernelMode) { /* FIXME: Handle user-mode */ } /* Setup the prompt and response buffers */ PromptBuffer.Buffer = PromptString; PromptBuffer.Length = PromptLength; ResponseBuffer.Buffer = ResponseString; ResponseBuffer.Length = 0; ResponseBuffer.MaximumLength = MaximumResponseLength; /* Log the print */ //KdLogDbgPrint(&PromptBuffer); /* Enter the debugger */ Enable = KdEnterDebugger(TrapFrame, ExceptionFrame); /* Enter prompt loop */ do { /* Send the prompt and receive the response */ Resend = KdpPromptString(&PromptBuffer, &ResponseBuffer); /* Loop while we need to resend */ } while (Resend); /* Exit the debugger */ KdExitDebugger(Enable); /* Return the number of characters received */ return ResponseBuffer.Length; }
BOOLEAN KdpTrap ( IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN SecondChance ) /*++ Routine Description: This routine is called whenever a exception is dispatched and the kernel debugger is active. Arguments: TrapFrame - Supplies a pointer to a trap frame that describes the trap. ExceptionFrame - Supplies a pointer to a exception frame that describes the trap. ExceptionRecord - Supplies a pointer to an exception record that describes the exception. ContextRecord - Supplies the context at the time of the exception. PreviousMode - Supplies the previous processor mode. SecondChance - Supplies a boolean value that determines whether this is the second chance (TRUE) that the exception has been raised. Return Value: A value of TRUE is returned if the exception is handled. Otherwise a value of FALSE is returned. --*/ { BOOLEAN Completion; BOOLEAN Enable; BOOLEAN UnloadSymbols = FALSE; ULONG OldIar; STRING Input; STRING Output; PKPRCB Prcb; // // Synchronize processor execution, save processor state, enter debugger, // and flush the current TB. // re_enter_debugger: Enable = KdEnterDebugger(TrapFrame, ExceptionFrame); Prcb = KeGetCurrentPrcb(); KiSaveProcessorState(TrapFrame, ExceptionFrame); KeFlushCurrentTb(); // // If this is a breakpoint instruction, then check to determine if is // an internal command. // if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) && ((ExceptionRecord->ExceptionInformation[0] & BREAKPOINT_CODE_MASK) >= DEBUG_PRINT_BREAKPOINT)) { // // Switch on the breakpoint code. // switch (ExceptionRecord->ExceptionInformation[0] & BREAKPOINT_CODE_MASK) { // // Print a debug string. // // Arguments: // // a0 - Supplies a pointer to an output string buffer. // a1 - Supplies the length of the output string buffer. // case DEBUG_PRINT_BREAKPOINT: ContextRecord->Iar += 4; Output.Buffer = (PCHAR)ContextRecord->Gpr3; Output.Length = (USHORT)ContextRecord->Gpr4; if (KdDebuggerNotPresent == FALSE) { if (KdpPrintString(&Output)) { ContextRecord->Gpr3 = (ULONG)STATUS_BREAKPOINT; } else { ContextRecord->Gpr3 = (ULONG)STATUS_SUCCESS; } } else { ContextRecord->Gpr3 = (ULONG)STATUS_DEVICE_NOT_CONNECTED; } KiRestoreProcessorState(TrapFrame, ExceptionFrame); KdExitDebugger(Enable); return TRUE; // // Print a debug prompt string, then input a string. // // r.3 - Supplies a pointer to an output string buffer. // r.4 - Supplies the length of the output string buffer.. // r.5 - supplies a pointer to an input string buffer. // r.6 - Supplies the length of the input string bufffer. // case DEBUG_PROMPT_BREAKPOINT: ContextRecord->Iar += 4; Output.Buffer = (PCHAR)ContextRecord->Gpr3; Output.Length = (USHORT)ContextRecord->Gpr4; Input.Buffer = (PCHAR)ContextRecord->Gpr5; Input.MaximumLength = (USHORT)ContextRecord->Gpr6; KdpPromptString(&Output, &Input); ContextRecord->Gpr3 = Input.Length; KiRestoreProcessorState(TrapFrame, ExceptionFrame); KdExitDebugger(Enable); return TRUE; // // Load the symbolic information for an image. // // Arguments: // // r.3 - Supplies a pointer to an output string descriptor. // r.4 - Supplies a the base address of the image. // case DEBUG_UNLOAD_SYMBOLS_BREAKPOINT: UnloadSymbols = TRUE; // // Fall through // case DEBUG_LOAD_SYMBOLS_BREAKPOINT: OldIar = ContextRecord->Iar; if (KdDebuggerNotPresent == FALSE) { KdpReportLoadSymbolsStateChange((PSTRING)ContextRecord->Gpr3, (PKD_SYMBOLS_INFO) ContextRecord->Gpr4, UnloadSymbols, &Prcb->ProcessorState.ContextFrame); } RtlCopyMemory(ContextRecord, &Prcb->ProcessorState.ContextFrame, sizeof(CONTEXT)); KiRestoreProcessorState(TrapFrame, ExceptionFrame); KdExitDebugger(Enable); // // If the kernel debugger did not update the IAR, then increment // past the breakpoint instruction. // if (ContextRecord->Iar == OldIar) { ContextRecord->Iar += 4; } return TRUE; // // Unknown internal command. // default: break; } } // // Report state change to kernel debugger on host machine. // Completion = KdpReportExceptionStateChange( ExceptionRecord, &Prcb->ProcessorState.ContextFrame, SecondChance); RtlCopyMemory(ContextRecord, &Prcb->ProcessorState.ContextFrame, sizeof(CONTEXT)); KiRestoreProcessorState(TrapFrame, ExceptionFrame); KdExitDebugger(Enable); // // check to see if the user of the remote debugger // requested memory to be paged in // if (KdpPageInAddress) { if (KeGetCurrentIrql() <= APC_LEVEL) { // // if the IQRL is below DPC level then cause // the page fault to occur and then re-enter // the debugger. this whole process is transparent // to the user. // KdpPageInData( (PUCHAR)KdpPageInAddress ); KdpPageInAddress = 0; KdpControlCPending = FALSE; goto re_enter_debugger; } else { // // we cannot take a page fault // here so a worker item is queued to take the // page fault. after the worker item takes the // page fault it sets the contol-c flag so that // the user re-enters the debugger just as if // control-c was pressed. // if (KdpControlCPressed) { ExInitializeWorkItem( &KdpPageInWorkItem, (PWORKER_THREAD_ROUTINE) KdpPageInData, (PVOID) KdpPageInAddress ); ExQueueWorkItem( &KdpPageInWorkItem, DelayedWorkQueue ); KdpPageInAddress = 0; } } } KdpControlCPressed = FALSE; return Completion; }
BOOLEAN KdpTrap ( IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN SecondChance ) /*++ Routine Description: This routine is called whenever a exception is dispatched and the kernel debugger is active. Arguments: TrapFrame - Supplies a pointer to a trap frame that describes the trap. ExceptionFrame - Supplies a pointer to a exception frame that describes the trap. ExceptionRecord - Supplies a pointer to an exception record that describes the exception. ContextRecord - Supplies the context at the time of the exception. PreviousMode - Supplies the previous processor mode. SecondChance - Supplies a boolean value that determines whether this is the second chance (TRUE) that the exception has been raised. Return Value: A value of TRUE is returned if the exception is handled. Otherwise a value of FALSE is returned. --*/ { BOOLEAN Completion; BOOLEAN Enable; BOOLEAN UnloadSymbols = FALSE; STRING Input; ULONGLONG OldFir; STRING Output; PKPRCB Prcb; // // Enter debugger and synchronize processor execution. // // // If this is a breakpoint instruction, then check to determine if is // an internal command. // if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) && (ExceptionRecord->ExceptionInformation[0] >= DEBUG_PRINT_BREAKPOINT)){ // // Switch on the breakpoint code. // switch (ExceptionRecord->ExceptionInformation[0]) { // // Print a debug string. // // Arguments: // // a0 - Supplies a pointer to an output string buffer. // a1 - Supplies the length of the output string buffer. // case DEBUG_PRINT_BREAKPOINT: ContextRecord->Fir += 4; Output.Buffer = (PCHAR)ContextRecord->IntA0; Output.Length = (USHORT)ContextRecord->IntA1; KdLogDbgPrint(&Output); if (KdDebuggerNotPresent == FALSE) { Enable = KdEnterDebugger(TrapFrame, ExceptionFrame); if (KdpPrintString(&Output)) { ContextRecord->IntV0 = (ULONG)STATUS_BREAKPOINT; } else { ContextRecord->IntV0 = (ULONG)STATUS_SUCCESS; } KdExitDebugger(Enable); } else { ContextRecord->IntV0 = (ULONG)STATUS_DEVICE_NOT_CONNECTED; } return TRUE; // // Stop in the debugger // // As this is not a normal breakpoint we must increment the // context past the breakpoint instruction // case BREAKIN_BREAKPOINT: ContextRecord->Fir += 4; break; // // Print a debug prompt string, then input a string. // // a0 - Supplies a pointer to an output string buffer. // a1 - Supplies the length of the output string buffer.. // a2 - supplies a pointer to an input string buffer. // a3 - Supplies the length of the input string bufffer. // case DEBUG_PROMPT_BREAKPOINT: ContextRecord->Fir += 4; Output.Buffer = (PCHAR)ContextRecord->IntA0; Output.Length = (USHORT)ContextRecord->IntA1; Input.Buffer = (PCHAR)ContextRecord->IntA2; Input.MaximumLength = (USHORT)ContextRecord->IntA3; KdLogDbgPrint(&Output); Enable = KdEnterDebugger(TrapFrame, ExceptionFrame); KdpPromptString(&Output, &Input); ContextRecord->IntV0 = Input.Length; KdExitDebugger(Enable); return TRUE; // // Load the symbolic information for an image. // // Arguments: // // a0 - Supplies a pointer to an output string descriptor. // a1 - Supplies a the base address of the image. // a2 - Supplies the current process id. // case DEBUG_UNLOAD_SYMBOLS_BREAKPOINT: UnloadSymbols = TRUE; // // Fall through // case DEBUG_LOAD_SYMBOLS_BREAKPOINT: Enable = KdEnterDebugger(TrapFrame, ExceptionFrame); Prcb = KeGetCurrentPrcb(); OldFir = ContextRecord->Fir; RtlCopyMemory(&Prcb->ProcessorState.ContextFrame, ContextRecord, sizeof(CONTEXT)); if (KdDebuggerNotPresent == FALSE) { KdpReportLoadSymbolsStateChange((PSTRING)ContextRecord->IntA0, (PKD_SYMBOLS_INFO) ContextRecord->IntA1, UnloadSymbols, &Prcb->ProcessorState.ContextFrame); } RtlCopyMemory(ContextRecord, &Prcb->ProcessorState.ContextFrame, sizeof(CONTEXT)); KdExitDebugger(Enable); // // If the kernel debugger did not update the FIR, then increment // past the breakpoint instruction. // if (ContextRecord->Fir == OldFir) { ContextRecord->Fir += 4; } return TRUE; // // Unknown internal command. // default: break; } } // // Report state change to kernel debugger on host machine. // Enable = KdEnterDebugger(TrapFrame, ExceptionFrame); Prcb = KeGetCurrentPrcb(); RtlCopyMemory(&Prcb->ProcessorState.ContextFrame, ContextRecord, sizeof (CONTEXT)); Completion = KdpReportExceptionStateChange(ExceptionRecord, &Prcb->ProcessorState.ContextFrame, SecondChance); RtlCopyMemory(ContextRecord, &Prcb->ProcessorState.ContextFrame, sizeof(CONTEXT)); KdExitDebugger(Enable); KdpControlCPressed = FALSE; // // Always return TRUE if this is the first chance to handle the // exception. Otherwise, return the completion status of the // state change reporting. // if( SecondChance ){ return Completion; } else { return TRUE; } }