From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../Universal/EbcDxe/EbcDebugger/EdbSymbol.c | 2230 ++++++++++++++++++++ 1 file changed, 2230 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c (limited to 'roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c') diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c new file mode 100644 index 000000000..90a9b9fbd --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c @@ -0,0 +1,2230 @@ +/** @file + +Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +#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 + 0000:00000000 ___safe_se_handler_count 00000000 + 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 || RetEntry == NULL) { + 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; +} -- cgit