/** @file Copyright (c) 2007 - 2016, 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. **/ #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 ; }