| /** @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; | |
| } |