/*++

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.

Module Name:

  EdbSymbol.c

Abstract:


--*/

#include "Edb.h"

EFI_STATUS
EdbLoadSymbolSingleEntry (
  IN EFI_DEBUGGER_SYMBOL_OBJECT  *Object,
  IN CHAR8                       *Name,
  IN CHAR8                       *ObjName,
  IN UINTN                       Address,
  IN EFI_DEBUGGER_SYMBOL_TYPE    Type
  )
/*++

Routine Description:

  Load single symbol entry

Arguments:

  Object          - Symbol file object
  Name            - Symbol name
  ObjName         - Object name
  Address         - Symbol address
  Type            - Symbol type

Returns:

  EFI_SUCCESS - add single symbol entry successfully

--*/
{
  EFI_DEBUGGER_SYMBOL_ENTRY  *Entry;

  //
  // Check Count VS MaxCount
  //
  if (Object->EntryCount >= Object->MaxEntryCount) {
    //
    // reallocate (for codebuffer too)
    // TBD
    //
    return EFI_OUT_OF_RESOURCES;
  }

  Entry = &Object->Entry[Object->EntryCount];

  //
  // Print Debug info
  //
  if (sizeof (UINTN) == sizeof(UINT64)) {
    DEBUG ((DEBUG_ERROR, "  Symbol: %a, Address: 0x%016lx (%d)\n", Name, (UINT64)Address, (UINTN)Type));
  } else {
    DEBUG ((DEBUG_ERROR, "  Symbol: %a, Address: 0x%08x (%d)\n", Name, Address, (UINTN)Type));
  }

  //
  // Fill the entry - name, RVA, type
  //
  AsciiStrnCpyS (Entry->Name, sizeof(Entry->Name), Name, sizeof(Entry->Name) - 1);
  if (ObjName != NULL) {
    AsciiStrnCpyS (Entry->ObjName, sizeof(Entry->ObjName), ObjName, sizeof(Entry->ObjName) - 1);
  }
  Entry->RVA = Address % EFI_DEBUGGER_DEFAULT_LINK_IMAGEBASE;
  Entry->Type = Type;

  //
  // Increase Count
  //
  Object->EntryCount++;

  //
  // Done
  //
  return EFI_SUCCESS;
}

typedef enum {
  EdbEbcMapParseStateUninitialized,
  EdbEbcMapParseStateSymbolStart,
  EdbEbcMapParseStateSeHandlerSymbol,
  EdbEbcMapParseStateFunctionSymbol,
  EdbEbcMapParseStateVarbssInitSymbol,
  EdbEbcMapParseStateCrtSymbol,
  EdbEbcMapParseStateVariableSymbol,
  EdbEbcMapParseStateStaticFunctionSymbol,
  EdbEbcMapParseStateMax,
} EDB_EBC_MAP_PARSE_STATE;

typedef enum {
  EdbEbcSymbolParseStateUninitialized,
  EdbEbcSymbolParseStateReadyForName,
  EdbEbcSymbolParseStateReadyForRVA,
  EdbEbcSymbolParseStateReadyForType,
  EdbEbcSymbolParseStateReadyForObject,
  EdbEbcSymbolParseStateMax,
} EDB_EBC_SYMBOL_PARSE_STATE;

/*++

  The following code depends on the MAP file generated by IEC compiler (actually Microsoft linker).

  Sample as follows: EbcTest.map
===============================================================================
  EbcTest

 Timestamp is 45b02718 (Fri Jan 19 10:04:08 2007)

 Preferred load address is 10000000

 Start         Length     Name                   Class
 0001:00000000 00000370H .text                   CODE
 0002:00000000 00000030H _VARBSS_INIT            CODE
 0003:00000000 00000004H .CRT$TSA                DATA
 0003:00000004 00000004H .CRT$TSC                DATA
 0003:00000008 00000004H .CRT$X                  DATA
 0003:0000000c 00000008H .CRT$XCU                DATA
 0003:00000014 00000004H .CRT$Z                  DATA
 0003:00000020 0000001cH .rdata                  DATA
 0003:0000003c 00000000H .edata                  DATA
 0003:0000003c 00000056H .rdata$debug            DATA
 0004:00000000 00000070H .data                   DATA
 0004:00000070 00000020H .bss                    DATA

  Address         Publics by Value              Rva+Base     Lib:Object

 0000:00000000       ___safe_se_handler_table   00000000     <absolute>
 0000:00000000       ___safe_se_handler_count   00000000     <absolute>
 0001:00000042       TestSubRoutine             10000442 f   EbcTest.obj
 0001:0000011a       EfiMain                    1000051a f   EbcTest.obj
 0001:00000200       TestSubRoutineSub          10000600 f   EbcTestSub.obj
 0001:00000220       EfiStart                   10000620 f   EbcLib:EbcLib.obj
 0002:00000000       varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b02717 10000800 f   EbcTest.obj
 0002:00000020       varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTestSub$c45af77f3 10000820 f   EbcTestSub.obj
 0003:00000000       CrtThunkBegin              10000a00     EbcLib:EbcLib.obj
 0003:00000004       CrtThunkEnd                10000a04     EbcLib:EbcLib.obj
 0003:00000008       CrtBegin                   10000a08     EbcLib:EbcLib.obj
 0003:00000014       CrtEnd                     10000a14     EbcLib:EbcLib.obj
 0004:00000070       TestStr                    10000c70     EbcTest.obj
 0004:00000078       TestVariable1              10000c78     EbcTest.obj
 0004:00000080       TestSubVariableSub         10000c80     EbcTestSub.obj

 entry point at        0001:00000220

 Static symbols

 0001:00000000       TestSubRoutine2            10000400 f   EbcTest.obj
===============================================================================

--*/
EFI_STATUS
EdbLoadSymbolEntryByIec (
  IN EFI_DEBUGGER_SYMBOL_OBJECT  *Object,
  IN UINTN                       BufferSize,
  IN VOID                        *Buffer
  )
