For variable name, it should contain lower case characters. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Dandan Bi <dandan.bi@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
		
			
				
	
	
		
			2237 lines
		
	
	
		
			59 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2237 lines
		
	
	
		
			59 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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"
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Load single symbol entry.
 | |
| 
 | |
|   @param  Object          - Symbol file object
 | |
|   @param  Name            - Symbol name
 | |
|   @param  ObjName         - Object name
 | |
|   @param  Address         - Symbol address
 | |
|   @param  Type            - Symbol type
 | |
| 
 | |
|   @retval EFI_SUCCESS - add single symbol entry successfully
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EdbLoadSymbolSingleEntry (
 | |
|   IN EFI_DEBUGGER_SYMBOL_OBJECT  *Object,
 | |
|   IN CHAR8                       *Name,
 | |
|   IN CHAR8                       *ObjName,
 | |
|   IN UINTN                       Address,
 | |
|   IN EFI_DEBUGGER_SYMBOL_TYPE    Type
 | |
|   )
 | |
| {
 | |
|   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
 | |
| ===============================================================================
 | |
| 
 | |
| **/
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Load symbol entry by Iec.
 | |
| 
 | |
|   @param  Object          - Symbol file object
 | |
|   @param  BufferSize      - Symbol file buffer size
 | |
|   @param  Buffer          - Symbol file buffer
 | |
| 
 | |
|   @retval EFI_SUCCESS - add symbol entry successfully
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EdbLoadSymbolEntryByIec (
 | |
|   IN EFI_DEBUGGER_SYMBOL_OBJECT  *Object,
 | |
|   IN UINTN                       BufferSize,
 | |
|   IN VOID                        *Buffer
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Load symbol entry.
 | |
| 
 | |
|   @param  Object          - Symbol file object
 | |
|   @param  BufferSize      - Symbol file buffer size
 | |
|   @param  Buffer          - Symbol file buffer
 | |
| 
 | |
|   @retval EFI_SUCCESS - add symbol entry successfully
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EdbLoadSymbolEntry (
 | |
|   IN EFI_DEBUGGER_SYMBOL_OBJECT  *Object,
 | |
|   IN UINTN                       BufferSize,
 | |
|   IN VOID                        *Buffer
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // 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);
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Find symbol file by name.
 | |
| 
 | |
|   @param  DebuggerPrivate - EBC Debugger private data structure
 | |
|   @param  FileName        - Symbol file name
 | |
|   @param  Index           - Symbol file index
 | |
| 
 | |
|   @return Object
 | |
| 
 | |
| **/
 | |
| EFI_DEBUGGER_SYMBOL_OBJECT *
 | |
| EdbFindSymbolFile (
 | |
|   IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
 | |
|   IN CHAR16                      *FileName,
 | |
|   IN OUT UINTN                   *Index OPTIONAL
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Find symbol by address.
 | |
| 
 | |
|   @param  Address         - Symbol address
 | |
|   @param  Type            - Search type
 | |
|   @param  RetObject       - Symbol object
 | |
|   @param  RetEntry        - Symbol entry
 | |
| 
 | |
|   @return Nearest symbol address
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| EbdFindSymbolAddress (
 | |
|   IN UINTN                       Address,
 | |
|   IN EDB_MATCH_SYMBOL_TYPE       Type,
 | |
|   OUT EFI_DEBUGGER_SYMBOL_OBJECT **RetObject,
 | |
|   OUT EFI_DEBUGGER_SYMBOL_ENTRY  **RetEntry
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Unload symbol file by name.
 | |
| 
 | |
|   @param  DebuggerPrivate - EBC Debugger private data structure
 | |
|   @param  FileName        - Symbol file name
 | |
| 
 | |
|   @retval EFI_SUCCESS - unload symbol successfully
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EdbUnloadSymbol (
 | |
|   IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
 | |
|   IN CHAR16                      *FileName
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Load symbol file by name.
 | |
| 
 | |
|   @param  DebuggerPrivate - EBC Debugger private data structure
 | |
|   @param  FileName        - Symbol file name
 | |
|   @param  BufferSize      - Symbol file buffer size
 | |
|   @param  Buffer          - Symbol file buffer
 | |
| 
 | |
|   @retval EFI_SUCCESS - load symbol successfully
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EdbLoadSymbol (
 | |
|   IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
 | |
|   IN CHAR16                      *FileName,
 | |
|   IN UINTN                       BufferSize,
 | |
|   IN VOID                        *Buffer
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Located PDB path name in PE image.
 | |
| 
 | |
|   @param  ImageBase - base of PE to search
 | |
| 
 | |
|   @return Pointer into image at offset of PDB file name if PDB file name is found,
 | |
|   Otherwise a pointer to an empty string.
 | |
| 
 | |
| **/
 | |
| CHAR8 *
 | |
| GetPdbPath (
 | |
|   VOID *ImageBase
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Check whether PDB file and MAP file have same name.
 | |
| 
 | |
|   @param  PdbFileName - PDB file name
 | |
|   @param  MapFileName - MAP file name
 | |
| 
 | |
|   @retval TRUE  - PDB and MAP file name match
 | |
|   @retval FALSE - PDB and MAP file name not match
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| MatchPdbAndMap (
 | |
|   IN CHAR8   *PdbFileName,
 | |
|   IN CHAR16  *MapFileName
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| 
 | |
| /**
 | |
| 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              |    |                        |
 | |
|   +------------------------+    +------------------------+
 | |
| 
 | |
|   @param DebugImageInfoTableHeader  Point to the EFI_DEBUG_IMAGE_INFO_TABLE_HEADER structure.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EdbFixDebugImageInfoTable (
 | |
|   IN OUT EFI_DEBUG_IMAGE_INFO_TABLE_HEADER **DebugImageInfoTableHeader
 | |
|   )
 | |
| {
 | |
|   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
 | |
| //
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Patch symbol RVA.
 | |
| 
 | |
|   @param  DebuggerPrivate - EBC Debugger private data structure
 | |
|   @param  FileName        - Symbol file name
 | |
|   @param  SearchType      - Search type for Object
 | |
| 
 | |
|   @retval EFI_SUCCESS   - Patch symbol RVA successfully
 | |
|   @retval EFI_NOT_FOUND - Symbol RVA base not found
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EdbPatchSymbolRVA (
 | |
|   IN EFI_DEBUGGER_PRIVATE_DATA     *DebuggerPrivate,
 | |
|   IN CHAR16                        *FileName,
 | |
|   IN EDB_EBC_IMAGE_RVA_SEARCH_TYPE SearchType
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Check whether OBJ file and COD file have same name.
 | |
| 
 | |
|   @param  ObjFileName - OBJ file name
 | |
|   @param  CodFileName - COD file name
 | |
| 
 | |
|   @retval TRUE  - OBJ and COD file name match
 | |
|   @retval FALSE - OBJ and COD file name not match
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| MatchObjAndCod (
 | |
|   IN CHAR8   *ObjFileName,
 | |
|   IN CHAR16  *CodFileName
 | |
|   )
 | |
| {
 | |
|   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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Load code by symbol by Iec.
 | |
| 
 | |
|   @param  Name            - Symbol file name
 | |
|   @param  Buffer          - Symbol file buffer
 | |
|   @param  BufferSize      - Symbol file buffer size
 | |
|   @param  CodeBufferSize  - Code buffer size
 | |
|   @param  FuncOffset      - Code funcion offset
 | |
| 
 | |
|   @return CodeBuffer
 | |
| 
 | |
| **/
 | |
| CHAR8 *
 | |
| EdbLoadCodBySymbolByIec (
 | |
|   IN CHAR8                       *Name,
 | |
|   IN VOID                        *Buffer,
 | |
|   IN UINTN                       BufferSize,
 | |
|   OUT UINTN                      *CodeBufferSize,
 | |
|   OUT UINTN                      *FuncOffset
 | |
|   )
 | |
| {
 | |
|   CHAR8                      *LineBuffer;
 | |
|   CHAR8                      *FieldBuffer;
 | |
|   VOID                       *BufferStart;
 | |
|   VOID                       *BufferEnd;
 | |
|   UINTN                      Offset;
 | |
|   EDB_EBC_COD_PARSE_STATE    CodParseState;
 | |
|   CHAR8                      Char[2];
 | |
| 
 | |
|   //
 | |
|   // Init
 | |
|   //
 | |
|   Char[0] = 9;
 | |
|   Char[1] = 0;
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Load code by symbol.
 | |
| 
 | |
|   @param  Name            - Symbol file name
 | |
|   @param  Buffer          - Symbol file buffer
 | |
|   @param  BufferSize      - Symbol file buffer size
 | |
|   @param  CodeBufferSize  - Code buffer size
 | |
|   @param  FuncOffset      - Code funcion offset
 | |
| 
 | |
|   @return CodeBuffer
 | |
| 
 | |
| **/
 | |
| CHAR8 *
 | |
| EdbLoadCodBySymbol (
 | |
|   IN CHAR8                       *Name,
 | |
|   IN VOID                        *Buffer,
 | |
|   IN UINTN                       BufferSize,
 | |
|   OUT UINTN                      *CodeBufferSize,
 | |
|   OUT UINTN                      *FuncOffset
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // 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);
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Find code from object.
 | |
| 
 | |
|   @param  DebuggerPrivate    EBC Debugger private data structure
 | |
|   @param  Object          - Symbol object
 | |
|   @param  FileName        - File name
 | |
| 
 | |
| **/
 | |
| VOID *
 | |
| EdbFindCodeFromObject (
 | |
|   IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
 | |
|   IN EFI_DEBUGGER_SYMBOL_OBJECT  *Object,
 | |
|   IN CHAR16                      *FileName
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Load code.
 | |
| 
 | |
|   @param  DebuggerPrivate - EBC Debugger private data structure
 | |
|   @param  MapFileName     - Symbol file name
 | |
|   @param  FileName        - Code file name
 | |
|   @param  BufferSize      - Code file buffer size
 | |
|   @param  Buffer          - Code file buffer
 | |
| 
 | |
|   @retval EFI_SUCCESS - Code loaded successfully
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EdbLoadCode (
 | |
|   IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
 | |
|   IN CHAR16                      *MapFileName,
 | |
|   IN CHAR16                      *FileName,
 | |
|   IN UINTN                       BufferSize,
 | |
|   IN VOID                        *Buffer
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Unload code.
 | |
| 
 | |
|   @param  DebuggerPrivate - EBC Debugger private data structure
 | |
|   @param  MapFileName     - Symbol file name
 | |
|   @param  FileName        - Code file name
 | |
|   @param  Buffer          - Code file buffer
 | |
| 
 | |
|   @retval EFI_SUCCESS - Code unloaded successfully
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EdbUnloadCode (
 | |
|   IN EFI_DEBUGGER_PRIVATE_DATA   *DebuggerPrivate,
 | |
|   IN CHAR16                      *MapFileName,
 | |
|   IN CHAR16                      *FileName,
 | |
|   OUT VOID                       **Buffer
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Add code buffer.
 | |
| 
 | |
|   @param  DebuggerPrivate - EBC Debugger private data structure
 | |
|   @param  MapFileName     - Symbol file name
 | |
|   @param  CodeFileName    - Code file name
 | |
|   @param  SourceBufferSize- Code buffer size
 | |
|   @param  SourceBuffer    - Code buffer
 | |
| 
 | |
|   @retval EFI_SUCCESS - CodeBuffer added successfully
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EdbAddCodeBuffer (
 | |
|   IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
 | |
|   IN     CHAR16                    *MapFileName,
 | |
|   IN     CHAR16                    *CodeFileName,
 | |
|   IN     UINTN                     SourceBufferSize,
 | |
|   IN     VOID                      *SourceBuffer
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Delete code buffer.
 | |
| 
 | |
|   @param  DebuggerPrivate - EBC Debugger private data structure
 | |
|   @param  MapFileName     - Symbol file name
 | |
|   @param  CodeFileName    - Code file name
 | |
|   @param  SourceBuffer    - Code buffer
 | |
| 
 | |
|   @retval EFI_SUCCESS - CodeBuffer deleted successfully
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EdbDeleteCodeBuffer (
 | |
|   IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
 | |
|   IN     CHAR16                    *MapFileName,
 | |
|   IN     CHAR16                    *CodeFileName,
 | |
|   IN     VOID                      *SourceBuffer
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Find the symbol string according to address.
 | |
| 
 | |
|   @param  Address         - Symbol address
 | |
| 
 | |
|   @return Symbol string
 | |
| 
 | |
| **/
 | |
| CHAR8 *
 | |
| FindSymbolStr (
 | |
|   IN UINTN Address
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Get line number and offset from this line in code file.
 | |
| 
 | |
|   @param  Line            - Line buffer in code file
 | |
|   @param  Offset          - Offset to functin entry
 | |
| 
 | |
|   @return Line number
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| EdbGetLineNumberAndOffsetFromThisLine (
 | |
|   IN VOID     *Line,
 | |
|   OUT UINTN   *Offset
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Get line number from this code file.
 | |
| 
 | |
|   @param  Entry           - Symbol entry
 | |
|   @param  FuncOffset      - Offset to functin entry
 | |
|   @param  SearchType      - Search type for the code
 | |
| 
 | |
|   @return Line number
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| EdbGetLineNumberFromCode (
 | |
|   IN EFI_DEBUGGER_SYMBOL_ENTRY  *Entry,
 | |
|   IN UINTN                      FuncOffset,
 | |
|   IN EDB_EBC_LINE_SEARCH_TYPE   SearchType
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Get the source string from this code file by line.
 | |
| 
 | |
|   @param  Entry           - Symbol entry
 | |
|   @param  LineNumber      - line number
 | |
|   @param  FuncEnd         - Function end
 | |
| 
 | |
|   @return Funtion start
 | |
| 
 | |
| **/
 | |
| VOID *
 | |
| EdbGetSourceStrFromCodeByLine (
 | |
|   IN EFI_DEBUGGER_SYMBOL_ENTRY  *Entry,
 | |
|   IN UINTN                      LineNumber,
 | |
|   IN VOID                       **FuncEnd
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Get source string from this code file.
 | |
| 
 | |
|   @param  Entry           - Symbol entry
 | |
|   @param  FuncOffset      - Offset to functin entry
 | |
|   @param  FuncEnd         - Function end
 | |
| 
 | |
|   @retval Funtion start
 | |
| 
 | |
| **/
 | |
| VOID *
 | |
| EdbGetSourceStrFromCode (
 | |
|   IN EFI_DEBUGGER_SYMBOL_ENTRY  *Entry,
 | |
|   IN UINTN                      FuncOffset,
 | |
|   IN VOID                       **FuncEnd
 | |
|   )
 | |
| {
 | |
|   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);
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Print source.
 | |
| 
 | |
|   @param  Address         - Instruction address
 | |
|   @param  IsPrint         - Whether need to print
 | |
| 
 | |
|   @retval 1 - find the source
 | |
|   @retval 0 - not find the source
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| EdbPrintSource (
 | |
|   IN UINTN     Address,
 | |
|   IN BOOLEAN   IsPrint
 | |
|   )
 | |
| {
 | |
|   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 ;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Get Mapfile and SymbolName from one symbol format: [MapFileName:]SymbolName.
 | |
| 
 | |
|   @param  Symbol          - whole Symbol name
 | |
|   @param  MapfileName     - the mapfile name in the symbol
 | |
|   @param  SymbolName      - the symbol name in the symbol
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| GetMapfileAndSymbol (
 | |
|   IN CHAR16   *Symbol,
 | |
|   OUT CHAR16  **MapfileName,
 | |
|   OUT CHAR16  **SymbolName
 | |
|   )
 | |
| {
 | |
|   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 ;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Convert a symbol to an address.
 | |
| 
 | |
|   @param  Symbol          - Symbol name
 | |
|   @param  Address         - Symbol address
 | |
| 
 | |
|   @retval EFI_SUCCESS    - symbol found and address returned.
 | |
|   @retval EFI_NOT_FOUND  - symbol not found
 | |
|   @retval EFI_NO_MAPPING - duplicated symbol not found
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Symboltoi (
 | |
|   IN CHAR16   *Symbol,
 | |
|   OUT UINTN   *Address
 | |
|   )
 | |
| {
 | |
|   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;
 | |
| }
 |