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