/*++

Routine Description:

  Load symbol entry by Iec

Arguments:

  DebuggerPrivate - EBC Debugger private data structure
  Object          - Symbol file object
  BufferSize      - Symbol file buffer size
  Buffer          - Symbol file buffer

Returns:

  EFI_SUCCESS - add symbol entry successfully

--*/
{
  CHAR8                      *LineBuffer;
  CHAR8                      *FieldBuffer;
  EDB_EBC_MAP_PARSE_STATE    MapParseState;
  EDB_EBC_SYMBOL_PARSE_STATE SymbolParseState;
  CHAR8                      *Name;
  CHAR8                      *ObjName;
  UINTN                      Address;
  EFI_DEBUGGER_SYMBOL_TYPE   Type;


  //
  // Begin to parse the Buffer
  //
  LineBuffer = AsciiStrGetNewTokenLine (Buffer, "\n\r");
  MapParseState = EdbEbcMapParseStateUninitialized;
  //
  // Check each line
  //
  while (LineBuffer != NULL) {
    FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, " ");
    SymbolParseState = EdbEbcSymbolParseStateUninitialized;
    //
    // Init entry value
    //
    Name = NULL;
    ObjName = NULL;
    Address = 0;
    Type = EfiDebuggerSymbolTypeMax;
    //
    // Check each field
    //
    while (FieldBuffer != NULL) {
      if (AsciiStrCmp (FieldBuffer, "") == 0) {
        FieldBuffer = AsciiStrGetNextTokenField (" ");
        continue;
      }
      //
      // check "Address"
      //
      if (AsciiStrCmp (FieldBuffer, "Address") == 0) {
        MapParseState = EdbEbcMapParseStateSymbolStart;
        break;
      }
      //
      // check "Static"
      //
      if (AsciiStrCmp (FieldBuffer, "Static") == 0) {
        MapParseState = EdbEbcMapParseStateStaticFunctionSymbol;
        break;
      }

      if (MapParseState == EdbEbcMapParseStateUninitialized) {
        //
        // Do not parse anything until get "Address" or "Static"
        //
        break;
      }
      if (AsciiStrCmp (FieldBuffer, "entry") == 0) {
        //
        // Skip entry point
        //
        break;
      }

      //
      // Now we start to parse this line for Name, Address, and Object
      //
      switch (SymbolParseState) {
      case  EdbEbcSymbolParseStateUninitialized:
        //
        // Get the Address
        //
        SymbolParseState = EdbEbcSymbolParseStateReadyForName;
        break;
      case  EdbEbcSymbolParseStateReadyForName:
        //
        // Get the Name
        //
        if (AsciiStrnCmp (FieldBuffer, "___safe_se_handler", AsciiStrLen ("___safe_se_handler")) == 0) {
          //
          // skip SeHandler
          //
          MapParseState = EdbEbcMapParseStateSeHandlerSymbol;
          goto ExitFieldParse;
        } else if (AsciiStrnCmp (FieldBuffer, "varbss_init", AsciiStrLen ("varbss_init")) == 0) {
          //
          // check VarbssInit
          //
          MapParseState = EdbEbcMapParseStateVarbssInitSymbol;
//          goto ExitFieldParse;
          Name = FieldBuffer;
          SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
        } else if (AsciiStrnCmp (FieldBuffer, "Crt", AsciiStrLen ("Crt")) == 0) {
          //
          // check Crt
          //
          MapParseState = EdbEbcMapParseStateCrtSymbol;
//          goto ExitFieldParse;
          Name = FieldBuffer;
          SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
        } else {
          //
          // Now, it is normal function
          //
          switch (MapParseState) {
          case EdbEbcMapParseStateSeHandlerSymbol:
            MapParseState = EdbEbcMapParseStateFunctionSymbol;
            break;
          case EdbEbcMapParseStateCrtSymbol:
            MapParseState = EdbEbcMapParseStateVariableSymbol;
            break;
          case EdbEbcMapParseStateFunctionSymbol:
          case EdbEbcMapParseStateVariableSymbol:
          case EdbEbcMapParseStateStaticFunctionSymbol:
            break;
          default:
            ASSERT (FALSE);
            break;
          }
          Name = FieldBuffer;
          SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
        }
        break;
      case  EdbEbcSymbolParseStateReadyForRVA:
        //
        // Get the RVA
        //
        Address = AsciiXtoi (FieldBuffer);
        SymbolParseState = EdbEbcSymbolParseStateReadyForType;
        break;
      case  EdbEbcSymbolParseStateReadyForType:
        //
        // Get the Type. This is optional, only for "f".
        //
        if (AsciiStrCmp (FieldBuffer, "f") == 0) {
          SymbolParseState = EdbEbcSymbolParseStateReadyForObject;
          switch (MapParseState) {
          case EdbEbcMapParseStateFunctionSymbol:
          case EdbEbcMapParseStateVarbssInitSymbol:
            Type = EfiDebuggerSymbolFunction;
            break;
          case EdbEbcMapParseStateStaticFunctionSymbol:
            Type = EfiDebuggerSymbolStaticFunction;
            break;
          default:
            ASSERT (FALSE);
            break;
          }
          break;
        }
        //
        // Else it should be Object.
        // let it bypass here
        //
      case  EdbEbcSymbolParseStateReadyForObject:
        switch (Type) {
        case EfiDebuggerSymbolTypeMax:
          switch (MapParseState) {
          case EdbEbcMapParseStateVariableSymbol:
          case EdbEbcMapParseStateCrtSymbol:
            Type = EfiDebuggerSymbolGlobalVariable;
            break;
          case EdbEbcMapParseStateSeHandlerSymbol:
            //
            // do nothing here
            //
            break;
          default:
            ASSERT (FALSE);
            break;
          }
          break;
        case EfiDebuggerSymbolFunction:
        case EfiDebuggerSymbolStaticFunction:
          break;
        default:
          ASSERT (FALSE);
          break;
        }
        //
        // Get the Object
        //
        ObjName = FieldBuffer;
        SymbolParseState = EdbEbcSymbolParseStateUninitialized;
        break;
      default:
        ASSERT (FALSE);
        break;
      }

      //
      // Get the next field
      //
      FieldBuffer = AsciiStrGetNextTokenField (" ");
    }

    //
    // Add the entry if we get everything.
    //
    if ((Name != NULL) && (Type != EfiDebuggerSymbolTypeMax)) {
      EdbLoadSymbolSingleEntry (Object, Name, ObjName, Address, Type);
    }

ExitFieldParse:
    //
    // Get the next line
    //
    LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
  }

  //
  // Done
  //
  return EFI_SUCCESS;
}

EFI_STATUS
EdbLoadSymbolEntry (
  IN EFI_DEBUGGER_SYMBOL_OBJECT  *Object,
  IN UINTN                       BufferSize,
  IN VOID                        *Buffer
  )
/*++

Routine Description:

  Load symbol entry

Arguments:

  Object          - Symbol file object
  BufferSize      - Symbol file buffer size
  Buffer          - Symbol file buffer

Returns:

  EFI_SUCCESS - add symbol entry successfully

--*/
{
  //
  // MAP file format depends on the compiler (actually linker).
  //
  // It is possible to check the different MAP file format in this routine.
  // Now only IEC is supported.
  //
  return EdbLoadSymbolEntryByIec (Object, BufferSize, Buffer);
}

EFI_DEBUGGER_SYMBOL_OBJECT *
EdbFindSymbolFile (
  IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
  IN CHAR16                      *FileName,
  IN OUT UINTN                   *Index OPTIONAL
  )
/*++

Routine Description:

  Find symbol file by name

Arguments:

  DebuggerPrivate - EBC Debugger private data structure
  FileName        - Symbol file name
  Index           - Symbol file index

Returns:

  Object

--*/
{
  UINTN ObjectIndex;

  //
  // Check each Object
  //
  for (ObjectIndex = 0; ObjectIndex < DebuggerPrivate->DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
    if (StrCmp (FileName, DebuggerPrivate->DebuggerSymbolContext.Object[ObjectIndex].Name) == 0) {
      //
      // Name match, found it
      //
      if (Index != NULL) {
        *Index = ObjectIndex;
      }
      return &DebuggerPrivate->DebuggerSymbolContext.Object[ObjectIndex];
    }
  }

  //
  // Not found
  //
  return NULL;
}

UINTN
EbdFindSymbolAddress (
  IN UINTN                       Address,
  IN EDB_MATCH_SYMBOL_TYPE       Type,
  OUT EFI_DEBUGGER_SYMBOL_OBJECT **RetObject,
  OUT EFI_DEBUGGER_SYMBOL_ENTRY  **RetEntry
  )
/*++

Routine Description:

  Find symbol by address

Arguments:

  Address         - Symbol address
  Type            - Search type
  RetObject       - Symbol object
  RetEntry        - Symbol entry

Returns:

  Nearest symbol address

--*/
{
  UINTN                      Index;
  UINTN                      SubIndex;
  UINTN                      CandidateLowerAddress;
  UINTN                      CandidateUpperAddress;
  EFI_DEBUGGER_SYMBOL_OBJECT *Object;
  EFI_DEBUGGER_SYMBOL_ENTRY  *Entry;
  EFI_DEBUGGER_SYMBOL_ENTRY  *LowEntry;
  EFI_DEBUGGER_SYMBOL_ENTRY  *UpperEntry;
  EFI_DEBUGGER_SYMBOL_OBJECT *LowObject;
  EFI_DEBUGGER_SYMBOL_OBJECT *UpperObject;

  if ((Type < 0) || (Type >= EdbMatchSymbolTypeMax)) {
    return 0;
  }

  //
  // Init
  //
  CandidateLowerAddress = 0;
  CandidateUpperAddress = (UINTN)-1;
  LowEntry = NULL;
  UpperEntry = NULL;
  LowObject = NULL;
  UpperObject = NULL;

  //
  // Go through each object
  //
  Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
  for (Index = 0; Index < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; Index++, Object++) {
    if (Object->EntryCount == 0) {
      continue;
    }
    //
    // Go through each entry
    //
    Entry = Object->Entry;
    for (SubIndex = 0; SubIndex < Object->EntryCount; SubIndex++, Entry++) {
      if (Address != Entry->RVA + Object->BaseAddress) {
        //
        // Check for nearest address
        //
        if (Address > Entry->RVA + Object->BaseAddress) {
          //
          // Record it if Current RVA < Address
          //
          if (CandidateLowerAddress < Entry->RVA + Object->BaseAddress) {
            CandidateLowerAddress = Entry->RVA + Object->BaseAddress;
            LowEntry = Entry;
            LowObject = Object;
          }
        } else {
          //
          // Record it if Current RVA > Address
          //
          if (CandidateUpperAddress > Entry->RVA + Object->BaseAddress) {
            CandidateUpperAddress = Entry->RVA + Object->BaseAddress;
            UpperEntry = Entry;
            UpperObject = Object;
          }
        }
        continue;
      }
      //
      // address match, return directly
      //
      *RetEntry = Entry;
      *RetObject = Object;
      return Address;
    }
  }

  //
  // No Match, provide latest symbol
  //

  if ((Address - CandidateLowerAddress) < EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE) {
    //
    // Check for lower address
    //
    if (((Type == EdbMatchSymbolTypeNearestAddress) &&
         ((CandidateUpperAddress - Address) > (Address - CandidateLowerAddress))) ||
        (Type == EdbMatchSymbolTypeLowerAddress)) {
      //
      // return nearest lower address
      //
      *RetEntry = LowEntry;
      *RetObject = LowObject;
      return CandidateLowerAddress;
    }
  }

  if ((CandidateUpperAddress - Address) < EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE) {
    //
    // Check for upper address
    //
    if (((Type == EdbMatchSymbolTypeNearestAddress) &&
         ((CandidateUpperAddress - Address) < (Address - CandidateLowerAddress))) ||
        (Type == EdbMatchSymbolTypeUpperAddress)) {
      //
      // return nearest upper address
      //
      *RetEntry = UpperEntry;
      *RetObject = UpperObject;
      return CandidateUpperAddress;
    }
  }

  //
  // No match and nearest one, return NULL
  //
  return 0;
}

EFI_STATUS
EdbUnloadSymbol (
  IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
  IN CHAR16                      *FileName
  )
