https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
		
			
				
	
	
		
			834 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			834 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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++) {
 | 
						|
      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 ;
 | 
						|
}
 |