/** @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"

/**

  Get file name from full path.

  @param  FullPath        - full file path

  @return  file name

**/
CHAR16 *
GetFileNameFromFullPath (
  IN CHAR16   *FullPath
  )
{
  CHAR16   *FileName;
  CHAR16   *TempFileName;

  FileName = FullPath;
  TempFileName = StrGetNewTokenLine (FullPath, L"\\");

  while (TempFileName != NULL) {
    FileName = TempFileName;
    TempFileName = StrGetNextTokenLine (L"\\");
    PatchForStrTokenBefore (TempFileName, L'\\');
  }

  return FileName;
}

/**

  Get dir name from full path.

  @param  FullPath        - full file path

  @return dir name

**/
CHAR16 *
GetDirNameFromFullPath (
  IN CHAR16   *FullPath
  )
{
  CHAR16   *FileName;

  FileName = GetFileNameFromFullPath (FullPath);
  if (FileName != FullPath) {
    *(FileName - 1) = 0;
    return FullPath;
  }

  return L"";
}

/**

  Construct full path according to dir and file path.

  @param  DirPath         - dir path
  @param  FilePath        - file path
  @param  Size            - dir max size

  @return Full file name

**/
CHAR16 *
ConstructFullPath (
  IN CHAR16   *DirPath,
  IN CHAR16   *FilePath,
  IN UINTN    Size
  )
{
  UINTN DirPathSize;

  DirPathSize = StrLen(DirPath);
  *(DirPath + DirPathSize) = L'\\';
  StrnCatS (DirPath, DirPathSize + Size + 1, FilePath, Size);

  *(DirPath + DirPathSize + Size + 1) = 0;

  return DirPath;
}

CHAR16 *mSymbolTypeStr[] = {
  L"( F)",
  L"(SF)",
  L"(GV)",
  L"(SV)",
};

/**

  Comvert Symbol Type to string.

  @param  Type            - Symbol Type

  @return String

**/
CHAR16 *
EdbSymbolTypeToStr (
  IN EFI_DEBUGGER_SYMBOL_TYPE  Type
  )
{
  if (Type < 0 || Type >= EfiDebuggerSymbolTypeMax) {
    return L"(?)";
  }

  return mSymbolTypeStr [Type];
}

/**

  Find the symbol according to address and display symbol.

  @param  Address         - SymbolAddress
  @param  DebuggerPrivate - EBC Debugger private data structure

  @retval EFI_DEBUG_CONTINUE - formal return value

**/
EFI_DEBUG_STATUS
DebuggerDisplaySymbolAccrodingToAddress (
  IN     UINTN                      Address,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
  )
{
  EFI_DEBUGGER_SYMBOL_OBJECT *Object;
  EFI_DEBUGGER_SYMBOL_ENTRY  *Entry;
  UINTN                      CandidateAddress;

  //
  // Find the nearest symbol address
  //
  CandidateAddress = EbdFindSymbolAddress (Address, EdbMatchSymbolTypeNearestAddress, &Object, &Entry);
  if (CandidateAddress == 0 || CandidateAddress == (UINTN) -1) {
    EDBPrint (L"Symbole at Address not found!\n");
    return EFI_DEBUG_CONTINUE;
  } else if (Address != CandidateAddress) {
    EDBPrint (L"Symbole at Address not found, print nearest one!\n");
  }

  //
  // Display symbol
  //
  EDBPrint (L"Symbol File Name: %s\n", Object->Name);
  if (sizeof(UINTN) == sizeof(UINT64)) {
    EDBPrint (L"        Address      Type  Symbol\n");
    EDBPrint (L"  ================== ==== ========\n");
//  EDBPrint (L"  0xFFFFFFFF00000000 ( F) TestMain\n");
    EDBPrint (
      L"  0x%016lx %s %a\n",
      (UINT64)Entry->Rva + Object->BaseAddress,
      EdbSymbolTypeToStr (Entry->Type),
      Entry->Name
      );
  } else {
    EDBPrint (L"   Address   Type  Symbol\n");
    EDBPrint (L"  ========== ==== ========\n");
//  EDBPrint (L"  0xFFFF0000 ( F) TestMain\n");
    EDBPrint (
      L"  0x%08x %s %a\n",
      Entry->Rva + Object->BaseAddress,
      EdbSymbolTypeToStr (Entry->Type),
      Entry->Name
      );
  }

  //
  // Done
  //
  return EFI_DEBUG_CONTINUE;
}