/*++

Routine Description:

  Unload symbol file by name

Arguments:

  DebuggerPrivate - EBC Debugger private data structure
  FileName        - Symbol file name

Returns:

  EFI_SUCCESS - unload symbol successfully

--*/
{
  EFI_DEBUGGER_SYMBOL_OBJECT *Object;
  UINTN                      ObjectIndex;
  UINTN                      Index;
  EFI_DEBUGGER_SYMBOL_ENTRY  *OldEntry;
  UINTN                      OldEntryCount;
  UINTN                      MaxEntryCount;
  VOID                       **OldSourceBuffer;

  //
  // Find Symbol
  //
  Object = EdbFindSymbolFile (DebuggerPrivate, FileName, &ObjectIndex);
  if (Object == NULL) {
    EDBPrint (L"SymbolFile is not loaded!\n");
    return EFI_DEBUG_CONTINUE;
  }

  //
  // Record old data
  //
  Object = DebuggerPrivate->DebuggerSymbolContext.Object;
  OldEntry = Object->Entry;
  OldSourceBuffer = Object->SourceBuffer;
  MaxEntryCount = Object->MaxEntryCount;
  OldEntryCount = Object->EntryCount;

  //
  // Remove the matched Object
  //
  for (Index = ObjectIndex; Index < DebuggerPrivate->DebuggerSymbolContext.ObjectCount - 1; Index++) {
    CopyMem (&Object[Index], &Object[Index + 1], sizeof(EFI_DEBUGGER_SYMBOL_OBJECT));
  }
  ZeroMem (&Object[Index], sizeof(Object[Index]));

  //
  // Move old data to new place
  //
  Object[Index].Entry = OldEntry;
  Object[Index].SourceBuffer = OldSourceBuffer;
  Object[Index].MaxEntryCount = MaxEntryCount;
  DebuggerPrivate->DebuggerSymbolContext.ObjectCount --;

  //
  // Clean old entry data
  //
  for (Index = 0; Index < OldEntryCount; Index++) {
    ZeroMem (&OldEntry[Index], sizeof(OldEntry[Index]));
  }

  //
  // Free OldSourceBuffer
  //
  for (Index = 0; OldSourceBuffer[Index] != NULL; Index++) {
    gBS->FreePool (OldSourceBuffer[Index]);
    OldSourceBuffer[Index] = NULL;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EdbLoadSymbol (
  IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
  IN CHAR16                      *FileName,
  IN UINTN                       BufferSize,
  IN VOID                        *Buffer
  )
/*++

Routine Description:

  Load symbol file by name

Arguments:

  DebuggerPrivate - EBC Debugger private data structure
  FileName        - Symbol file name
  BufferSize      - Symbol file buffer size
  Buffer          - Symbol file buffer

Returns:

  EFI_SUCCESS - load symbol successfully

--*/
{
  EFI_DEBUGGER_SYMBOL_OBJECT *Object;
  EFI_STATUS                 Status;

  //
  // Check duplicated File
  //
  Object = EdbFindSymbolFile (DebuggerPrivate, FileName, NULL);
  if (Object != NULL) {
    Status = EdbUnloadSymbol (DebuggerPrivate, FileName);
    if (EFI_ERROR(Status)) {
      DEBUG ((DEBUG_ERROR, "Unload Duplicated Symbol File Error!\n"));
      return Status;
    }
  }

  //
  // Check Count VS MaxCount
  //
  if (DebuggerPrivate->DebuggerSymbolContext.ObjectCount >= DebuggerPrivate->DebuggerSymbolContext.MaxObjectCount) {
    //
    // reallocate
    // TBD
    //
    return EFI_OUT_OF_RESOURCES;
  }

  Object = &DebuggerPrivate->DebuggerSymbolContext.Object[DebuggerPrivate->DebuggerSymbolContext.ObjectCount];

  //
  // Init Object
  //
  Object->EntryCount = 0;
  Object->MaxEntryCount = EFI_DEBUGGER_SYMBOL_ENTRY_MAX;

  //
  // Load SymbolEntry
  //
  DEBUG ((DEBUG_ERROR, "Symbol File: %s\n", FileName));
  Status = EdbLoadSymbolEntry (Object, BufferSize, Buffer);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Fill Object value
  //
  StrnCpyS (Object->Name, sizeof(Object->Name) / sizeof(CHAR16),
            FileName, (sizeof(Object->Name) / sizeof(CHAR16)) - 1);
  Object->BaseAddress = 0;

  //
  // Increase the object count
  //
  DebuggerPrivate->DebuggerSymbolContext.ObjectCount ++;

  return EFI_SUCCESS;
}

CHAR8 *
GetPdbPath (
  VOID *ImageBase
  )
/*++

Routine Description:

  Located PDB path name in PE image

Arguments:

  ImageBase - base of PE to search

Returns:

  Pointer into image at offset of PDB file name if PDB file name is found,
  Otherwise a pointer to an empty string.

--*/
{
  CHAR8                           *PdbPath;
  UINT32                          DirCount;
  EFI_IMAGE_DOS_HEADER            *DosHdr;
  EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
  EFI_IMAGE_OPTIONAL_HEADER32     *OptionalHdr32;
  EFI_IMAGE_OPTIONAL_HEADER64     *OptionalHdr64;
  EFI_IMAGE_DATA_DIRECTORY        *DirectoryEntry;
  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
  VOID                            *CodeViewEntryPointer;

  //
  // Init value
  //
  CodeViewEntryPointer  = NULL;
  PdbPath               = NULL;
  DosHdr                = ImageBase;

  //
  // Check magic
  //
  if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
    return NULL;
  }
  NtHdr           = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) DosHdr + DosHdr->e_lfanew);
  //
  // Check Machine, filter for EBC
  //
  if (NtHdr->Pe32.FileHeader.Machine != EFI_IMAGE_MACHINE_EBC) {
    //
    // If not EBC, return NULL
    //
    return NULL;
  }

  //
  // Get DirectoryEntry
  // EBC spec says PE32+, but implementation uses PE32. So check dynamically here.
  //
  if (NtHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    OptionalHdr32   = (VOID *) &NtHdr->Pe32.OptionalHeader;
    DirectoryEntry  = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
  } else if (NtHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
    OptionalHdr64   = (VOID *) &NtHdr->Pe32Plus.OptionalHeader;
    DirectoryEntry  = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
  } else {
    return NULL;
  }
  if (DirectoryEntry->VirtualAddress == 0) {
    return NULL;
  }
  //
  // Go through DirectoryEntry
  //
  for (DirCount = 0;
       (DirCount < DirectoryEntry->Size / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) && CodeViewEntryPointer == NULL;
       DirCount++
      ) {
    DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (DirectoryEntry->VirtualAddress + (UINTN) ImageBase + DirCount * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
    if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
      //
      // Match DebugEntry, only CODEVIEW_SIGNATURE_NB10 and CODEVIEW_SIGNATURE_RSDS are supported.
      //
      CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + (UINTN) ImageBase);
      switch (*(UINT32 *) CodeViewEntryPointer) {
      case CODEVIEW_SIGNATURE_NB10:
        PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
        break;
      case CODEVIEW_SIGNATURE_RSDS:
        PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
        break;
      default:
        break;
      }
    }
  }

  //
  // Done successfully
  //
  return PdbPath;
}

BOOLEAN
MatchPdbAndMap (
  IN CHAR8   *PdbFileName,
  IN CHAR16  *MapFileName
  )
/*++

Routine Description:

  Check whether PDB file and MAP file have same name

Arguments:

  PdbFileName - PDB file name
  MapFileName - MAP file name

Returns:

  TRUE  - PDB and MAP file name match
  FALSE - PDB and MAP file name not match

--*/
{
  UINTN   PdbNameSize;
  UINTN   MapNameSize;
  CHAR8   *PurePdbFileName;
  UINTN   Index;

  //
  // remove dir name
  //
  PurePdbFileName = PdbFileName;
  for (Index = 0; PdbFileName[Index] != 0; Index++) {
    if (PdbFileName[Index] == '\\') {
      PurePdbFileName = &PdbFileName[Index + 1];
    }
  }
  PdbFileName = PurePdbFileName;

  //
  // get size
  //
  PdbNameSize = AsciiStrLen (PdbFileName);
  MapNameSize = StrLen (MapFileName);

  if (PdbNameSize != MapNameSize) {
    return FALSE;
  }

  //
  // check the name
  //
  for (Index = 0; Index < MapNameSize - 4; Index++) {
    if ((PdbFileName[Index] | 0x20) != (MapFileName[Index] | 0x20)) {
      return FALSE;
    }
  }

  return TRUE;
}

//
// BUGBUG: work-around start
//
typedef struct {
  EFI_DEBUG_IMAGE_INFO  *EfiDebugImageInfoTable;
  volatile UINT32       UpdateStatus;
  UINT32                TableSize;
} EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD;

EFI_DEBUG_IMAGE_INFO_TABLE_HEADER  mDebugImageInfoTableHeader;

VOID
EdbFixDebugImageInfoTable (
  IN OUT EFI_DEBUG_IMAGE_INFO_TABLE_HEADER **DebugImageInfoTableHeader
  )
