/** @file
Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Edb.h"
/**
Load single symbol entry.
@param Object - Symbol file object
@param Name - Symbol name
@param ObjName - Object name
@param Address - Symbol address
@param Type - Symbol type
@retval EFI_SUCCESS - add single symbol entry successfully
**/
EFI_STATUS
EdbLoadSymbolSingleEntry (
IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
IN CHAR8 *Name,
IN CHAR8 *ObjName,
IN UINTN Address,
IN EFI_DEBUGGER_SYMBOL_TYPE Type
)
{
EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
//
// Check Count VS MaxCount
//
if (Object->EntryCount >= Object->MaxEntryCount) {
//
// reallocate (for codebuffer too)
// TBD
//
return EFI_OUT_OF_RESOURCES;
}
Entry = &Object->Entry[Object->EntryCount];
//
// Print Debug info
//
if (sizeof (UINTN) == sizeof(UINT64)) {
DEBUG ((DEBUG_ERROR, " Symbol: %a, Address: 0x%016lx (%d)\n", Name, (UINT64)Address, (UINTN)Type));
} else {
DEBUG ((DEBUG_ERROR, " Symbol: %a, Address: 0x%08x (%d)\n", Name, Address, (UINTN)Type));
}
//
// Fill the entry - name, RVA, type
//
AsciiStrnCpyS (Entry->Name, sizeof(Entry->Name), Name, sizeof(Entry->Name) - 1);
if (ObjName != NULL) {
AsciiStrnCpyS (Entry->ObjName, sizeof(Entry->ObjName), ObjName, sizeof(Entry->ObjName) - 1);
}
Entry->Rva = Address % EFI_DEBUGGER_DEFAULT_LINK_IMAGEBASE;
Entry->Type = Type;
//
// Increase Count
//
Object->EntryCount++;
//
// Done
//
return EFI_SUCCESS;
}
typedef enum {
EdbEbcMapParseStateUninitialized,
EdbEbcMapParseStateSymbolStart,
EdbEbcMapParseStateSeHandlerSymbol,
EdbEbcMapParseStateFunctionSymbol,
EdbEbcMapParseStateVarbssInitSymbol,
EdbEbcMapParseStateCrtSymbol,
EdbEbcMapParseStateVariableSymbol,
EdbEbcMapParseStateStaticFunctionSymbol,
EdbEbcMapParseStateMax,
} EDB_EBC_MAP_PARSE_STATE;
typedef enum {
EdbEbcSymbolParseStateUninitialized,
EdbEbcSymbolParseStateReadyForName,
EdbEbcSymbolParseStateReadyForRVA,
EdbEbcSymbolParseStateReadyForType,
EdbEbcSymbolParseStateReadyForObject,
EdbEbcSymbolParseStateMax,
} EDB_EBC_SYMBOL_PARSE_STATE;
/**
The following code depends on the MAP file generated by IEC compiler (actually Microsoft linker).
Sample as follows: EbcTest.map
===============================================================================
EbcTest
Timestamp is 45b02718 (Fri Jan 19 10:04:08 2007)
Preferred load address is 10000000
Start Length Name Class
0001:00000000 00000370H .text CODE
0002:00000000 00000030H _VARBSS_INIT CODE
0003:00000000 00000004H .CRT$TSA DATA
0003:00000004 00000004H .CRT$TSC DATA
0003:00000008 00000004H .CRT$X DATA
0003:0000000c 00000008H .CRT$XCU DATA
0003:00000014 00000004H .CRT$Z DATA
0003:00000020 0000001cH .rdata DATA
0003:0000003c 00000000H .edata DATA
0003:0000003c 00000056H .rdata$debug DATA
0004:00000000 00000070H .data DATA
0004:00000070 00000020H .bss DATA
Address Publics by Value Rva+Base Lib:Object
0000:00000000 ___safe_se_handler_table 00000000
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;
}