/**

  Find the symbol according to name and display symbol.

  @param  SymbolFileName  - The Symbol File Name, NULL means for all
  @param  SymbolName      - The Symbol Name, NULL means for all
  @param  DebuggerPrivate - EBC Debugger private data structure

  @retval EFI_DEBUG_CONTINUE - formal return value

**/
EFI_DEBUG_STATUS
DebuggerDisplaySymbolAccrodingToName (
  IN     CHAR16                     *SymbolFileName,
  IN     CHAR16                     *SymbolName,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
  )
{
  UINTN                      Index;
  UINTN                      SubIndex;
  EFI_DEBUGGER_SYMBOL_OBJECT *Object;
  EFI_DEBUGGER_SYMBOL_ENTRY  *Entry;

  if (DebuggerPrivate->DebuggerSymbolContext.ObjectCount == 0) {
    EDBPrint (L"No Symbol File!\n");
    return EFI_DEBUG_CONTINUE;
  }

  //
  // Go throuth each symbol file
  //
  Object = DebuggerPrivate->DebuggerSymbolContext.Object;
  for (Index = 0; Index < DebuggerPrivate->DebuggerSymbolContext.ObjectCount; Index++, Object++) {
    if ((SymbolFileName != NULL) &&
        (StriCmp (SymbolFileName, Object->Name) != 0)) {
      continue;
    }

    //
    // Break each symbol file
    //
    if (Index != 0) {
      if (SetPageBreak ()) {
        break;
      }
    }

    EDBPrint (L"Symbol File Name: %s\n", Object->Name);
    if (Object->EntryCount == 0) {
      EDBPrint (L"No Symbol!\n");
      continue;
    }
    Entry = Object->Entry;
    if (sizeof(UINTN) == sizeof(UINT64)) {
      EDBPrint (L"        Address      Type  Symbol\n");
      EDBPrint (L"  ================== ==== ========\n");
//    EDBPrint (L"  0xFFFFFFFF00000000 ( F) TestMain (EbcTest.obj)\n");
    } else {
      EDBPrint (L"   Address   Type  Symbol\n");
      EDBPrint (L"  ========== ==== ========\n");
//    EDBPrint (L"  0xFFFF0000 ( F) TestMain (EbcTest.obj)\n");
    }

    //
    // Go through each symbol name
    //
    for (SubIndex = 0; SubIndex < Object->EntryCount; SubIndex++, Entry++) {
      if ((SymbolName != NULL) &&
          (StrCmpUnicodeAndAscii (SymbolName, Entry->Name) != 0)) {
        continue;
      }

      //
      // Break symbol
      //
      if (((SubIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
          (SubIndex != 0)) {
        if (SetPageBreak ()) {
          break;
        }
      }

      if (sizeof(UINTN) == sizeof(UINT64)) {
        EDBPrint (
          L"  0x%016lx %s %a (%a)\n",
          (UINT64)Entry->Rva + Object->BaseAddress,
          EdbSymbolTypeToStr (Entry->Type),
          Entry->Name,
          Entry->ObjName
          );
      } else {
        EDBPrint (
          L"  0x%08x %s %a (%a)\n",
          Entry->Rva + Object->BaseAddress,
          EdbSymbolTypeToStr (Entry->Type),
          Entry->Name,
          Entry->ObjName
          );
      }
    }
  }

  //
  // Done
  //
  return EFI_DEBUG_CONTINUE;
}

/**

  DebuggerCommand - ListSymbol.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_CONTINUE - formal return value

**/
EFI_DEBUG_STATUS
DebuggerListSymbol (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  CHAR16                     *SymbolFileName;
  CHAR16                     *SymbolName;
  CHAR16                     *CommandStr;
  UINTN                      Address;

  SymbolFileName = NULL;
  SymbolName = NULL;
  CommandStr = CommandArg;

  //
  // display symbol according to address
  //
  if (CommandStr != NULL) {
    if ((StriCmp (CommandStr, L"F") != 0) &&
        (StriCmp (CommandStr, L"S") != 0)) {
      Address = Xtoi (CommandStr);
      return DebuggerDisplaySymbolAccrodingToAddress (Address, DebuggerPrivate);
    }
  }

  //
  // Get SymbolFileName
  //
  if (CommandStr != NULL) {
    if (StriCmp (CommandStr, L"F") == 0) {
      CommandStr = StrGetNextTokenLine (L" ");
      if (CommandStr == NULL) {
        EDBPrint (L"Symbol File Name missing!\n");
        return EFI_DEBUG_CONTINUE;
      } else {
        SymbolFileName = CommandStr;
        CommandStr = StrGetNextTokenLine (L" ");
      }
    }
  }
  //
  // Get SymbolName
  //
  if (CommandStr != NULL) {
    if (StriCmp (CommandStr, L"S") == 0) {
      CommandStr = StrGetNextTokenLine (L" ");
      if (CommandStr == NULL) {
        EDBPrint (L"Symbol Name missing!\n");
        return EFI_DEBUG_CONTINUE;
      } else {
        SymbolName = CommandStr;
        CommandStr = StrGetNextTokenLine (L" ");
      }
    }
  }
  if (CommandStr != NULL) {
    EDBPrint (L"Argument error!\n");
    return EFI_DEBUG_CONTINUE;
  }

  //
  // display symbol according to name
  //
  return DebuggerDisplaySymbolAccrodingToName (SymbolFileName, SymbolName, DebuggerPrivate);
}

/**

  DebuggerCommand - LoadSymbol.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_CONTINUE - formal return value

**/
EFI_DEBUG_STATUS
DebuggerLoadSymbol (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  UINTN      BufferSize;
  VOID       *Buffer;
  EFI_STATUS Status;
  CHAR16     *FileName;
  CHAR16     *CommandArg2;
  BOOLEAN    IsLoadCode;
  CHAR16     *DirName;
  CHAR16     CodFile[EFI_DEBUGGER_SYMBOL_NAME_MAX];
  CHAR16     *CodFileName;
  UINTN      Index;

  //
  // Check the argument
  //
  if (CommandArg == NULL) {
    EDBPrint (L"SymbolFile not found!\n");
    return EFI_DEBUG_CONTINUE;
  }
  IsLoadCode = FALSE;
  CommandArg2 = StrGetNextTokenLine (L" ");
  if (CommandArg2 != NULL) {
    if (StriCmp (CommandArg2, L"a") == 0) {
      IsLoadCode = TRUE;
    } else {
      EDBPrint (L"Argument error!\n");
      return EFI_DEBUG_CONTINUE;
    }
  }

  if (StrLen (CommandArg) <= 4) {
    EDBPrint (L"SymbolFile name error!\n");
    return EFI_DEBUG_CONTINUE;
  }
  if (StriCmp (CommandArg + (StrLen (CommandArg) - 4), L".map") != 0) {
    EDBPrint (L"SymbolFile name error!\n");
    return EFI_DEBUG_CONTINUE;
  }

  //
  // Read MAP file to memory
  //
  Status = ReadFileToBuffer (DebuggerPrivate, CommandArg, &BufferSize, &Buffer, TRUE);
  if (EFI_ERROR(Status)) {
    EDBPrint (L"SymbolFile read error!\n");
    return EFI_DEBUG_CONTINUE;
  }

  FileName = GetFileNameFromFullPath (CommandArg);
  //
  // Load Symbol
  //
  Status = EdbLoadSymbol (DebuggerPrivate, FileName, BufferSize, Buffer);
  if (EFI_ERROR(Status)) {
    EDBPrint (L"LoadSymbol error!\n");
    gBS->FreePool (Buffer);
    return EFI_DEBUG_CONTINUE;
  }
  gBS->FreePool (Buffer);

  //
  // Patch Symbol for RVA
  //
  Status = EdbPatchSymbolRVA (DebuggerPrivate, FileName, EdbEbcImageRvaSearchTypeLast);
  if (EFI_ERROR(Status)) {
    EDBPrint (L"PatchSymbol RVA  - %r! Using the RVA in symbol file.\n", Status);
  } else {
    DEBUG ((DEBUG_ERROR, "PatchSymbol RVA successfully!\n"));
  }

  if (!IsLoadCode) {
    return EFI_DEBUG_CONTINUE;
  }

  //
  // load each cod file
  //
  DirName = GetDirNameFromFullPath (CommandArg);
  ZeroMem (CodFile, sizeof(CodFile));
  if (StrCmp (DirName, L"") != 0) {
    StrCpyS (CodFile, sizeof(CodFile), DirName);
  } else {
    DirName = L"\\";
  }

  //
  // Go throuth each file under this dir
  //
  Index = 0;
  CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
  while (CodFileName != NULL) {
    ZeroMem (CodFile, sizeof(CodFile));
    if (StrCmp (DirName, L"\\") != 0) {
      StrCpyS (CodFile, sizeof(CodFile), DirName);
    }

    //
    // read cod file to memory
    //
    Status = ReadFileToBuffer (DebuggerPrivate, ConstructFullPath (CodFile, CodFileName, EFI_DEBUGGER_SYMBOL_NAME_MAX - StrLen (CodFile) - 2), &BufferSize, &Buffer, FALSE);
    if (EFI_ERROR(Status)) {
      EDBPrint (L"CodeFile read error!\n");
      CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
      continue;
    }

    //
    // Load Code
    //
    Status = EdbLoadCode (DebuggerPrivate, FileName, CodFileName, BufferSize, Buffer);
    if (EFI_ERROR (Status)) {
      EDBPrint (L"LoadCode error!\n");
      gBS->FreePool (Buffer);
      CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
      continue;
    }

    //
    // Record the buffer
    //
    Status = EdbAddCodeBuffer (DebuggerPrivate, FileName, CodFileName, BufferSize, Buffer);
    if (EFI_ERROR (Status)) {
      EDBPrint (L"AddCodeBuffer error!\n");
      gBS->FreePool (Buffer);
      CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
      continue;
    }

    //
    // Get next file
    //
    CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
  }

  //
  // Done
  //
  return EFI_DEBUG_CONTINUE;
}

/**

  DebuggerCommand - UnloadSymbol

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_CONTINUE - formal return value

**/
EFI_DEBUG_STATUS
DebuggerUnloadSymbol (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  EFI_STATUS Status;
  CHAR16     *FileName;
  CHAR16     *DirName;
  CHAR16     CodFile[EFI_DEBUGGER_SYMBOL_NAME_MAX];
  CHAR16     *CodFileName;
  UINTN      Index;
  VOID       *BufferPtr;

  //
  // Check the argument
  //
  if (CommandArg == NULL) {
    EDBPrint (L"SymbolFile not found!\n");
    return EFI_DEBUG_CONTINUE;
  }

  FileName = GetFileNameFromFullPath (CommandArg);

  //
  // Unload Code
  //
  DirName = GetDirNameFromFullPath (CommandArg);
  ZeroMem (CodFile, sizeof(CodFile));
  if (StrCmp (DirName, L"") != 0) {
    StrCpyS (CodFile, sizeof(CodFile), DirName);
  } else {
    DirName = L"\\";
  }

  //
  // Go through each file under this dir
  //
  Index = 0;
  CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
  while (CodFileName != NULL) {
    ZeroMem (CodFile, sizeof(CodFile));
    if (StrCmp (DirName, L"\\") != 0) {
      StrCpyS (CodFile, sizeof(CodFile), DirName);
    }

    //
    // Unload Code
    //
    Status = EdbUnloadCode (DebuggerPrivate, FileName, CodFileName, &BufferPtr);
    if (EFI_ERROR (Status)) {
      EDBPrint (L"UnloadCode error!\n");
      CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
      continue;
    }

    //
    // Delete the code buffer
    //
    Status = EdbDeleteCodeBuffer (DebuggerPrivate, FileName, CodFileName, BufferPtr);
    if (EFI_ERROR (Status)) {
      EDBPrint (L"DeleteCodeBuffer error!\n");
      CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
      continue;
    }

    //
    // Get next file
    //
    CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
  }

  //
  // Unload Symbol
  //
  Status = EdbUnloadSymbol (DebuggerPrivate, FileName);
  if (EFI_ERROR(Status)) {
    EDBPrint (L"UnloadSymbol error!\n");
  }

  //
  // Done
  //
  return EFI_DEBUG_CONTINUE;
}

/**

  DebuggerCommand - DisplaySymbol.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_CONTINUE - formal return value

**/
EFI_DEBUG_STATUS
DebuggerDisplaySymbol (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  if (CommandArg == NULL) {
    DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = !DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol;
    EdbShowDisasm (DebuggerPrivate, SystemContext);
  } else if (StriCmp (CommandArg, L"on") == 0) {
    DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = TRUE;
    EdbShowDisasm (DebuggerPrivate, SystemContext);
  } else if (StriCmp (CommandArg, L"off") == 0) {
    DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = FALSE;
    EdbShowDisasm (DebuggerPrivate, SystemContext);
  } else {
    EDBPrint (L"DisplaySymbol - argument error\n");
  }

  return EFI_DEBUG_CONTINUE;
}

/**

  DebuggerCommand - LoadCode.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_CONTINUE - formal return value

**/
EFI_DEBUG_STATUS
DebuggerLoadCode (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  UINTN      BufferSize;
  VOID       *Buffer;
  EFI_STATUS Status;
  CHAR16     *CommandArg2;
  CHAR16     *FileName;
  CHAR16     *MapFileName;

  //
  // Check the argument
  //
  if (CommandArg == NULL) {
    EDBPrint (L"CodeFile not found!\n");
    return EFI_DEBUG_CONTINUE;
  }
  CommandArg2 = StrGetNextTokenLine (L" ");
  if (CommandArg2 == NULL) {
    EDBPrint (L"SymbolFile not found!\n");
    return EFI_DEBUG_CONTINUE;
  }

  if (StrLen (CommandArg) <= 4) {
    EDBPrint (L"CodeFile name error!\n");
    return EFI_DEBUG_CONTINUE;
  }
  if (StriCmp (CommandArg + (StrLen (CommandArg) - 4), L".cod") != 0) {
    EDBPrint (L"CodeFile name error!\n");
    return EFI_DEBUG_CONTINUE;
  }
  if (StrLen (CommandArg2) <= 4) {
    EDBPrint (L"SymbolFile name error!\n");
    return EFI_DEBUG_CONTINUE;
  }
  if (StriCmp (CommandArg2 + (StrLen (CommandArg2) - 4), L".map") != 0) {
    EDBPrint (L"SymbolFile name error!\n");
    return EFI_DEBUG_CONTINUE;
  }

  //
  // read cod file to memory
  //
  Status = ReadFileToBuffer (DebuggerPrivate, CommandArg, &BufferSize, &Buffer, TRUE);
  if (EFI_ERROR(Status)) {
    EDBPrint (L"CodeFile read error!\n");
    return EFI_DEBUG_CONTINUE;
  }

  FileName = GetFileNameFromFullPath (CommandArg);
  MapFileName = GetFileNameFromFullPath (CommandArg2);
  //
  // Load Code
  //
  Status = EdbLoadCode (DebuggerPrivate, MapFileName, FileName, BufferSize, Buffer);
  if (EFI_ERROR (Status)) {
    EDBPrint (L"LoadCode error!\n");
    gBS->FreePool (Buffer);
    return EFI_DEBUG_CONTINUE;
  }

  //
  // Record the buffer
  //
  Status = EdbAddCodeBuffer (DebuggerPrivate, MapFileName, FileName, BufferSize, Buffer);
  if (EFI_ERROR (Status)) {
    EDBPrint (L"AddCodeBuffer error!\n");
    gBS->FreePool (Buffer);
    return EFI_DEBUG_CONTINUE;
  }

  //
  // Done
  //
  return EFI_DEBUG_CONTINUE;
}

/**

  DebuggerCommand - UnloadCode.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_CONTINUE - formal return value

**/
EFI_DEBUG_STATUS
DebuggerUnloadCode (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  CHAR16     *CommandArg2;
  CHAR16     *FileName;
  CHAR16     *MapFileName;
  EFI_STATUS Status;
  VOID       *BufferPtr;

  //
  // Check the argument
  //
  if (CommandArg == NULL) {
    EDBPrint (L"CodeFile not found!\n");
    return EFI_DEBUG_CONTINUE;
  }
  CommandArg2 = StrGetNextTokenLine (L" ");
  if (CommandArg2 == NULL) {
    EDBPrint (L"SymbolFile not found!\n");
    return EFI_DEBUG_CONTINUE;
  }

  FileName = GetFileNameFromFullPath (CommandArg);
  MapFileName = GetFileNameFromFullPath (CommandArg2);

  //
  // Unload Code
  //
  Status = EdbUnloadCode (DebuggerPrivate, MapFileName, FileName, &BufferPtr);
  if (EFI_ERROR (Status)) {
    EDBPrint (L"UnloadCode error!\n");
    return EFI_DEBUG_CONTINUE;
  }

  //
  // Delete Code buffer
  //
  Status = EdbDeleteCodeBuffer (DebuggerPrivate, MapFileName, FileName, BufferPtr);
  if (EFI_ERROR (Status)) {
    EDBPrint (L"DeleteCodeBuffer error!\n");
  }

  //
  // Done
  //
  return EFI_DEBUG_CONTINUE;
}

/**

  DebuggerCommand - DisplayCode.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_CONTINUE - formal return value

**/
EFI_DEBUG_STATUS
DebuggerDisplayCode (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  if (CommandArg == NULL) {
    DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = !DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly;
    EdbShowDisasm (DebuggerPrivate, SystemContext);
  } else if (StriCmp (CommandArg, L"on") == 0) {
    DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = TRUE;
    EdbShowDisasm (DebuggerPrivate, SystemContext);
  } else if (StriCmp (CommandArg, L"off") == 0) {
    DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = FALSE;
    EdbShowDisasm (DebuggerPrivate, SystemContext);
  } else {
    EDBPrint (L"DisplayCode - argument error\n");
  }

  return EFI_DEBUG_CONTINUE;
}