/*
For compatibility consideration, we handle 2 cases:

1) IA32:
  Old:                          New:
  +------------------------+    +------------------------+
  | EfiDebugImageInfoTable |    | UpdateStatus           |
  +------------------------+    +------------------------+
  | UpdateStatus           |    | TableSize              |
  +------------------------+    +------------------------+
  | TableSize              |    | EfiDebugImageInfoTable |
  +------------------------+    +------------------------+

2) X64 and IPF:
  Old:                          New:
  +------------------------+    +------------------------+
  | EfiDebugImageInfoTable |    | UpdateStatus           |
  |                        |    +------------------------+
  |                        |    | TableSize              |
  +------------------------+    +------------------------+
  | UpdateStatus           |    | EfiDebugImageInfoTable |
  +------------------------+    |                        |
  | TableSize              |    |                        |
  +------------------------+    +------------------------+

*/
{
  mDebugImageInfoTableHeader.EfiDebugImageInfoTable = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->EfiDebugImageInfoTable;
  mDebugImageInfoTableHeader.UpdateStatus           = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->UpdateStatus;
  mDebugImageInfoTableHeader.TableSize              = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->TableSize;

  if ((*DebugImageInfoTableHeader)->UpdateStatus > 3) {
    *DebugImageInfoTableHeader = &mDebugImageInfoTableHeader;
    return ;
  }

  if ((*DebugImageInfoTableHeader)->TableSize % (EFI_PAGE_SIZE / (sizeof (VOID *))) != 0) {
    *DebugImageInfoTableHeader = &mDebugImageInfoTableHeader;
    return ;
  }

  return ;
}
//
// BUGBUG: work-around end
//

EFI_STATUS
EdbPatchSymbolRVA (
  IN EFI_DEBUGGER_PRIVATE_DATA     *DebuggerPrivate,
  IN CHAR16                        *FileName,
  IN EDB_EBC_IMAGE_RVA_SEARCH_TYPE SearchType
  )
/*++

Routine Description:

  Patch symbol RVA

Arguments:

  DebuggerPrivate - EBC Debugger private data structure
  FileName        - Symbol file name
  SearchType      - Search type for Object

Returns:

  EFI_SUCCESS   - Patch symbol RVA successfully
  EFI_NOT_FOUND - Symbol RVA base not found

--*/
{
  EFI_STATUS            Status;
  UINTN                 ImageNumber;
  EFI_DEBUG_IMAGE_INFO  *ImageTable;
  CHAR8                 *PdbPath;
  VOID                  *ImageBase;
  VOID                  *CandidateImageBase;
  EFI_DEBUGGER_SYMBOL_OBJECT *Object;

  if (SearchType < 0 || SearchType >= EdbEbcImageRvaSearchTypeMax) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Get the related object
  //
  Object = EdbFindSymbolFile (DebuggerPrivate, FileName, NULL);
  if (Object == NULL) {
    return EFI_NOT_FOUND;
  }

  //
  // Try again to get DebugImageInfoTable
  //
  if (mDebuggerPrivate.DebugImageInfoTableHeader == NULL) {
    Status = EfiGetSystemConfigurationTable (
               &gEfiDebugImageInfoTableGuid,
               (VOID **) &mDebuggerPrivate.DebugImageInfoTableHeader
               );
    if (EFI_ERROR (Status)) {
      EDBPrint (L"DebugImageInfoTable not found!\n");
      return Status;
    }
  }
  DEBUG ((DEBUG_ERROR, "DebugImageInfoTableHeader: %x\n", mDebuggerPrivate.DebugImageInfoTableHeader));

  //
  // BUGBUG: work-around start
  //
  EdbFixDebugImageInfoTable (&mDebuggerPrivate.DebugImageInfoTableHeader);
  //
  // BUGBUG: work-around end
  //

  //
  // Go through DebugImageInfoTable for each Image
  //
  CandidateImageBase = NULL;
  ImageTable  = mDebuggerPrivate.DebugImageInfoTableHeader->EfiDebugImageInfoTable;
  for (ImageNumber = 0; ImageNumber < mDebuggerPrivate.DebugImageInfoTableHeader->TableSize; ImageNumber++) {
    if (ImageTable[ImageNumber].NormalImage == NULL) {
      continue;
    }
    ImageBase = ImageTable[ImageNumber].NormalImage->LoadedImageProtocolInstance->ImageBase;
    //
    // Get PDB path
    //
    PdbPath   = GetPdbPath (ImageBase);
    if (PdbPath == NULL) {
      continue;
    }
    //
    // Check PDB name
    //
    if (!MatchPdbAndMap (PdbPath, FileName)) {
      continue;
    }
    DEBUG ((DEBUG_ERROR, "ImageBase: %x\n", ImageBase));

    //
    // Check SearchType
    //
    if (SearchType == EdbEbcImageRvaSearchTypeAny || SearchType == EdbEbcImageRvaSearchTypeFirst) {
      //
      // Assign base address and return
      //
      Object->BaseAddress = (UINTN)ImageBase;
      return EFI_SUCCESS;
    }

    //
    // Get CandidateImageBase for EdbEbcImageRvaSearchTypeLast
    //
    CandidateImageBase = ImageBase;
  }

  //
  // Check EdbEbcImageRvaSearchTypeLast
  //
  if (SearchType == EdbEbcImageRvaSearchTypeLast) {
    if (CandidateImageBase == NULL) {
      return EFI_NOT_FOUND;
    }
    //
    // Assign base address and return
    //
    Object->BaseAddress = (UINTN)CandidateImageBase;
    return EFI_SUCCESS;
  }

  //
  // No match
  //
  return EFI_NOT_FOUND;
}

BOOLEAN
MatchObjAndCod (
  IN CHAR8   *ObjFileName,
  IN CHAR16  *CodFileName
  )
/*++

Routine Description:

  Check whether OBJ file and COD file have same name

Arguments:

  ObjFileName - OBJ file name
  CodFileName - COD file name

Returns:

  TRUE  - OBJ and COD file name match
  FALSE - OBJ and COD file name not match

--*/
{
  UINTN   ObjNameSize;
  UINTN   CodNameSize;
  CHAR8   *PureObjFileName;
  UINTN   Index;

  //
  // remove library name
  //
  PureObjFileName = ObjFileName;
  for (Index = 0; ObjFileName[Index] != 0; Index++) {
    if (ObjFileName[Index] == ':') {
      PureObjFileName = &ObjFileName[Index + 1];
      break;
    }
  }
  ObjFileName = PureObjFileName;

  //
  // get size
  //
  ObjNameSize = AsciiStrLen (ObjFileName);
  CodNameSize = StrLen (CodFileName);

  if (ObjNameSize != CodNameSize) {
    return FALSE;
  }

  //
  // check the name
  //
  for (Index = 0; Index < CodNameSize - 4; Index++) {
    if ((ObjFileName[Index] | 0x20) != (CodFileName[Index] | 0x20)) {
      return FALSE;
    }
  }

  return TRUE;
}

typedef enum {
  EdbEbcCodParseStateUninitialized,
  EdbEbcCodParseStateSymbolInitialized,
  EdbEbcCodParseStateSymbolStart,
  EdbEbcCodParseStateSymbolEnd,
  EdbEbcCodParseStateMax,
} EDB_EBC_COD_PARSE_STATE;

