mirror of https://github.com/acidanthera/audk.git
840 lines
21 KiB
C
840 lines
21 KiB
C
/** @file
|
|
|
|
Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
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.
|
|
|
|
|
|
**/
|
|
|
|
#include "Edb.h"
|
|
|
|
/**
|
|
|
|
Check the Hook flag, and trigger exception if match.
|
|
|
|
@param VmPtr - EbcDebuggerCheckHookFlag
|
|
@param Flag - Feature flag
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerCheckHookFlag (
|
|
IN VM_CONTEXT *VmPtr,
|
|
IN UINT32 Flag
|
|
)
|
|
{
|
|
if ((mDebuggerPrivate.FeatureFlags & Flag) == Flag) {
|
|
mDebuggerPrivate.StatusFlags = Flag;
|
|
EbcDebugSignalException (
|
|
EXCEPT_EBC_BREAKPOINT,
|
|
EXCEPTION_FLAG_NONE,
|
|
VmPtr
|
|
);
|
|
}
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
It will record soruce address for Callstack entry.
|
|
|
|
@param SourceEntry - Source address
|
|
@param Type - Branch type
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerPushCallstackSource (
|
|
IN UINT64 SourceEntry,
|
|
IN EFI_DEBUGGER_BRANCH_TYPE Type
|
|
)
|
|
{
|
|
if (mDebuggerPrivate.CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) {
|
|
ASSERT (FALSE);
|
|
mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
|
|
}
|
|
//
|
|
// Record the new callstack entry
|
|
//
|
|
mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].SourceAddress = SourceEntry;
|
|
mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Type = Type;
|
|
|
|
//
|
|
// Do not change CallStackEntryCount
|
|
//
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
It will record parameter for Callstack entry.
|
|
|
|
@param ParameterAddress - The address for the parameter
|
|
@param Type - Branch type
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerPushCallstackParameter (
|
|
IN UINT64 ParameterAddress,
|
|
IN EFI_DEBUGGER_BRANCH_TYPE Type
|
|
)
|
|
{
|
|
if (mDebuggerPrivate.CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) {
|
|
ASSERT (FALSE);
|
|
mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
|
|
}
|
|
//
|
|
// Record the new callstack parameter
|
|
//
|
|
mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].ParameterAddr = (UINTN)ParameterAddress;
|
|
CopyMem (
|
|
mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Parameter,
|
|
(VOID *)(UINTN)ParameterAddress,
|
|
sizeof(mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Parameter)
|
|
);
|
|
|
|
//
|
|
// Do not change CallStackEntryCount
|
|
//
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
It will record source address for callstack entry.
|
|
|
|
@param DestEntry - Source address
|
|
@param Type - Branch type
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerPushCallstackDest (
|
|
IN UINT64 DestEntry,
|
|
IN EFI_DEBUGGER_BRANCH_TYPE Type
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
if (mDebuggerPrivate.CallStackEntryCount < EFI_DEBUGGER_CALLSTACK_MAX) {
|
|
//
|
|
// If there is empty entry for callstack, add it
|
|
//
|
|
ASSERT (mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Type == Type);
|
|
mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].DestAddress = DestEntry;
|
|
mDebuggerPrivate.CallStackEntryCount ++;
|
|
} else {
|
|
//
|
|
// If there is no empty entry for callstack, throw the oldest one
|
|
//
|
|
ASSERT (mDebuggerPrivate.CallStackEntry[EFI_DEBUGGER_TRACE_MAX].Type == Type);
|
|
for (Index = 0; Index < EFI_DEBUGGER_CALLSTACK_MAX; Index++) {
|
|
CopyMem (&mDebuggerPrivate.CallStackEntry[Index],
|
|
&mDebuggerPrivate.CallStackEntry[Index + 1],
|
|
sizeof (mDebuggerPrivate.CallStackEntry[Index])
|
|
);
|
|
}
|
|
mDebuggerPrivate.CallStackEntry[EFI_DEBUGGER_CALLSTACK_MAX - 1].DestAddress = DestEntry;
|
|
mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
It will throw the newest Callstack entry.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerPopCallstack (
|
|
VOID
|
|
)
|
|
{
|
|
if ((mDebuggerPrivate.CallStackEntryCount > 0) &&
|
|
(mDebuggerPrivate.CallStackEntryCount <= EFI_DEBUGGER_CALLSTACK_MAX)) {
|
|
//
|
|
// Throw the newest one
|
|
//
|
|
mDebuggerPrivate.CallStackEntryCount --;
|
|
mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].SourceAddress = 0;
|
|
mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].DestAddress = 0;
|
|
} else if (mDebuggerPrivate.CallStackEntryCount == 0) {
|
|
//
|
|
// NOT assert here because it is reasonable, because when we start to build
|
|
// callstack, we do not know how many function already called.
|
|
//
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
It will record source address for trace entry.
|
|
|
|
@param SourceEntry - Source address
|
|
@param Type - Branch type
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerPushTraceSourceEntry (
|
|
IN UINT64 SourceEntry,
|
|
IN EFI_DEBUGGER_BRANCH_TYPE Type
|
|
)
|
|
{
|
|
if (mDebuggerPrivate.TraceEntryCount > EFI_DEBUGGER_TRACE_MAX) {
|
|
ASSERT (FALSE);
|
|
mDebuggerPrivate.TraceEntryCount = EFI_DEBUGGER_TRACE_MAX;
|
|
}
|
|
//
|
|
// Record the new trace entry
|
|
//
|
|
mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].SourceAddress = SourceEntry;
|
|
mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].Type = Type;
|
|
|
|
//
|
|
// Do not change TraceEntryCount
|
|
//
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
It will record destination address for trace entry.
|
|
|
|
@param DestEntry - Destination address
|
|
@param Type - Branch type
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerPushTraceDestEntry (
|
|
IN UINT64 DestEntry,
|
|
IN EFI_DEBUGGER_BRANCH_TYPE Type
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
if (mDebuggerPrivate.TraceEntryCount < EFI_DEBUGGER_TRACE_MAX) {
|
|
//
|
|
// If there is empty entry for trace, add it
|
|
//
|
|
ASSERT (mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].Type == Type);
|
|
mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].DestAddress = DestEntry;
|
|
mDebuggerPrivate.TraceEntryCount ++;
|
|
} else {
|
|
//
|
|
// If there is no empty entry for trace, throw the oldest one
|
|
//
|
|
ASSERT (mDebuggerPrivate.TraceEntry[EFI_DEBUGGER_TRACE_MAX].Type == Type);
|
|
for (Index = 0; Index < EFI_DEBUGGER_TRACE_MAX; Index++) {
|
|
mDebuggerPrivate.TraceEntry[Index] = mDebuggerPrivate.TraceEntry[Index + 1];
|
|
}
|
|
mDebuggerPrivate.TraceEntry[EFI_DEBUGGER_CALLSTACK_MAX - 1].DestAddress = DestEntry;
|
|
mDebuggerPrivate.TraceEntryCount = EFI_DEBUGGER_TRACE_MAX;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
It will record address for StepEntry, if STEPOVER or STEPOUT is enabled.
|
|
|
|
@param Entry - Break Address
|
|
@param FramePtr - Break Frame pointer
|
|
@param Flag - for STEPOVER or STEPOUT
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerPushStepEntry (
|
|
IN UINT64 Entry,
|
|
IN UINT64 FramePtr,
|
|
IN UINT32 Flag
|
|
)
|
|
{
|
|
//
|
|
// Check StepOver
|
|
//
|
|
if ((Flag == EFI_DEBUG_FLAG_EBC_STEPOVER) &&
|
|
((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_STEPOVER) == EFI_DEBUG_FLAG_EBC_STEPOVER)) {
|
|
mDebuggerPrivate.StepContext.BreakAddress = Entry;
|
|
mDebuggerPrivate.StepContext.FramePointer = FramePtr;
|
|
mDebuggerPrivate.FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOVER;
|
|
}
|
|
//
|
|
// Check StepOut
|
|
//
|
|
if ((Flag == EFI_DEBUG_FLAG_EBC_STEPOUT) &&
|
|
((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_STEPOUT) == EFI_DEBUG_FLAG_EBC_STEPOUT)) {
|
|
mDebuggerPrivate.StepContext.BreakAddress = Entry;
|
|
mDebuggerPrivate.StepContext.FramePointer = FramePtr;
|
|
mDebuggerPrivate.FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOUT;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Notify the callback function when an event is triggered.
|
|
|
|
@param Event Indicates the event that invoke this function.
|
|
@param Context Indicates the calling context.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
EbcDebuggerBreakEventFunc (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if ((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_BOK) != EFI_DEBUG_FLAG_EBC_BOK) {
|
|
return ;
|
|
}
|
|
|
|
Status = gBS->CheckEvent (gST->ConIn->WaitForKey);
|
|
if (Status == EFI_SUCCESS) {
|
|
mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_BOK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in InitializeEbcDriver.
|
|
It will init the EbcDebuggerPrivate data structure.
|
|
|
|
@param Handle - The EbcDebugProtocol handle.
|
|
@param EbcDebugProtocol - The EbcDebugProtocol interface.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookInit (
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
|
EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
|
|
|
|
|
|
//
|
|
// Register all exception handler
|
|
//
|
|
for (Index = EXCEPT_EBC_UNDEFINED; Index <= EXCEPT_EBC_STEP; Index++) {
|
|
EbcDebugProtocol->RegisterExceptionCallback (
|
|
EbcDebugProtocol,
|
|
0,
|
|
NULL,
|
|
Index
|
|
);
|
|
EbcDebugProtocol->RegisterExceptionCallback (
|
|
EbcDebugProtocol,
|
|
0,
|
|
EdbExceptionHandler,
|
|
Index
|
|
);
|
|
}
|
|
|
|
//
|
|
// Init Symbol
|
|
//
|
|
Object = AllocateZeroPool (sizeof(EFI_DEBUGGER_SYMBOL_OBJECT) * EFI_DEBUGGER_SYMBOL_OBJECT_MAX);
|
|
ASSERT (Object != NULL);
|
|
mDebuggerPrivate.DebuggerSymbolContext.Object = Object;
|
|
mDebuggerPrivate.DebuggerSymbolContext.ObjectCount = 0;
|
|
mDebuggerPrivate.DebuggerSymbolContext.MaxObjectCount = EFI_DEBUGGER_SYMBOL_OBJECT_MAX;
|
|
for (Index = 0; Index < EFI_DEBUGGER_SYMBOL_OBJECT_MAX; Index++) {
|
|
Entry = AllocateZeroPool (sizeof(EFI_DEBUGGER_SYMBOL_ENTRY) * EFI_DEBUGGER_SYMBOL_ENTRY_MAX);
|
|
ASSERT (Entry != NULL);
|
|
Object[Index].Entry = Entry;
|
|
Object[Index].MaxEntryCount = EFI_DEBUGGER_SYMBOL_ENTRY_MAX;
|
|
Object[Index].SourceBuffer = AllocateZeroPool (sizeof(VOID *) * (EFI_DEBUGGER_SYMBOL_ENTRY_MAX + 1));
|
|
ASSERT (Object[Index].SourceBuffer != NULL);
|
|
}
|
|
|
|
//
|
|
// locate PciRootBridgeIo
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiPciRootBridgeIoProtocolGuid,
|
|
NULL,
|
|
(VOID**) &mDebuggerPrivate.PciRootBridgeIo
|
|
);
|
|
|
|
//
|
|
// locate DebugImageInfoTable
|
|
//
|
|
Status = EfiGetSystemConfigurationTable (
|
|
&gEfiDebugImageInfoTableGuid,
|
|
(VOID**) &mDebuggerPrivate.DebugImageInfoTableHeader
|
|
);
|
|
|
|
//
|
|
// Register Debugger Configuration Protocol, for config in shell
|
|
//
|
|
Status = gBS->InstallProtocolInterface (
|
|
&Handle,
|
|
&gEfiDebuggerConfigurationProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&mDebuggerPrivate.DebuggerConfiguration
|
|
);
|
|
|
|
//
|
|
//
|
|
// Create break event
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
EbcDebuggerBreakEventFunc,
|
|
NULL,
|
|
&mDebuggerPrivate.BreakEvent
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->SetTimer (
|
|
mDebuggerPrivate.BreakEvent,
|
|
TimerPeriodic,
|
|
EFI_DEBUG_BREAK_TIMER_INTERVAL
|
|
);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in UnloadImage for EBC Interpreter.
|
|
It clean up the environment.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookUnload (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN SubIndex;
|
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
|
|
|
//
|
|
// Close the break event
|
|
//
|
|
if (mDebuggerPrivate.BreakEvent != NULL) {
|
|
gBS->CloseEvent (mDebuggerPrivate.BreakEvent);
|
|
}
|
|
|
|
//
|
|
// Clean up the symbol
|
|
//
|
|
Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
|
|
for (Index = 0; Index < EFI_DEBUGGER_SYMBOL_OBJECT_MAX; Index++) {
|
|
//
|
|
// Clean up Entry
|
|
//
|
|
gBS->FreePool (Object[Index].Entry);
|
|
Object[Index].Entry = NULL;
|
|
Object[Index].EntryCount = 0;
|
|
//
|
|
// Clean up source buffer
|
|
//
|
|
for (SubIndex = 0; Object[Index].SourceBuffer[SubIndex] != NULL; SubIndex++) {
|
|
gBS->FreePool (Object[Index].SourceBuffer[SubIndex]);
|
|
Object[Index].SourceBuffer[SubIndex] = NULL;
|
|
}
|
|
gBS->FreePool (Object[Index].SourceBuffer);
|
|
Object[Index].SourceBuffer = NULL;
|
|
}
|
|
|
|
//
|
|
// Clean up Object
|
|
//
|
|
gBS->FreePool (Object);
|
|
mDebuggerPrivate.DebuggerSymbolContext.Object = NULL;
|
|
mDebuggerPrivate.DebuggerSymbolContext.ObjectCount = 0;
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in EbcUnloadImage.
|
|
Currently do nothing here.
|
|
|
|
@param Handle - The EbcImage handle.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookEbcUnloadImage (
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
{
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteEbcImageEntryPoint.
|
|
It will record the call-stack entry. (-1 means EbcImageEntryPoint call)
|
|
and trigger Exception if BOE enabled.
|
|
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookExecuteEbcImageEntryPoint (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EbcDebuggerPushCallstackSource ((UINT64)(UINTN)-1, EfiDebuggerBranchTypeEbcCall);
|
|
EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
|
|
EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
|
|
EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOE);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteEbcImageEntryPoint.
|
|
It will record the call-stack entry. (-2 means EbcInterpret call)
|
|
and trigger Exception if BOT enabled.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookEbcInterpret (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EbcDebuggerPushCallstackSource ((UINT64)(UINTN)-2, EfiDebuggerBranchTypeEbcCall);
|
|
EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
|
|
EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
|
|
EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOT);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in EbcExecute, before ExecuteFunction.
|
|
It will trigger Exception if GoTil, StepOver, or StepOut hit.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookExecuteStart (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EFI_TPL CurrentTpl;
|
|
|
|
//
|
|
// Check Ip for GoTil
|
|
//
|
|
if (mDebuggerPrivate.GoTilContext.BreakAddress == (UINT64)(UINTN)VmPtr->Ip) {
|
|
mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_GT;
|
|
mDebuggerPrivate.GoTilContext.BreakAddress = 0;
|
|
EbcDebugSignalException (
|
|
EXCEPT_EBC_BREAKPOINT,
|
|
EXCEPTION_FLAG_NONE,
|
|
VmPtr
|
|
);
|
|
mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_GT;
|
|
return ;
|
|
}
|
|
//
|
|
// Check ReturnAddress for StepOver
|
|
//
|
|
if ((mDebuggerPrivate.StepContext.BreakAddress == (UINT64)(UINTN)VmPtr->Ip) &&
|
|
(mDebuggerPrivate.StepContext.FramePointer == (UINT64)(UINTN)VmPtr->FramePtr)) {
|
|
mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_STEPOVER;
|
|
mDebuggerPrivate.StepContext.BreakAddress = 0;
|
|
mDebuggerPrivate.StepContext.FramePointer = 0;
|
|
EbcDebugSignalException (
|
|
EXCEPT_EBC_BREAKPOINT,
|
|
EXCEPTION_FLAG_NONE,
|
|
VmPtr
|
|
);
|
|
mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOVER;
|
|
}
|
|
//
|
|
// Check FramePtr for StepOut
|
|
//
|
|
if (mDebuggerPrivate.StepContext.BreakAddress == (UINT64)(UINTN)VmPtr->FramePtr) {
|
|
mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_STEPOUT;
|
|
mDebuggerPrivate.StepContext.BreakAddress = 0;
|
|
mDebuggerPrivate.StepContext.FramePointer = 0;
|
|
EbcDebugSignalException (
|
|
EXCEPT_EBC_BREAKPOINT,
|
|
EXCEPTION_FLAG_NONE,
|
|
VmPtr
|
|
);
|
|
mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOUT;
|
|
}
|
|
//
|
|
// Check Flags for BreakOnKey
|
|
//
|
|
if (mDebuggerPrivate.StatusFlags == EFI_DEBUG_FLAG_EBC_BOK) {
|
|
//
|
|
// Only break when the current TPL <= TPL_APPLICATION
|
|
//
|
|
CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
|
|
gBS->RestoreTPL (CurrentTpl);
|
|
if (CurrentTpl <= TPL_APPLICATION) {
|
|
EbcDebugSignalException (
|
|
EXCEPT_EBC_BREAKPOINT,
|
|
EXCEPTION_FLAG_NONE,
|
|
VmPtr
|
|
);
|
|
mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOK;
|
|
}
|
|
}
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in EbcExecute, after ExecuteFunction.
|
|
It will record StepOut Entry if need.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookExecuteEnd (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
UINTN Address;
|
|
|
|
//
|
|
// Use FramePtr as checkpoint for StepOut
|
|
//
|
|
CopyMem (&Address, (VOID *)((UINTN)VmPtr->FramePtr), sizeof(Address));
|
|
EbcDebuggerPushStepEntry (Address, (UINT64)(UINTN)VmPtr->FramePtr, EFI_DEBUG_FLAG_EBC_STEPOUT);
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteCALL, before move IP.
|
|
It will trigger Exception if BOC enabled,
|
|
and record Callstack, and trace information.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookCALLStart (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOC);
|
|
EbcDebuggerPushCallstackSource ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
|
|
EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
|
|
EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteCALL, after move IP.
|
|
It will record Callstack, trace information
|
|
and record StepOver/StepOut Entry if need.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookCALLEnd (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
UINT64 Address;
|
|
UINTN FramePtr;
|
|
|
|
EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
|
|
EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
|
|
|
|
//
|
|
// Get Old FramePtr
|
|
//
|
|
CopyMem (&FramePtr, (VOID *)((UINTN)VmPtr->FramePtr), sizeof(FramePtr));
|
|
|
|
//
|
|
// Use ReturnAddress as checkpoint for StepOver
|
|
//
|
|
CopyMem (&Address, (VOID *)(UINTN)VmPtr->Gpr[0], sizeof(Address));
|
|
EbcDebuggerPushStepEntry (Address, FramePtr, EFI_DEBUG_FLAG_EBC_STEPOVER);
|
|
|
|
//
|
|
// Use FramePtr as checkpoint for StepOut
|
|
//
|
|
Address = 0;
|
|
CopyMem (&Address, (VOID *)(FramePtr), sizeof(UINTN));
|
|
EbcDebuggerPushStepEntry (Address, FramePtr, EFI_DEBUG_FLAG_EBC_STEPOUT);
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteCALL, before call EbcLLCALLEX.
|
|
It will trigger Exception if BOCX enabled,
|
|
and record Callstack information.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookCALLEXStart (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOCX);
|
|
// EbcDebuggerPushCallstackSource ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
|
|
// EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->R[0], EfiDebuggerBranchTypeEbcCallEx);
|
|
EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteCALL, after call EbcLLCALLEX.
|
|
It will record trace information.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookCALLEXEnd (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
// EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
|
|
EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteRET, before move IP.
|
|
It will trigger Exception if BOR enabled,
|
|
and record Callstack, and trace information.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookRETStart (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOR);
|
|
EbcDebuggerPopCallstack ();
|
|
EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcRet);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteRET, after move IP.
|
|
It will record trace information.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookRETEnd (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcRet);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteJMP, before move IP.
|
|
It will record trace information.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookJMPStart (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteJMP, after move IP.
|
|
It will record trace information.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookJMPEnd (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteJMP8, before move IP.
|
|
It will record trace information.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookJMP8Start (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp8);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
The hook in ExecuteJMP8, after move IP.
|
|
It will record trace information.
|
|
|
|
@param VmPtr - pointer to VM context.
|
|
|
|
**/
|
|
VOID
|
|
EbcDebuggerHookJMP8End (
|
|
IN VM_CONTEXT *VmPtr
|
|
)
|
|
{
|
|
EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp8);
|
|
return ;
|
|
}
|