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