/*++

  The following code depends on the COD file generated by IEC compiler.

  Sample as follows: EbcTest.cod
===============================================================================
; -- Machine type EFI
; mark_description "Intel(R) C Compiler for EFI Byte Code, Version 1.2 Build 20040123";
; mark_description "XXX";
;ident "Intel(R) C Compiler for EFI Byte Code, Version 1.2 Build 20040123"
;ident "XXX"
    .686P
    .387
_TEXT   SEGMENT PARA PUBLIC USE32 'CODE'
_TEXT   ENDS
_DATA   SEGMENT PARA PUBLIC USE32 'DATA'
    ALIGN 010H
_DATA   ENDS
_BSS    SEGMENT PARA PUBLIC USE32 'BSS'
    ALIGN 010H
_BSS    ENDS
_VARBSS SEGMENT PARA PUBLIC USE32 'BSS'
    ALIGN 010H
_VARBSS ENDS
    ASSUME  CS:FLAT,DS:FLAT,SS:FLAT
_DATA   SEGMENT PARA PUBLIC USE32 'DATA'
TestVariable2   DD 000000003H,000000000H    ; u64
_DATA   ENDS
_DATA   SEGMENT PARA PUBLIC USE32 'DATA'
_DATA   ENDS
_TEXT   SEGMENT PARA PUBLIC USE32 'CODE'
; -- Begin  EfiMain
; mark_begin;
    PUBLIC   EfiMain
EfiMain  PROC NEAR
$B3$1:; 11a
$LN45:

;117 ; {

  0011a 60 00 70 80         MOVqw     R0, R0(+0,-112)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:117
$LN46:

;118 ;   UINT16 test = 0x1234;

  0011e 77 58 58 00 34
        12                  MOVIww    @R0(+0,+88), +4660      ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:118
$LN47:

;121 ;   EFI_STATUS  Status;
;121 ;
;121 ;   SystemTable->ConOut->OutputString (

  00124 72 87 01 12         MOVnw     R7, @R0(+1,+128)        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:121
  00128 72 f7 85 21         MOVnw     R7, @R7(+5,+24)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:121
$LN48:

;122 ;                          SystemTable->ConOut,

  0012c 72 84 01 12         MOVnw     R4, @R0(+1,+128)        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
  00130 72 c8 85 21         MOVnw     @R0, @R4(+5,+24)        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
  00134 b9 34 00 00 00
        00                  MOVreld   R4, __STRING$1          ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
  0013a b2 48 01 10         MOVnw     @R0(+1,+0), R4          ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
  0013e 83 2f 01 00 00
        10                  CALLEX    @R7(+1,+0)              ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
$B3$2:; 144
$LN49:

;125 ;                          L"Hello EBC Test!\n\r"
;125 ;                          );
;125 ;   EFI_BREAKPOINT ();

  00144 00 03               BREAK     3                       ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:125
$B3$3:; 146
$LN50:

;126 ;   TestVariable1 = 6;

  00146 b9 37 00 00 00
        00                  MOVreld   R7, TestVariable1       ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:126
  0014c 78 0f 06 00         MOVInw    @R7, (0,6)              ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:126
$LN51:

;127 ;   TestSubRoutineSub (1, 5);

  00150 78 08 01 00         MOVInw    @R0, (0,1)              ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:127
  00154 78 48 01 10 05
        00                  MOVInw    @R0(1,0), (0,5)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:127
  0015a 83 10 00 00 00
        00                  CALL      TestSubRoutineSub       ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:127
$B3$4:; 160
$LN52:

;129 ;
;129 ;   SystemTable->ConOut->OutputString (

  00160 72 87 01 12         MOVnw     R7, @R0(+1,+128)        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:129
  00164 72 f7 85 21         MOVnw     R7, @R7(+5,+24)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:129
$LN53:

;130 ;                          SystemTable->ConOut,

  00168 72 84 01 12         MOVnw     R4, @R0(+1,+128)        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:130
  0016c 72 c8 85 21         MOVnw     @R0, @R4(+5,+24)        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:130
$LN54:

;131 ;                          TestStr

  00170 b9 34 00 00 00
        00                  MOVreld   R4, TestStr             ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:131
  00176 b2 c8 01 10         MOVnw     @R0(+1, +0), @R4        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:131
  0017a 83 2f 01 00 00
        10                  CALLEX    @R7(+1,+0)              ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:131
$B3$5:; 180
$LN55:

;134 ;                          );
;134 ;
;134 ;   test = test & 0xFF;

  00180 de 88 58 00 58
        00                  MOVww     @R0(+0,+88), @R0(+0,+88) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:134
$LN56:

;139 ;   if (test != 0x34) {
;139 ; //    EFI_BREAKPOINT ();
;139 ;   }
;139 ;
;139 ;   Status = TestSubRoutine (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

  00186 78 08 01 00         MOVInw    @R0, (0,1)              ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
  0018a 78 48 01 10 02
        00                  MOVInw    @R0(1,0), (0,2)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
  00190 78 48 02 10 03
        00                  MOVInw    @R0(2,0), (0,3)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
  00196 78 48 03 10 04
        00                  MOVInw    @R0(3,0), (0,4)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
  0019c 78 48 04 20 05
        00                  MOVInw    @R0(4,0), (0,5)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
  001a2 78 48 05 20 06
        00                  MOVInw    @R0(5,0), (0,6)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
  001a8 78 48 06 20 07
        00                  MOVInw    @R0(6,0), (0,7)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
  001ae 78 48 07 20 08
        00                  MOVInw    @R0(7,0), (0,8)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
  001b4 78 48 08 20 09
        00                  MOVInw    @R0(8,0), (0,9)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
  001ba 78 48 09 20 0a
        00                  MOVInw    @R0(9,0), (0,10)        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
  001c0 83 10 00 00 00
        00                  CALL      TestSubRoutine          ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
$B3$10:; 1c6
  001c6 b2 78 60 00         MOVnw     @R0(+0,+96), R7         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
$B3$6:; 1ca
$LN57:
  001ca f2 88 50 00 60
        00                  MOVnw     @R0(+0,+80), @R0(+0,+96) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
$LN58:

;141 ;
;141 ;   SystemTable->ConOut->OutputString (

  001d0 72 87 01 12         MOVnw     R7, @R0(+1,+128)        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:141
  001d4 72 f7 85 21         MOVnw     R7, @R7(+5,+24)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:141
$LN59:

;142 ;                          SystemTable->ConOut,

  001d8 72 84 01 12         MOVnw     R4, @R0(+1,+128)        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
  001dc 72 c8 85 21         MOVnw     @R0, @R4(+5,+24)        ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
  001e0 b9 34 00 00 00
        00                  MOVreld   R4, __STRING$2          ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
  001e6 b2 48 01 10         MOVnw     @R0(+1,+0), R4          ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
  001ea 83 2f 01 00 00
        10                  CALLEX    @R7(+1,+0)              ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
$B3$7:; 1f0
$LN60:

;146 ;                          L"Goodbye EBC Test!\n\r"
;146 ;                          );
;146 ;
;146 ;   return Status;

  001f0 72 87 50 00         MOVnw     R7, @R0(+0,+80)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:146
  001f4 60 00 70 00         MOVqw     R0, R0(+0,+112)         ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:146
  001f8 04 00               RET                               ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:146
; mark_end;
EfiMain ENDP
_TEXT   ENDS
_DATA   SEGMENT PARA PUBLIC USE32 'DATA'
    DB 3 DUP (0)    ; pad
__STRING$2  DW 71   ; u16
    DW 111  ; u16
    DW 111  ; u16
    DW 100  ; u16
    DW 98   ; u16
    DW 121  ; u16
    DW 101  ; u16
    DW 32   ; u16
    DW 69   ; u16
    DW 66   ; u16
    DW 67   ; u16
    DW 32   ; u16
    DW 84   ; u16
    DW 101  ; u16
    DW 115  ; u16
    DW 116  ; u16
    DW 33   ; u16
    DW 10   ; u16
    DW 13   ; u16
    DW 0    ; u16
__STRING$1  DW 72   ; u16
    DW 101  ; u16
    DW 108  ; u16
    DW 108  ; u16
    DW 111  ; u16
    DW 32   ; u16
    DW 69   ; u16
    DW 66   ; u16
    DW 67   ; u16
    DW 32   ; u16
    DW 84   ; u16
    DW 101  ; u16
    DW 115  ; u16
    DW 116  ; u16
    DW 33   ; u16
    DW 10   ; u16
    DW 13   ; u16
    DW 0    ; u16
_DATA   ENDS
_DATA   SEGMENT PARA PUBLIC USE32 'DATA'
_DATA   ENDS
; -- End  EfiMain
_DATA   SEGMENT PARA PUBLIC USE32 'DATA'
__STRING$0  DW 55   ; u16
    DW 56   ; u16
    DW 57   ; u16
    DW 52   ; u16
    DW 53   ; u16
    DW 54   ; u16
    DW 49   ; u16
    DW 50   ; u16
    DW 51   ; u16
    DW 13   ; u16
    DW 10   ; u16
    DW 0    ; u16
_DATA   ENDS
_VARBSS SEGMENT PARA PUBLIC USE32 'BSS'
    PUBLIC TestStr
TestStr DD 2 DUP (?)    ; pad
    PUBLIC TestVariable1
TestVariable1   DD 2 DUP (?)    ; pad
_VARBSS ENDS
_VARBSS_INIT    SEGMENT DWORD PUBLIC USE32 'CODE'
; -- Begin varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2
    PUBLIC    varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2
varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2 PROC NEAR
  00000 b9 34 00 00 00
        00                  MOVreld   R4, TestStr
  00006 b9 35 00 00 00
        00                  MOVreld   R5, __STRING$0
  0000c 33 5c               MOVnd     @R4, R5
  0000e b9 34 00 00 00
        00                  MOVreld   R4, TestVariable1
  00014 78 0c 04 00         MOVInw    @R4, (0,4)
  00018 04 00               RET
; -- End varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2
_VARBSS_INIT    ENDS
_DATA   SEGMENT PARA PUBLIC USE32 'DATA'
_DATA   ENDS
EXTRN   TestSubRoutineSub:PROC
    END

===============================================================================

--*/
CHAR8 *
EdbLoadCodBySymbolByIec (
  IN CHAR8                       *Name,
  IN VOID                        *Buffer,
  IN UINTN                       BufferSize,
  OUT UINTN                      *CodeBufferSize,
  OUT UINTN                      *FuncOffset
  )
