blob: e0b85c70eff52857fc2460b4db4da141066e3982 [file] [log] [blame]
/*++
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Ebc.c
Abstract:
--*/
#include <Uefi.h>
#include "Edb.h"
EFI_DEBUGGER_PRIVATE_DATA mDebuggerPrivate = {
EFI_DEBUGGER_SIGNATURE, // Signature
IsaEbc, // Isa
(EBC_DEBUGGER_MAJOR_VERSION << 16) |
EBC_DEBUGGER_MINOR_VERSION, // EfiDebuggerRevision
(VM_MAJOR_VERSION << 16) |
VM_MINOR_VERSION, // EbcVmRevision
NULL, // DebugImageInfoTableHeader
NULL, // Vol
NULL, // PciRootBridgeIo
mDebuggerCommandSet, // DebuggerCommandSet
{0}, // DebuggerSymbolContext
0, // DebuggerBreakpointCount
{{0}}, // DebuggerBreakpointContext
0, // CallStackEntryCount
{{0}}, // CallStackEntry
0, // TraceEntryCount
{{0}}, // TraceEntry
{0}, // StepContext
{0}, // GoTilContext
0, // InstructionScope
EFI_DEBUG_DEFAULT_INSTRUCTION_NUMBER, // InstructionNumber
EFI_DEBUG_FLAG_EBC_BOE | EFI_DEBUG_FLAG_EBC_BOT, // FeatureFlags
0, // StatusFlags
FALSE, // EnablePageBreak
NULL // BreakEvent
};
CHAR16 *mExceptionStr[] = {
L"EXCEPT_EBC_UNDEFINED",
L"EXCEPT_EBC_DIVIDE_ERROR",
L"EXCEPT_EBC_DEBUG",
L"EXCEPT_EBC_BREAKPOINT",
L"EXCEPT_EBC_OVERFLOW",
L"EXCEPT_EBC_INVALID_OPCODE",
L"EXCEPT_EBC_STACK_FAULT",
L"EXCEPT_EBC_ALIGNMENT_CHECK",
L"EXCEPT_EBC_INSTRUCTION_ENCODING",
L"EXCEPT_EBC_BAD_BREAK",
L"EXCEPT_EBC_SINGLE_STEP",
};
VOID
EdbClearAllBreakpoint (
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
IN BOOLEAN NeedRemove
)
/*++
Routine Description:
Clear all the breakpoint
Arguments:
DebuggerPrivate - EBC Debugger private data structure
NeedRemove - Whether need to remove all the breakpoint
Returns:
None
--*/
{
UINTN Index;
//
// Patch all the breakpoint
//
for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
if (DebuggerPrivate->DebuggerBreakpointContext[Index].State) {
CopyMem (
(VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress,
&DebuggerPrivate->DebuggerBreakpointContext[Index].OldInstruction,
sizeof(UINT16)
);
}
}
//
// Zero Breakpoint context, if need to remove all breakpoint
//
if (NeedRemove) {
DebuggerPrivate->DebuggerBreakpointCount = 0;
ZeroMem (DebuggerPrivate->DebuggerBreakpointContext, sizeof(DebuggerPrivate->DebuggerBreakpointContext));
}
//
// Done
//
return ;
}
VOID
EdbSetAllBreakpoint (
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
)
/*++
Routine Description:
Set all the breakpoint
Arguments:
DebuggerPrivate - EBC Debugger private data structure
Returns:
None
--*/
{
UINTN Index;
UINT16 Data16;
//
// Set all the breakpoint (BREAK(3) : 0x0300)
//
Data16 = 0x0300;
for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
if (DebuggerPrivate->DebuggerBreakpointContext[Index].State) {
CopyMem (
(VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress,
&Data16,
sizeof(UINT16)
);
}
}
//
// Check if current break is caused by breakpoint set.
// If so, we need to patch memory back to let user see the real memory.
//
if (DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].BreakpointAddress != 0) {
CopyMem (
(VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].BreakpointAddress,
&DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].OldInstruction,
sizeof(UINT16)
);
DebuggerPrivate->StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_BP;
}
//
// Done
//
return ;
}
VOID
EdbCheckBreakpoint (
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
IN EFI_SYSTEM_CONTEXT SystemContext
)
/*++
Routine Description:
Check all the breakpoint, if match, then set status flag, and record current breakpoint.
Then clear all breakpoint to let user see a clean memory
Arguments:
DebuggerPrivate - EBC Debugger private data structure
SystemContext - EBC system context.
Returns:
None
--*/
{
UINT64 Address;
UINTN Index;
UINT16 OldInstruction;
BOOLEAN IsHitBreakpoint;
//
// Roll back IP for breakpoint instruction (BREAK(3) : 0x0300)
//
Address = SystemContext.SystemContextEbc->Ip - sizeof(UINT16);
//
// Check if the breakpoint is hit
//
IsHitBreakpoint = FALSE;
for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
if ((DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress == Address) &&
(DebuggerPrivate->DebuggerBreakpointContext[Index].State)) {
OldInstruction = (UINT16)DebuggerPrivate->DebuggerBreakpointContext[Index].OldInstruction;
IsHitBreakpoint = TRUE;
break;
}
}
if (IsHitBreakpoint) {
//
// If hit, record current breakpoint
//
DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX] = DebuggerPrivate->DebuggerBreakpointContext[Index];
DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].State = TRUE;
//
// Update: IP and Instruction (NOTE: Since we not allow set breakpoint to BREAK 3, this update is safe)
//
SystemContext.SystemContextEbc->Ip = Address;
//
// Set Flags
//
DebuggerPrivate->StatusFlags |= EFI_DEBUG_FLAG_EBC_BP;
} else {
//
// If not hit, check whether current IP is in breakpoint list,
// because STEP will be triggered before execute the instruction.
// We should not patch it in de-init.
//
Address = SystemContext.SystemContextEbc->Ip;
//
// Check if the breakpoint is hit
//
IsHitBreakpoint = FALSE;
for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
if ((DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress == Address) &&
(DebuggerPrivate->DebuggerBreakpointContext[Index].State)) {
OldInstruction = (UINT16)DebuggerPrivate->DebuggerBreakpointContext[Index].OldInstruction;
IsHitBreakpoint = TRUE;
break;
}
}
if (IsHitBreakpoint) {
//
// If hit, record current breakpoint
//
DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX] = DebuggerPrivate->DebuggerBreakpointContext[Index];
DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].State = TRUE;
//
// Do not set Breakpoint flag. We record the address here just let it not patch breakpoint address when de-init.
//
} else {
//
// Zero current breakpoint
//
ZeroMem (
&DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX],
sizeof(DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX])
);
}
}
//
// Done
//
return ;
}
VOID
EdbClearSymbol (
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
)
/*++
Routine Description:
clear all the symbol
Arguments:
DebuggerPrivate - EBC Debugger private data structure
Returns:
None
--*/
{
EFI_DEBUGGER_SYMBOL_CONTEXT *DebuggerSymbolContext;
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
UINTN ObjectIndex;
UINTN Index;
//
// Go throuth each object
//
DebuggerSymbolContext = &DebuggerPrivate->DebuggerSymbolContext;
for (ObjectIndex = 0; ObjectIndex < DebuggerSymbolContext->ObjectCount; ObjectIndex++) {
Object = &DebuggerSymbolContext->Object[ObjectIndex];
//
// Go throuth each entry
//
for (Index = 0; Index < Object->EntryCount; Index++) {
ZeroMem (&Object->Entry[Index], sizeof(Object->Entry[Index]));
}
ZeroMem (Object->Name, sizeof(Object->Name));
Object->EntryCount = 0;
Object->BaseAddress = 0;
Object->StartEntrypointRVA = 0;
Object->MainEntrypointRVA = 0;
//
// Free source buffer
//
for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
gBS->FreePool (Object->SourceBuffer[Index]);
Object->SourceBuffer[Index] = NULL;
}
}
DebuggerSymbolContext->ObjectCount = 0;
return ;
}
EFI_STATUS
InitDebuggerPrivateData (
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_SYSTEM_CONTEXT SystemContext,
IN BOOLEAN Initialized
)
/*++
Routine Description:
Initialize Debugger private data structure
Arguments:
DebuggerPrivate - EBC Debugger private data structure
InterruptType - Interrupt type.
SystemContext - EBC system context.
Initialized - Whether the DebuggerPrivate data is initialized.
Returns:
None
--*/
{
//
// clear STEP flag in any condition.
//
if (SystemContext.SystemContextEbc->Flags & VMFLAGS_STEP) {
SystemContext.SystemContextEbc->Flags &= ~VMFLAGS_STEP;
}
if (!Initialized) {
//
// Initialize everything
//
DebuggerPrivate->InstructionNumber = EFI_DEBUG_DEFAULT_INSTRUCTION_NUMBER;
DebuggerPrivate->DebuggerBreakpointCount = 0;
ZeroMem (DebuggerPrivate->DebuggerBreakpointContext, sizeof(DebuggerPrivate->DebuggerBreakpointContext));
// DebuggerPrivate->StatusFlags = 0;
DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = TRUE;
DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = FALSE;
DebuggerPrivate->DebuggerSymbolContext.ObjectCount = 0;
} else {
//
// Already initialized, just check Breakpoint here.
//
if (ExceptionType == EXCEPT_EBC_BREAKPOINT) {
EdbCheckBreakpoint (DebuggerPrivate, SystemContext);
}
//
// Clear all breakpoint
//
EdbClearAllBreakpoint (DebuggerPrivate, FALSE);
}
//
// Set Scope to currentl IP. (Note: Check Breakpoint may change Ip)
//
DebuggerPrivate->InstructionScope = SystemContext.SystemContextEbc->Ip;
//
// Done
//
return EFI_SUCCESS;
}
EFI_STATUS
DeinitDebuggerPrivateData (
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_SYSTEM_CONTEXT SystemContext,
IN BOOLEAN Initialized
)
/*++
Routine Description:
De-initialize Debugger private data structure
Arguments:
DebuggerPrivate - EBC Debugger private data structure
InterruptType - Interrupt type.
SystemContext - EBC system context.
Initialized - Whether the DebuggerPrivate data is initialized.
Returns:
None
--*/
{
if (!Initialized) {
//
// If it does not want initialized state, de-init everything
//
DebuggerPrivate->FeatureFlags = EFI_DEBUG_FLAG_EBC_BOE | EFI_DEBUG_FLAG_EBC_BOT;
DebuggerPrivate->CallStackEntryCount = 0;
DebuggerPrivate->TraceEntryCount = 0;
ZeroMem (DebuggerPrivate->CallStackEntry, sizeof(DebuggerPrivate->CallStackEntry));
ZeroMem (DebuggerPrivate->TraceEntry, sizeof(DebuggerPrivate->TraceEntry));
//
// Clear all breakpoint
//
EdbClearAllBreakpoint (DebuggerPrivate, TRUE);
//
// Clear symbol
//
EdbClearSymbol (DebuggerPrivate);
} else {
//
// If it wants to keep initialized state, just set breakpoint.
//
EdbSetAllBreakpoint (DebuggerPrivate);
}
//
// Clear Step context
//
ZeroMem (&mDebuggerPrivate.StepContext, sizeof(mDebuggerPrivate.StepContext));
DebuggerPrivate->StatusFlags = 0;
//
// Done
//
return EFI_SUCCESS;
}
VOID
PrintExceptionReason (
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_SYSTEM_CONTEXT SystemContext,
IN BOOLEAN Initialized
)
/*++
Routine Description:
Print the reason of current break to EbcDebugger.
Arguments:
DebuggerPrivate - EBC Debugger private data structure
InterruptType - Interrupt type.
SystemContext - EBC system context.
Initialized - Whether the DebuggerPrivate data is initialized.
Returns:
None
--*/
{
//
// Print break status
//
if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_GT) == EFI_DEBUG_FLAG_EBC_GT) {
EDBPrint (L"Break on GoTil\n");
} else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOC) == EFI_DEBUG_FLAG_EBC_BOC) {
EDBPrint (L"Break on CALL\n");
} else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOCX) == EFI_DEBUG_FLAG_EBC_BOCX) {
EDBPrint (L"Break on CALLEX\n");
} else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOR) == EFI_DEBUG_FLAG_EBC_BOR) {
EDBPrint (L"Break on RET\n");
} else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOE) == EFI_DEBUG_FLAG_EBC_BOE) {
EDBPrint (L"Break on Entrypoint\n");
} else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOT) == EFI_DEBUG_FLAG_EBC_BOT) {
EDBPrint (L"Break on Thunk\n");
} else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_STEPOVER) == EFI_DEBUG_FLAG_EBC_STEPOVER) {
EDBPrint (L"Break on StepOver\n");
} else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_STEPOUT) == EFI_DEBUG_FLAG_EBC_STEPOUT) {
EDBPrint (L"Break on StepOut\n");
} else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BP) == EFI_DEBUG_FLAG_EBC_BP) {
EDBPrint (L"Break on Breakpoint\n");
} else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOK) == EFI_DEBUG_FLAG_EBC_BOK) {
EDBPrint (L"Break on Key\n");
} else {
EDBPrint (L"Exception Type - %x", (UINTN)ExceptionType);
if ((ExceptionType >= EXCEPT_EBC_UNDEFINED) && (ExceptionType <= EXCEPT_EBC_STEP)) {
EDBPrint (L" (%s)\n", mExceptionStr[ExceptionType]);
} else {
EDBPrint (L"\n");
}
}
return ;
}
VOID
EFIAPI
EdbExceptionHandler (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN OUT EFI_SYSTEM_CONTEXT SystemContext
)
/*++
Routine Description:
The default Exception Callback for the VM interpreter.
In this function, we report status code, and print debug information
about EBC_CONTEXT, then dead loop.
Arguments:
InterruptType - Interrupt type.
SystemContext - EBC system context.
Returns:
None
--*/
{
CHAR16 InputBuffer[EFI_DEBUG_INPUS_BUFFER_SIZE];
CHAR16 *CommandArg;
EFI_DEBUGGER_COMMAND DebuggerCommand;
EFI_DEBUG_STATUS DebugStatus;
STATIC BOOLEAN mInitialized = FALSE;
DEBUG ((DEBUG_ERROR, "Hello EBC Debugger!\n"));
if (!mInitialized) {
//
// Print version
//
EDBPrint (
L"EBC Interpreter Version - %d.%d\n",
(UINTN)VM_MAJOR_VERSION,
(UINTN)VM_MINOR_VERSION
);
EDBPrint (
L"EBC Debugger Version - %d.%d\n",
(UINTN)EBC_DEBUGGER_MAJOR_VERSION,
(UINTN)EBC_DEBUGGER_MINOR_VERSION
);
}
//
// Init Private Data
//
InitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
//
// EDBPrint basic info
//
PrintExceptionReason (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
EdbShowDisasm (&mDebuggerPrivate, SystemContext);
// EFI_BREAKPOINT ();
if (!mInitialized) {
//
// Interactive with user
//
EDBPrint (L"\nPlease enter command now, \'h\' for help.\n");
EDBPrint (L"(Using <Command> -b <...> to enable page break.)\n");
}
mInitialized = TRUE;
//
// Dispatch each command
//
while (TRUE) {
//
// Get user input
//
Input (L"\n\r" EFI_DEBUG_PROMPT_STRING, InputBuffer, EFI_DEBUG_INPUS_BUFFER_SIZE);
EDBPrint (L"\n");
//
// Get command
//
DebuggerCommand = MatchDebuggerCommand (InputBuffer, &CommandArg);
if (DebuggerCommand == NULL) {
EDBPrint (L"ERROR: Command not found!\n");
continue;
}
//
// Check PageBreak;
//
if (CommandArg != NULL) {
if (StriCmp (CommandArg, L"-b") == 0) {
CommandArg = StrGetNextTokenLine (L" ");
mDebuggerPrivate.EnablePageBreak = TRUE;
}
}
//
// Dispatch command
//
DebugStatus = DebuggerCommand (CommandArg, &mDebuggerPrivate, ExceptionType, SystemContext);
mDebuggerPrivate.EnablePageBreak = FALSE;
//
// Check command return status
//
if (DebugStatus == EFI_DEBUG_RETURN) {
mInitialized = FALSE;
break;
} else if (DebugStatus == EFI_DEBUG_BREAK) {
break;
} else if (DebugStatus == EFI_DEBUG_CONTINUE) {
continue;
} else {
ASSERT (FALSE);
}
}
//
// Deinit Private Data
//
DeinitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
DEBUG ((DEBUG_ERROR, "Goodbye EBC Debugger!\n"));
return;
}