/** @file | |
Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#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++) { | |
CopyMem ( | |
&mDebuggerPrivate.TraceEntry[Index], | |
&mDebuggerPrivate.TraceEntry[Index + 1], | |
sizeof (mDebuggerPrivate.TraceEntry[Index]) | |
); | |
} | |
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; | |
} |