/*++

Routine Description:

  Load code by symbol by Iec

Arguments:

  Name            - Symbol file name
  BufferSize      - Symbol file buffer size
  Buffer          - Symbol file buffer
  CodeBufferSize  - Code buffer size
  FuncOffset      - Code funcion offset

Returns:

  CodeBuffer

--*/
{
  CHAR8                      *LineBuffer;
  CHAR8                      *FieldBuffer;
  VOID                       *BufferStart;
  VOID                       *BufferEnd;
  UINTN                      Offset;
  EDB_EBC_COD_PARSE_STATE    CodParseState;
  CHAR8                      Char[2] = {9, 0};

  //
  // Init
  //
  LineBuffer = AsciiStrGetNewTokenLine (Buffer, "\n\r");
  Offset = (UINTN)-1;
  BufferStart = NULL;
  BufferEnd = NULL;
  CodParseState = EdbEbcCodParseStateUninitialized;

  //
  // Check each line
  //
  while (LineBuffer != NULL) {
    switch (CodParseState) {
    case EdbEbcCodParseStateUninitialized:
      //
      // check mark_begin, begin to check line after this match
      //
      if (AsciiStrCmp (LineBuffer, "; mark_begin;") == 0) {
        CodParseState = EdbEbcCodParseStateSymbolInitialized;
      }
      LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
      PatchForAsciiStrTokenBefore (LineBuffer, '\n');
      break;

    case EdbEbcCodParseStateSymbolInitialized:
      //
      // check mark_end, not check line after this match
      //
      if (AsciiStrCmp (LineBuffer, "; mark_end;") == 0) {
        CodParseState = EdbEbcCodParseStateUninitialized;
        LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
        PatchForAsciiStrTokenBefore (LineBuffer, '\n');
        break;
      }

      //
      // not check this line if the first char is as follows
      //
      if ((*LineBuffer == 0)   ||
          (*LineBuffer == '$') ||
          (*LineBuffer == ';') ||
          (*LineBuffer == '_') ||
          (*LineBuffer == ' ')) {
        LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
        PatchForAsciiStrTokenBefore (LineBuffer, '\n');
        break;
      }

      //
      // get function name, function name is followed by char 0x09.
      //
      FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, Char);
      ASSERT (FieldBuffer != NULL);
      if (AsciiStriCmp (FieldBuffer, Name) == 0) {
        BufferStart = FieldBuffer;
        CodParseState = EdbEbcCodParseStateSymbolStart;
      }
      PatchForAsciiStrTokenAfter (FieldBuffer, 0x9);

      //
      // Get next line
      //
      LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
      PatchForAsciiStrTokenBefore (LineBuffer, '\n');
      break;

    case EdbEbcCodParseStateSymbolStart:
      //
      // check mark_end, if this match, means the function is found successfully.
      //
      if (AsciiStrCmp (LineBuffer, "; mark_end;") == 0) {
        CodParseState = EdbEbcCodParseStateSymbolEnd;
        //
        // prepare CodeBufferSize, FuncOffset, and FuncStart to return
        //
        BufferEnd = LineBuffer + sizeof("; mark_end;") - 1;
        *CodeBufferSize = (UINTN)BufferEnd - (UINTN)BufferStart;
        *FuncOffset = Offset;
        PatchForAsciiStrTokenAfter (LineBuffer, '\n');
        return BufferStart;
      }

      //
      // Get function offset
      //
      if ((Offset == (UINTN)-1) &&
          (*LineBuffer == ' ')) {
        FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 2, " ");
        Offset = AsciiXtoi (FieldBuffer);
        PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
      }

      //
      // Get next line
      //
      LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
      PatchForAsciiStrTokenBefore (LineBuffer, '\n');
      break;

    case EdbEbcCodParseStateSymbolEnd:
      break;

    default:
      break;
    }
  }

  //
  // no function found
  //
  return NULL;
}

CHAR8 *
EdbLoadCodBySymbol (
  IN CHAR8                       *Name,
  IN VOID                        *Buffer,
  IN UINTN                       BufferSize,
  OUT UINTN                      *CodeBufferSize,
  OUT UINTN                      *FuncOffset
  )
/*++

Routine Description:

  Load code by symbol

Arguments:

  Name            - Symbol file name
  BufferSize      - Symbol file buffer size
  Buffer          - Symbol file buffer
  CodeBufferSize  - Code buffer size
  FuncOffset      - Code funcion offset

Returns:

  CodeBuffer

--*/
{
  //
  // COD file format depends on the compiler.
  //
  // It is possible to check the different COD file format in this routine.
  // Now only IEC is supported.
  //
  return EdbLoadCodBySymbolByIec (Name, Buffer, BufferSize, CodeBufferSize, FuncOffset);
}

VOID *
EdbFindCodeFromObject (
  IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
  IN EFI_DEBUGGER_SYMBOL_OBJECT  *Object,
  IN CHAR16                      *FileName
  )
/*++

Routine Description:

  Find code from object

Arguments:

  Object          - Symbol object
  FileName        - File name

Returns:

  CodeBuffer

--*/
{
  UINTN                      EntryIndex;

  //
  // Go througn each Entry in this Object
  //
  for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
    //
    // This check is for Function only
    //
    if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
        (Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
      continue;
    }
    //
    // Skip match varbss_init function, because they has no source code
    //
    if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
      continue;
    }
    //
    // check the name
    //
    if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
      continue;
    }
    //
    // found it, return source buffer
    //
    if (Object->Entry[EntryIndex].CodBuffer != NULL) {
      return Object->Entry[EntryIndex].SourceBuffer;
    }
  }

  //
  // not found
  //
  return NULL;
}

EFI_STATUS
EdbLoadCode (
  IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
  IN CHAR16                      *MapFileName,
  IN CHAR16                      *FileName,
  IN UINTN                       BufferSize,
  IN VOID                        *Buffer
  )
/*++

Routine Description:

  Load code

Arguments:

  DebuggerPrivate - EBC Debugger private data structure
  MapFileName     - Symbol file name
  FileName        - Code file name
  BufferSize      - Code file buffer size
  Buffer          - Code file buffer

Returns:

  EFI_SUCCESS - Code loaded successfully

--*/
{
  EFI_DEBUGGER_SYMBOL_OBJECT *Object;
  UINTN                      ObjectIndex;
  UINTN                      EntryIndex;
  VOID                       *SourceBuffer;
  EFI_STATUS                 Status;

  //
  // Find Symbol
  //
  Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, &ObjectIndex);
  if (Object == NULL) {
    EDBPrint (L"SymbolFile is not loaded!\n");
    return EFI_NOT_FOUND;
  } else {
    //
    // Check duplicated File
    //
    SourceBuffer = EdbFindCodeFromObject (DebuggerPrivate, Object, FileName);
    if (SourceBuffer != NULL) {
      //
      // unnload duplicated code
      //
      Status = EdbUnloadCode (DebuggerPrivate, MapFileName, FileName, &SourceBuffer);
      if (EFI_ERROR(Status)) {
        DEBUG ((DEBUG_ERROR, "Unload Duplicated Code File Error!\n"));
        return Status;
      }
      Status = EdbDeleteCodeBuffer (DebuggerPrivate, MapFileName, FileName, SourceBuffer);
      if (EFI_ERROR(Status)) {
        DEBUG ((DEBUG_ERROR, "Delete Duplicated Code File Error!\n"));
        return Status;
      }
    }
  }

  //
  // Go through each SymbolEntry
  //
  for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
    //
    // load symbol for function only
    //
    if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
        (Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
      continue;
    }
    //
    // skip varbss_init
    //
    if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
      continue;
    }
    //
    // Check the name
    //
    if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
      continue;
    }
    //
    // load code for this symbol
    //
    Object->Entry[EntryIndex].CodBuffer = EdbLoadCodBySymbol (
                                            Object->Entry[EntryIndex].Name,
                                            Buffer,
                                            BufferSize,
                                            &Object->Entry[EntryIndex].CodBufferSize,
                                            &Object->Entry[EntryIndex].FuncOffsetBase
                                            );
    if (Object->Entry[EntryIndex].CodBuffer != NULL) {
      Object->Entry[EntryIndex].SourceBuffer = Buffer;
    }
  }

  //
  // patch end '\0' for each code buffer
  //
  for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
    if (Object->Entry[EntryIndex].CodBuffer != NULL) {
      *((UINT8 *)Object->Entry[EntryIndex].CodBuffer + Object->Entry[EntryIndex].CodBufferSize) = 0;
      DEBUG ((DEBUG_ERROR, "  CodeSymbol: %a, FuncOffset: 0x05%x\n", Object->Entry[EntryIndex].Name, Object->Entry[EntryIndex].FuncOffsetBase));
//      DEBUG ((DEBUG_ERROR, "  [CODE]:\n%a\n", Object->Entry[EntryIndex].CodBuffer));
    }
  }

  //
  // Done
  //
  return EFI_SUCCESS;
}

EFI_STATUS
EdbUnloadCode (
  IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
  IN CHAR16                      *MapFileName,
  IN CHAR16                      *FileName,
  OUT VOID                       **Buffer
  )
