/*++ Copyright (c) 1996 Microsoft Corporation Module Name: bdtrap.c Abstract: This module contains code to implement the target side of the boot debugger. Author: David N. Cutler (davec) 30-Nov-96 Revision History: --*/ #include "bd.h" // // Define forward referenced function prototypes. // VOID BdRestoreKframe( IN OUT PKTRAP_FRAME TrapFrame, IN PCONTEXT ContextRecord ); VOID BdSaveKframe( IN PKTRAP_FRAME TrapFrame, IN OUT PCONTEXT ContextRecord ); LOGICAL BdTrap ( IN PEXCEPTION_RECORD ExceptionRecord, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: This routine is called whenever a exception is dispatched and the boot debugger is active. Arguments: ExceptionRecord - Supplies a pointer to an exception record that describes the exception. ExceptionFrame - Supplies a pointer to an exception frame (NULL). TrapFrame - Supplies a pointer to a trap frame that describes the trap. Return Value: A value of TRUE is returned if the exception is handled. Otherwise a value of FALSE is returned. --*/ { LOGICAL Completion; PCONTEXT ContextRecord; ULONG OldEip; STRING Input; STRING Output; PKD_SYMBOLS_INFO SymbolInfo; LOGICAL UnloadSymbols; // // Set address of context record and set context flags. // ContextRecord = &BdPrcb.ProcessorState.ContextFrame; ContextRecord->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; // // Print, prompt, load symbols, and unload symbols are all special cases // of STATUS_BREAKPOINT. // if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) && (ExceptionRecord->ExceptionInformation[0] != BREAKPOINT_BREAK)) { // // Switch on the request type. // UnloadSymbols = FALSE; switch (ExceptionRecord->ExceptionInformation[0]) { // // Print: // // ExceptionInformation[1] is a PSTRING which describes the string // to print. // case BREAKPOINT_PRINT: Output.Buffer = (PCHAR)ExceptionRecord->ExceptionInformation[1]; Output.Length = (USHORT)ExceptionRecord->ExceptionInformation[2]; if (BdDebuggerNotPresent == FALSE) { if (BdPrintString(&Output)) { TrapFrame->Eax = (ULONG)(STATUS_BREAKPOINT); } else { TrapFrame->Eax = STATUS_SUCCESS; } } else { TrapFrame->Eax = (ULONG)STATUS_DEVICE_NOT_CONNECTED; } TrapFrame->Eip += 1; return TRUE; // // Prompt: // // ExceptionInformation[1] is a PSTRING which describes the prompt // string, // // ExceptionInformation[2] is a PSTRING that describes the return // string. // case BREAKPOINT_PROMPT: Output.Buffer = (PCHAR)ExceptionRecord->ExceptionInformation[1]; Output.Length = (USHORT)ExceptionRecord->ExceptionInformation[2]; Input.Buffer = (PCHAR)TrapFrame->Ebx;; Input.MaximumLength = (USHORT)TrapFrame->Edi; // // Prompt and keep prompting until no breakin seen. // do { } while (BdPromptString(&Output, &Input) != FALSE); TrapFrame->Eax = Input.Length; TrapFrame->Eip += 1; return TRUE; // // Unload symbols: // // ExceptionInformation[1] is file name of a module. // ExceptionInformaiton[2] is the base of the dll. // case BREAKPOINT_UNLOAD_SYMBOLS: UnloadSymbols = TRUE; // // Fall through to load symbols case. // case BREAKPOINT_LOAD_SYMBOLS: BdSaveKframe(TrapFrame, ContextRecord); OldEip = ContextRecord->Eip; SymbolInfo = (PKD_SYMBOLS_INFO)ExceptionRecord->ExceptionInformation[2]; if (BdDebuggerNotPresent == FALSE) { BdReportLoadSymbolsStateChange((PSTRING)ExceptionRecord->ExceptionInformation[1], SymbolInfo, UnloadSymbols, ContextRecord); } // // If the kernel debugger did not update EIP, then increment // past the breakpoint instruction. // if (ContextRecord->Eip == OldEip) { ContextRecord->Eip += 1; } BdRestoreKframe(TrapFrame, ContextRecord); return TRUE; // // Unknown command // default: return FALSE; } } else { // // Report state change to kernel debugger on host. // BdSaveKframe(TrapFrame, ContextRecord); Completion = BdReportExceptionStateChange(ExceptionRecord, &BdPrcb.ProcessorState.ContextFrame); BdRestoreKframe(TrapFrame, ContextRecord); BdControlCPressed = FALSE; return TRUE; } } LOGICAL BdStub ( IN PEXCEPTION_RECORD ExceptionRecord, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: This routine provides a kernel debugger stub routine to catch debug prints when the boot debugger is not active. Arguments: ExceptionRecord - Supplies a pointer to an exception record that describes the exception. ExceptionFrame - Supplies a pointer to an exception frame (NULL). TrapFrame - Supplies a pointer to a trap frame that describes the trap. Return Value: A value of TRUE is returned if the exception is handled. Otherwise a value of FALSE is returned. --*/ { // // If the exception is a breakpoint and the function is a load symbols, // unload symbols, or a print, then return TRUE. Otherwise, return FALSE. // if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) && (ExceptionRecord->NumberParameters > 0) && ((ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_LOAD_SYMBOLS) || (ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_UNLOAD_SYMBOLS) || (ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_PRINT))) { TrapFrame->Eip += 1; return TRUE; } else { return FALSE; } } VOID BdRestoreKframe( IN OUT PKTRAP_FRAME TrapFrame, IN PCONTEXT ContextRecord ) /*++ Routine Description: This functions copie the processor state from a context record and the processor control block into the trap frame. Arguments: TrapFrame - Supplies a pointer to a trap frame. ContextRecord - Supplies a pointer to a context record. Return Value: None. --*/ { // // Copy information from context record to trap frame. // // Copy control information. // TrapFrame->Ebp = ContextRecord->Ebp; TrapFrame->Eip = ContextRecord->Eip; TrapFrame->SegCs = ContextRecord->SegCs; TrapFrame->EFlags = ContextRecord->EFlags; // // Copy segment register contents. // TrapFrame->SegDs = ContextRecord->SegDs; TrapFrame->SegEs = ContextRecord->SegEs; TrapFrame->SegFs = ContextRecord->SegFs; TrapFrame->SegGs = ContextRecord->SegGs; // // Copy integer registers contents. // TrapFrame->Edi = ContextRecord->Edi; TrapFrame->Esi = ContextRecord->Esi; TrapFrame->Ebx = ContextRecord->Ebx; TrapFrame->Ecx = ContextRecord->Ecx; TrapFrame->Edx = ContextRecord->Edx; TrapFrame->Eax = ContextRecord->Eax; // // Restore processor state. // KiRestoreProcessorControlState(&BdPrcb.ProcessorState); return; } VOID BdSaveKframe( IN PKTRAP_FRAME TrapFrame, IN OUT PCONTEXT ContextRecord ) /*++ Routine Description: This functions copis the processor state from a trap frame and the processor control block into a context record. Arguments: TrapFrame - Supplies a pointer to a trap frame. ContextRecord - Supplies a pointer to a context record. Return Value: None. --*/ { // // Copy information from trap frame to context record. // // Copy control information. // ContextRecord->Ebp = TrapFrame->Ebp; ContextRecord->Eip = TrapFrame->Eip; ContextRecord->SegCs = TrapFrame->SegCs & SEGMENT_MASK; ContextRecord->EFlags = TrapFrame->EFlags; ContextRecord->Esp = TrapFrame->TempEsp; ContextRecord->SegSs = TrapFrame->TempSegCs; // // Copy segment register contents. // ContextRecord->SegDs = TrapFrame->SegDs & SEGMENT_MASK; ContextRecord->SegEs = TrapFrame->SegEs & SEGMENT_MASK; ContextRecord->SegFs = TrapFrame->SegFs & SEGMENT_MASK; ContextRecord->SegGs = TrapFrame->SegGs & SEGMENT_MASK; // // Copy the integer register contents. // ContextRecord->Eax = TrapFrame->Eax; ContextRecord->Ebx = TrapFrame->Ebx; ContextRecord->Ecx = TrapFrame->Ecx; ContextRecord->Edx = TrapFrame->Edx; ContextRecord->Edi = TrapFrame->Edi; ContextRecord->Esi = TrapFrame->Esi; // // Copy debug register contents. // ContextRecord->Dr0 = TrapFrame->Dr0; ContextRecord->Dr1 = TrapFrame->Dr1; ContextRecord->Dr2 = TrapFrame->Dr2; ContextRecord->Dr3 = TrapFrame->Dr3; ContextRecord->Dr6 = TrapFrame->Dr6; ContextRecord->Dr7 = TrapFrame->Dr7; // // Save processor control state. // KiSaveProcessorControlState(&BdPrcb.ProcessorState); return; }