| /** @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 ; | |
| } |