/*++

Routine Description:

  Unload code

Arguments:

  DebuggerPrivate - EBC Debugger private data structure
  MapFileName     - Symbol file name
  FileName        - Code file name
  Buffer          - Code file buffer

Returns:

  EFI_SUCCESS - Code unloaded successfully

--*/
{
  EFI_DEBUGGER_SYMBOL_OBJECT *Object;
  UINTN                      ObjectIndex;
  UINTN                      EntryIndex;

  //
  // Find Symbol
  //
  Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, &ObjectIndex);
  if (Object == NULL) {
    EDBPrint (L"SymbolFile is not loaded!\n");
    return EFI_NOT_FOUND;
  }

  //
  // Find code
  //
  *Buffer = EdbFindCodeFromObject (DebuggerPrivate, Object, FileName);
  if (*Buffer == NULL) {
    EDBPrint (L"CodeFile is not loaded!\n");
    return EFI_NOT_FOUND;
  }

  //
  // go through each entry
  //
  for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
    if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
        (Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
      continue;
    }
    if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
      continue;
    }
    if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
      continue;
    }
    //
    // clean up the buffer
    //
    Object->Entry[EntryIndex].CodBuffer = NULL;
    Object->Entry[EntryIndex].CodBufferSize = 0;
    Object->Entry[EntryIndex].FuncOffsetBase = 0;
    Object->Entry[EntryIndex].SourceBuffer = NULL;
  }

  //
  // Done
  //
  return EFI_SUCCESS;
}

EFI_STATUS
EdbAddCodeBuffer (
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     CHAR16                    *MapFileName,
  IN     CHAR16                    *CodeFileName,
  IN     UINTN                     SourceBufferSize,
  IN     VOID                      *SourceBuffer
  )
/*++

Routine Description:

  Add code buffer

Arguments:

  DebuggerPrivate - EBC Debugger private data structure
  MapFileName     - Symbol file name
  CodeFileName    - Code file name
  SourceBufferSize- Code buffer size
  SourceBuffer    - Code buffer

Returns:

  EFI_SUCCESS - CodeBuffer added successfully

--*/
{
  UINTN                      Index;
  EFI_DEBUGGER_SYMBOL_OBJECT *Object;

  //
  // Find Symbol
  //
  Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, NULL);
  if (Object == NULL) {
    EDBPrint (L"SymbolFile is not loaded!\n");
    return EFI_NOT_FOUND;
  }

  //
  // Add it to last entry
  //
  for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
    ;
  }
  Object->SourceBuffer[Index] = SourceBuffer;

  return EFI_SUCCESS;
}

EFI_STATUS
EdbDeleteCodeBuffer (
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     CHAR16                    *MapFileName,
  IN     CHAR16                    *CodeFileName,
  IN     VOID                      *SourceBuffer
  )
/*++

Routine Description:

  Delete code buffer

Arguments:

  DebuggerPrivate - EBC Debugger private data structure
  MapFileName     - Symbol file name
  CodeFileName    - Code file name
  SourceBuffer    - Code buffer

Returns:

  EFI_SUCCESS - CodeBuffer deleted successfully

--*/
{
  UINTN                      Index;
  EFI_DEBUGGER_SYMBOL_OBJECT *Object;

  //
  // Find Symbol
  //
  Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, NULL);
  if (Object == NULL) {
    EDBPrint (L"SymbolFile is not loaded!\n");
    return EFI_NOT_FOUND;
  }

  for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
    //
    // free the buffer if match
    //
    if (Object->SourceBuffer[Index] == SourceBuffer) {
      gBS->FreePool (SourceBuffer);
      break;
    }
  }

  if (Object->SourceBuffer[Index] == NULL) {
    //
    // not return NOT_FOUND
    //
    return EFI_SUCCESS;
  }

  //
  // remove the entry
  //
  Object->SourceBuffer[Index] = NULL;
  for (Index = Index + 1; Object->SourceBuffer[Index] != NULL; Index++) {
    Object->SourceBuffer[Index - 1] = Object->SourceBuffer[Index];
  }
  Object->SourceBuffer[Index - 1] = NULL;

  return EFI_SUCCESS;
}

CHAR8 *
FindSymbolStr (
  IN UINTN Address
  )
/*++

Routine Description:

  Find the symbol string according to address

Arguments:

  Address         - Symbol address

Returns:

  Symbol string

--*/
{
  UINTN                       ObjectIndex;
  EFI_DEBUGGER_SYMBOL_OBJECT  *Object;
  UINTN                       EntryIndex;
  EFI_DEBUGGER_SYMBOL_ENTRY   *Entry;

  //
  // need we display symbol
  //
  if (!mDebuggerPrivate.DebuggerSymbolContext.DisplaySymbol) {
    return NULL;
  }

  //
  // Go through each object and entry
  //
  Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
  for (ObjectIndex = 0; ObjectIndex < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
    Entry = Object[ObjectIndex].Entry;
    for (EntryIndex = 0; EntryIndex < Object[ObjectIndex].EntryCount; EntryIndex++) {
      //
      // if Address match, return Name
      //
      if (Address == (Entry[EntryIndex].RVA + Object[ObjectIndex].BaseAddress)) {
        return Entry[EntryIndex].Name;
      }
    }
  }

  //
  // not found
  //
  return NULL;
}

UINTN
EdbGetLineNumberAndOffsetFromThisLine (
  IN VOID     *Line,
  OUT UINTN   *Offset
  )
/*++

Routine Description:

  Get line number and offset from this line in code file

Arguments:

  Line            - Line buffer in code file
  Offset          - Offset to functin entry

Returns:

  Line number

--*/
{
  UINTN  LineNumber;
  CHAR8  *LineBuffer;
  CHAR8  *FieldBuffer;

  LineNumber = (UINTN)-1;
  LineBuffer = Line;
  *Offset = (UINTN)-1;

  while (LineBuffer != NULL) {
    //
    // Check candidate
    //
    if (*LineBuffer != ' ') {
      return (UINTN)-1;
    }

    //
    // Get Offset
    //
    if (*(LineBuffer + 2) != ' ') {
      if (*Offset == (UINTN)-1) {
        FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 2, " ");
        *Offset = AsciiXtoi (FieldBuffer);
        PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
      }
    }

    //
    // 1. assembly instruction
    //
    FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, ":");
    //
    // 2. file path
    //
    FieldBuffer = AsciiStrGetNextTokenField (":");
    PatchForAsciiStrTokenBefore (FieldBuffer, ':');
    if (FieldBuffer == NULL) {
      //
      // candidate found
      //
      LineNumber = 0;
      LineBuffer = AsciiStrGetNextTokenLine ("\n");
      PatchForAsciiStrTokenBefore (LineBuffer, '\n');
      continue;
    }
    //
    // 3. line number
    //
    FieldBuffer = AsciiStrGetNextTokenField (":");
    PatchForAsciiStrTokenBefore (FieldBuffer, ':');
    if (FieldBuffer == NULL) {
      //
      // impossible, TBD?
      //
      LineBuffer = AsciiStrGetNextTokenLine ("\n");
      PatchForAsciiStrTokenBefore (LineBuffer, '\n');
      continue;
    }

    LineNumber = AsciiAtoi (FieldBuffer);
    //
    // Not patch after
    //

    return LineNumber;
  }

  return (UINTN)-1;
}

typedef enum {
  EdbEbcLineSearchTypeAny,
  EdbEbcLineSearchTypeFirst,
  EdbEbcLineSearchTypeLast,
  EdbEbcLineSearchTypeMax,
} EDB_EBC_LINE_SEARCH_TYPE;

UINTN
EdbGetLineNumberFromCode (
  IN EFI_DEBUGGER_SYMBOL_ENTRY  *Entry,
  IN UINTN                      FuncOffset,
  IN EDB_EBC_LINE_SEARCH_TYPE   SearchType
  )
/*++

Routine Description:

  Get line number from this code file

Arguments:

  Entry           - Symbol entry
  FuncOffset      - Offset to functin entry
  SearchType      - Search type for the code

Returns:

  Line number

--*/
{
  CHAR8  *LineBuffer;
  UINTN  LineNumber;
  UINTN  Offset;
  UINTN  CandidateLineNumber;
  UINTN  CandidateOffset;

  if (SearchType < 0 || SearchType >= EdbEbcLineSearchTypeMax) {
    return (UINTN)-1;
  }

  LineNumber = (UINTN)-1;
  CandidateLineNumber = (UINTN)-1;
  CandidateOffset = (UINTN)-1;
  LineBuffer = AsciiStrGetNewTokenLine (Entry->CodBuffer, "\n");
  while (LineBuffer != NULL) {
    if (*LineBuffer != ' ') {
      LineBuffer = AsciiStrGetNextTokenLine ("\n");
      PatchForAsciiStrTokenBefore (LineBuffer, '\n');
      continue;
    }

    //
    // Get Info
    //
    LineNumber = EdbGetLineNumberAndOffsetFromThisLine (LineBuffer, &Offset);

    //
    // Check offset
    //
    if (Offset != FuncOffset) {
      //
      // Check last offset match
      //
      if (CandidateOffset == FuncOffset) {
        if (SearchType == EdbEbcLineSearchTypeLast) {
          PatchForAsciiStrTokenAfter (LineBuffer, '\n');
          if (CandidateLineNumber != LineNumber) {
            return CandidateLineNumber;
          } else {
            return (UINTN)-1;
          }
        } else {
          //
          // impossible, TBD?
          //
        }
      }

      LineBuffer = AsciiStrGetNextTokenLine ("\n");
      PatchForAsciiStrTokenBefore (LineBuffer, '\n');
      CandidateLineNumber = LineNumber;
      continue;
    }

    //
    // Offset match, more check
    //
    if (SearchType == EdbEbcLineSearchTypeAny) {
      PatchForAsciiStrTokenAfter (LineBuffer, '\n');
      return LineNumber;
    }

    if (SearchType == EdbEbcLineSearchTypeFirst) {
      //
      // Check last line
      //
      PatchForAsciiStrTokenAfter (LineBuffer, '\n');
      if (CandidateLineNumber != LineNumber) {
        return LineNumber;
      } else {
        return (UINTN)-1;
      }
    }

    CandidateLineNumber = LineNumber;
    CandidateOffset = Offset;

    LineBuffer = AsciiStrGetNextTokenLine ("\n");
    PatchForAsciiStrTokenBefore (LineBuffer, '\n');
  }

  //
  // Check last offset match
  //
  if (CandidateOffset == FuncOffset) {
    if (SearchType == EdbEbcLineSearchTypeLast) {
      return CandidateLineNumber;
    }
  }

  return (UINTN)-1;
}

