412 lines
9.9 KiB
C
412 lines
9.9 KiB
C
/*++
|
||
|
||
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;
|
||
}
|