/** @file

Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent


**/

#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;

  BufferPtr = NULL; //MS_CHANGE vs2017

  //
  // 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;

  Buffer = NULL; //MS_CHANGE for vs2017

  //
  // 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;

  BufferPtr = NULL; //MS_CHANGE for vs2017
  //
  // 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;
}