VOID *
EdbGetSourceStrFromCodeByLine (
  IN EFI_DEBUGGER_SYMBOL_ENTRY  *Entry,
  IN UINTN                      LineNumber,
  IN VOID                       **FuncEnd
  )
/*++

Routine Description:

  Get the source string from this code file by line

Arguments:

  Entry           - Symbol entry
  LineNumber      - line number
  FuncEnd         - Function end

Returns:

  Funtion start

--*/
{
  CHAR8  *LineBuffer;
  CHAR8  *FieldBuffer;
  VOID   *FuncStart;
  UINTN  Number;

  FuncStart = NULL;
  LineBuffer = AsciiStrGetNewTokenLine (Entry->CodBuffer, "\n");
  while (LineBuffer != NULL) {
    if (*LineBuffer != ';') {
      if (FuncStart != NULL) {
        //
        // Over
        //
        *FuncEnd = LineBuffer - 1;
        PatchForAsciiStrTokenAfter (LineBuffer, '\n');
        return FuncStart;
      }
      LineBuffer = AsciiStrGetNextTokenLine ("\n");
      PatchForAsciiStrTokenBefore (LineBuffer, '\n');
      continue;
    }

    //
    // Check LineNumber
    //
    FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 1, " ");
    Number = AsciiAtoi (FieldBuffer);
    PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
    if (Number != LineNumber) {
      LineBuffer = AsciiStrGetNextTokenLine ("\n");
      PatchForAsciiStrTokenBefore (LineBuffer, '\n');
      continue;
    }

    //
    // Line match, get line number
    //
    if (FuncStart == NULL) {
      FuncStart = LineBuffer;
    }

    LineBuffer = AsciiStrGetNextTokenLine ("\n");
    PatchForAsciiStrTokenBefore (LineBuffer, '\n');
  }

  return NULL;
}

VOID *
EdbGetSourceStrFromCode (
  IN EFI_DEBUGGER_SYMBOL_ENTRY  *Entry,
  IN UINTN                      FuncOffset,
  IN VOID                       **FuncEnd
  )
/*++

Routine Description:

  Get source string from this code file

Arguments:

  Entry           - Symbol entry
  FuncOffset      - Offset to functin entry
  FuncEnd         - Function end

Returns:

  Funtion start

--*/
{
  UINTN  LineNumber;

  //
  // Only search the last line, then display
  //
  LineNumber = EdbGetLineNumberFromCode (Entry, FuncOffset, EdbEbcLineSearchTypeLast);
  if (LineNumber == (UINTN)-1) {
    return NULL;
  }

  return EdbGetSourceStrFromCodeByLine (Entry, LineNumber, FuncEnd);
}

UINTN
EdbPrintSource (
  IN UINTN     Address,
  IN BOOLEAN   IsPrint
  )
/*++

Routine Description:

  Print source

Arguments:

  Address         - Instruction address
  IsPrint         - Whether need to print

Returns:

  1 - find the source
  0 - not find the source

--*/
{
  UINTN                      SymbolAddress;
  EFI_DEBUGGER_SYMBOL_OBJECT *RetObject;
  EFI_DEBUGGER_SYMBOL_ENTRY  *RetEntry;
  UINTN                      FuncOffset;
  UINT8                      *FuncStart;
  UINT8                      *FuncEnd;
  UINT8                      *FuncIndex;
  CHAR8                      Buffer[EFI_DEBUG_MAX_PRINT_BUFFER];
  UINTN                      BufferSize;

  //
  // need we display symbol
  //
  if (!mDebuggerPrivate.DebuggerSymbolContext.DisplaySymbol) {
    return 0 ;
  }

  //
  // find the symbol address
  //
  SymbolAddress = EbdFindSymbolAddress (
                    Address,
                    EdbMatchSymbolTypeLowerAddress,
                    &RetObject,
                    &RetEntry
                    );
  if (SymbolAddress == 0) {
    return 0 ;
  }

  FuncOffset = Address - SymbolAddress + RetEntry->FuncOffsetBase;

  //
  // Get Func String
  //
  FuncStart = EdbGetSourceStrFromCode (RetEntry, FuncOffset, (VOID**) &FuncEnd);
  if (FuncStart == NULL) {
    return 0 ;
  }

  //
  // check whether need to real print
  //
  if (!IsPrint) {
    return 1;
  }

  *(UINT8 *)FuncEnd = 0;

  //
  // seperate buffer by \n, so that \r can be added.
  //
  FuncIndex = FuncStart;
  while (*FuncIndex != 0) {
    if (*FuncIndex == '\n') {
      if ((FuncIndex - FuncStart) < (EFI_DEBUG_MAX_PRINT_BUFFER - 3)) {
        BufferSize = FuncIndex - FuncStart;
      } else {
        BufferSize = EFI_DEBUG_MAX_PRINT_BUFFER - 3;
      }
      if (BufferSize != 0) {
        CopyMem (Buffer, FuncStart, BufferSize);
      }
      Buffer[BufferSize] = 0;
      EDBPrint (L"%a\n", Buffer);
      FuncStart = FuncIndex + 1;
      FuncIndex = FuncStart;
    } else {
      FuncIndex ++;
    }
  }

  //
  // Patch the end
  //
  *(UINT8 *)FuncEnd = '\n';

  return 1 ;
}

VOID
GetMapfileAndSymbol (
  IN CHAR16   *Symbol,
  OUT CHAR16  **MapfileName,
  OUT CHAR16  **SymbolName
  )
/*++

Routine Description:

  Get Mapfile and SymbolName from one symbol format: [MapFileName:]SymbolName

Arguments:

  Symbol          - whole Symbol name
  MapfileName     - the mapfile name in the symbol
  SymbolName      - the symbol name in the symbol

Returns:

  None

--*/
{
  CHAR16  *Ch;

  *MapfileName = NULL;
  *SymbolName = Symbol;

  for (Ch = Symbol; *Ch != 0; Ch++) {
    //
    // Find split char
    //
    if (*Ch == L':') {
      *MapfileName = Symbol;
      *Ch = 0;
      *SymbolName = Ch + 1;
      break;
    }
  }

  return ;
}

EFI_STATUS
Symboltoi (
  IN CHAR16   *Symbol,
  OUT UINTN   *Address
  )
/*++

Routine Description:

  Convert a symbol to an address

Arguments:

  Symbol          - Symbol name
  Address         - Symbol address

Returns:

  EFI_SUCCESS    - symbol found and address returned.
  EFI_NOT_FOUND  - symbol not found
  EFI_NO_MAPPING - duplicated symbol not found

--*/
{
  UINTN                       ObjectIndex;
  EFI_DEBUGGER_SYMBOL_OBJECT  *Object;
  UINTN                       EntryIndex;
  EFI_DEBUGGER_SYMBOL_ENTRY   *Entry;
  CHAR16                      *SymbolName;
  CHAR16                      *MapfileName;

  //
  // Split one symbol to mapfile name and symbol name
  //
  GetMapfileAndSymbol (Symbol, &MapfileName, &SymbolName);

  *Address = 0;
  //
  // Go through each object
  //
  Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
  for (ObjectIndex = 0; ObjectIndex < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
    //
    // Check MapfileName
    //
    if ((MapfileName != NULL) && (StriCmp (Object[ObjectIndex].Name, MapfileName) != 0)) {
      continue;
    }
    //
    // Go through each entry
    //
    Entry = Object[ObjectIndex].Entry;
    for (EntryIndex = 0; EntryIndex < Object[ObjectIndex].EntryCount; EntryIndex++) {
      //
      // Check SymbolName (case sensitive)
      //
      if (StrCmpUnicodeAndAscii (SymbolName, Entry[EntryIndex].Name) == 0) {
        if ((*Address != 0) && (MapfileName == NULL)) {
          //
          // Find the duplicated symbol
          //
          EDBPrint (L"Duplicated Symbol found!\n");
          return EFI_NO_MAPPING;
        } else {
          //
          // record Address
          //
          *Address = (Entry[EntryIndex].RVA + Object[ObjectIndex].BaseAddress);
        }
      }
    }
  }

  if (*Address == 0) {
    //
    // Not found
    //
    return EFI_NOT_FOUND;
  }

  return EFI_SUCCESS;
}
