mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-25 16:37:42 +01:00
2231 lines
58 KiB
C
2231 lines
58 KiB
C
|
/** @file
|
||
|
|
||
|
Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
|
||
|
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 <absolute>
|
||
|
0000:00000000 ___safe_se_handler_count 00000000 <absolute>
|
||
|
0001:00000042 TestSubRoutine 10000442 f EbcTest.obj
|
||
|
0001:0000011a EfiMain 1000051a f EbcTest.obj
|
||
|
0001:00000200 TestSubRoutineSub 10000600 f EbcTestSub.obj
|
||
|
0001:00000220 EfiStart 10000620 f EbcLib:EbcLib.obj
|
||
|
0002:00000000 varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b02717 10000800 f EbcTest.obj
|
||
|
0002:00000020 varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTestSub$c45af77f3 10000820 f EbcTestSub.obj
|
||
|
0003:00000000 CrtThunkBegin 10000a00 EbcLib:EbcLib.obj
|
||
|
0003:00000004 CrtThunkEnd 10000a04 EbcLib:EbcLib.obj
|
||
|
0003:00000008 CrtBegin 10000a08 EbcLib:EbcLib.obj
|
||
|
0003:00000014 CrtEnd 10000a14 EbcLib:EbcLib.obj
|
||
|
0004:00000070 TestStr 10000c70 EbcTest.obj
|
||
|
0004:00000078 TestVariable1 10000c78 EbcTest.obj
|
||
|
0004:00000080 TestSubVariableSub 10000c80 EbcTestSub.obj
|
||
|
|
||
|
entry point at 0001:00000220
|
||
|
|
||
|
Static symbols
|
||
|
|
||
|
0001:00000000 TestSubRoutine2 10000400 f EbcTest.obj
|
||
|
===============================================================================
|
||
|
|
||
|
**/
|
||
|
|
||
|
/**
|
||
|
|
||
|
Load symbol entry by Iec.
|
||
|
|
||
|
@param Object - Symbol file object
|
||
|
@param BufferSize - Symbol file buffer size
|
||
|
@param Buffer - Symbol file buffer
|
||
|
|
||
|
@retval EFI_SUCCESS - add symbol entry successfully
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EdbLoadSymbolEntryByIec (
|
||
|
IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
|
||
|
IN UINTN BufferSize,
|
||
|
IN VOID *Buffer
|
||
|
)
|
||
|
{
|
||
|
CHAR8 *LineBuffer;
|
||
|
CHAR8 *FieldBuffer;
|
||
|
EDB_EBC_MAP_PARSE_STATE MapParseState;
|
||
|
EDB_EBC_SYMBOL_PARSE_STATE SymbolParseState;
|
||
|
CHAR8 *Name;
|
||
|
CHAR8 *ObjName;
|
||
|
UINTN Address;
|
||
|
EFI_DEBUGGER_SYMBOL_TYPE Type;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Begin to parse the Buffer
|
||
|
//
|
||
|
LineBuffer = AsciiStrGetNewTokenLine (Buffer, "\n\r");
|
||
|
MapParseState = EdbEbcMapParseStateUninitialized;
|
||
|
//
|
||
|
// Check each line
|
||
|
//
|
||
|
while (LineBuffer != NULL) {
|
||
|
FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, " ");
|
||
|
SymbolParseState = EdbEbcSymbolParseStateUninitialized;
|
||
|
//
|
||
|
// Init entry value
|
||
|
//
|
||
|
Name = NULL;
|
||
|
ObjName = NULL;
|
||
|
Address = 0;
|
||
|
Type = EfiDebuggerSymbolTypeMax;
|
||
|
//
|
||
|
// Check each field
|
||
|
//
|
||
|
while (FieldBuffer != NULL) {
|
||
|
if (AsciiStrCmp (FieldBuffer, "") == 0) {
|
||
|
FieldBuffer = AsciiStrGetNextTokenField (" ");
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// check "Address"
|
||
|
//
|
||
|
if (AsciiStrCmp (FieldBuffer, "Address") == 0) {
|
||
|
MapParseState = EdbEbcMapParseStateSymbolStart;
|
||
|
break;
|
||
|
}
|
||
|
//
|
||
|
// check "Static"
|
||
|
//
|
||
|
if (AsciiStrCmp (FieldBuffer, "Static") == 0) {
|
||
|
MapParseState = EdbEbcMapParseStateStaticFunctionSymbol;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (MapParseState == EdbEbcMapParseStateUninitialized) {
|
||
|
//
|
||
|
// Do not parse anything until get "Address" or "Static"
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
if (AsciiStrCmp (FieldBuffer, "entry") == 0) {
|
||
|
//
|
||
|
// Skip entry point
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now we start to parse this line for Name, Address, and Object
|
||
|
//
|
||
|
switch (SymbolParseState) {
|
||
|
case EdbEbcSymbolParseStateUninitialized:
|
||
|
//
|
||
|
// Get the Address
|
||
|
//
|
||
|
SymbolParseState = EdbEbcSymbolParseStateReadyForName;
|
||
|
break;
|
||
|
case EdbEbcSymbolParseStateReadyForName:
|
||
|
//
|
||
|
// Get the Name
|
||
|
//
|
||
|
if (AsciiStrnCmp (FieldBuffer, "___safe_se_handler", AsciiStrLen ("___safe_se_handler")) == 0) {
|
||
|
//
|
||
|
// skip SeHandler
|
||
|
//
|
||
|
MapParseState = EdbEbcMapParseStateSeHandlerSymbol;
|
||
|
goto ExitFieldParse;
|
||
|
} else if (AsciiStrnCmp (FieldBuffer, "varbss_init", AsciiStrLen ("varbss_init")) == 0) {
|
||
|
//
|
||
|
// check VarbssInit
|
||
|
//
|
||
|
MapParseState = EdbEbcMapParseStateVarbssInitSymbol;
|
||
|
// goto ExitFieldParse;
|
||
|
Name = FieldBuffer;
|
||
|
SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
|
||
|
} else if (AsciiStrnCmp (FieldBuffer, "Crt", AsciiStrLen ("Crt")) == 0) {
|
||
|
//
|
||
|
// check Crt
|
||
|
//
|
||
|
MapParseState = EdbEbcMapParseStateCrtSymbol;
|
||
|
// goto ExitFieldParse;
|
||
|
Name = FieldBuffer;
|
||
|
SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
|
||
|
} else {
|
||
|
//
|
||
|
// Now, it is normal function
|
||
|
//
|
||
|
switch (MapParseState) {
|
||
|
case EdbEbcMapParseStateSeHandlerSymbol:
|
||
|
MapParseState = EdbEbcMapParseStateFunctionSymbol;
|
||
|
break;
|
||
|
case EdbEbcMapParseStateCrtSymbol:
|
||
|
MapParseState = EdbEbcMapParseStateVariableSymbol;
|
||
|
break;
|
||
|
case EdbEbcMapParseStateFunctionSymbol:
|
||
|
case EdbEbcMapParseStateVariableSymbol:
|
||
|
case EdbEbcMapParseStateStaticFunctionSymbol:
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT (FALSE);
|
||
|
break;
|
||
|
}
|
||
|
Name = FieldBuffer;
|
||
|
SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
|
||
|
}
|
||
|
break;
|
||
|
case EdbEbcSymbolParseStateReadyForRVA:
|
||
|
//
|
||
|
// Get the RVA
|
||
|
//
|
||
|
Address = AsciiXtoi (FieldBuffer);
|
||
|
SymbolParseState = EdbEbcSymbolParseStateReadyForType;
|
||
|
break;
|
||
|
case EdbEbcSymbolParseStateReadyForType:
|
||
|
//
|
||
|
// Get the Type. This is optional, only for "f".
|
||
|
//
|
||
|
if (AsciiStrCmp (FieldBuffer, "f") == 0) {
|
||
|
SymbolParseState = EdbEbcSymbolParseStateReadyForObject;
|
||
|
switch (MapParseState) {
|
||
|
case EdbEbcMapParseStateFunctionSymbol:
|
||
|
case EdbEbcMapParseStateVarbssInitSymbol:
|
||
|
Type = EfiDebuggerSymbolFunction;
|
||
|
break;
|
||
|
case EdbEbcMapParseStateStaticFunctionSymbol:
|
||
|
Type = EfiDebuggerSymbolStaticFunction;
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT (FALSE);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
//
|
||
|
// Else it should be Object.
|
||
|
// let it bypass here
|
||
|
//
|
||
|
case EdbEbcSymbolParseStateReadyForObject:
|
||
|
switch (Type) {
|
||
|
case EfiDebuggerSymbolTypeMax:
|
||
|
switch (MapParseState) {
|
||
|
case EdbEbcMapParseStateVariableSymbol:
|
||
|
case EdbEbcMapParseStateCrtSymbol:
|
||
|
Type = EfiDebuggerSymbolGlobalVariable;
|
||
|
break;
|
||
|
case EdbEbcMapParseStateSeHandlerSymbol:
|
||
|
//
|
||
|
// do nothing here
|
||
|
//
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT (FALSE);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case EfiDebuggerSymbolFunction:
|
||
|
case EfiDebuggerSymbolStaticFunction:
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT (FALSE);
|
||
|
break;
|
||
|
}
|
||
|
//
|
||
|
// Get the Object
|
||
|
//
|
||
|
ObjName = FieldBuffer;
|
||
|
SymbolParseState = EdbEbcSymbolParseStateUninitialized;
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT (FALSE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the next field
|
||
|
//
|
||
|
FieldBuffer = AsciiStrGetNextTokenField (" ");
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add the entry if we get everything.
|
||
|
//
|
||
|
if ((Name != NULL) && (Type != EfiDebuggerSymbolTypeMax)) {
|
||
|
EdbLoadSymbolSingleEntry (Object, Name, ObjName, Address, Type);
|
||
|
}
|
||
|
|
||
|
ExitFieldParse:
|
||
|
//
|
||
|
// Get the next line
|
||
|
//
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Done
|
||
|
//
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Load symbol entry.
|
||
|
|
||
|
@param Object - Symbol file object
|
||
|
@param BufferSize - Symbol file buffer size
|
||
|
@param Buffer - Symbol file buffer
|
||
|
|
||
|
@retval EFI_SUCCESS - add symbol entry successfully
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EdbLoadSymbolEntry (
|
||
|
IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
|
||
|
IN UINTN BufferSize,
|
||
|
IN VOID *Buffer
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// MAP file format depends on the compiler (actually linker).
|
||
|
//
|
||
|
// It is possible to check the different MAP file format in this routine.
|
||
|
// Now only IEC is supported.
|
||
|
//
|
||
|
return EdbLoadSymbolEntryByIec (Object, BufferSize, Buffer);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Find symbol file by name.
|
||
|
|
||
|
@param DebuggerPrivate - EBC Debugger private data structure
|
||
|
@param FileName - Symbol file name
|
||
|
@param Index - Symbol file index
|
||
|
|
||
|
@return Object
|
||
|
|
||
|
**/
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *
|
||
|
EdbFindSymbolFile (
|
||
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
||
|
IN CHAR16 *FileName,
|
||
|
IN OUT UINTN *Index OPTIONAL
|
||
|
)
|
||
|
{
|
||
|
UINTN ObjectIndex;
|
||
|
|
||
|
//
|
||
|
// Check each Object
|
||
|
//
|
||
|
for (ObjectIndex = 0; ObjectIndex < DebuggerPrivate->DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
|
||
|
if (StrCmp (FileName, DebuggerPrivate->DebuggerSymbolContext.Object[ObjectIndex].Name) == 0) {
|
||
|
//
|
||
|
// Name match, found it
|
||
|
//
|
||
|
if (Index != NULL) {
|
||
|
*Index = ObjectIndex;
|
||
|
}
|
||
|
return &DebuggerPrivate->DebuggerSymbolContext.Object[ObjectIndex];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Not found
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Find symbol by address.
|
||
|
|
||
|
@param Address - Symbol address
|
||
|
@param Type - Search type
|
||
|
@param RetObject - Symbol object
|
||
|
@param RetEntry - Symbol entry
|
||
|
|
||
|
@return Nearest symbol address
|
||
|
|
||
|
**/
|
||
|
UINTN
|
||
|
EbdFindSymbolAddress (
|
||
|
IN UINTN Address,
|
||
|
IN EDB_MATCH_SYMBOL_TYPE Type,
|
||
|
OUT EFI_DEBUGGER_SYMBOL_OBJECT **RetObject,
|
||
|
OUT EFI_DEBUGGER_SYMBOL_ENTRY **RetEntry
|
||
|
)
|
||
|
{
|
||
|
UINTN Index;
|
||
|
UINTN SubIndex;
|
||
|
UINTN CandidateLowerAddress;
|
||
|
UINTN CandidateUpperAddress;
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
||
|
EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
|
||
|
EFI_DEBUGGER_SYMBOL_ENTRY *LowEntry;
|
||
|
EFI_DEBUGGER_SYMBOL_ENTRY *UpperEntry;
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *LowObject;
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *UpperObject;
|
||
|
|
||
|
if ((Type < 0) || (Type >= EdbMatchSymbolTypeMax)) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Init
|
||
|
//
|
||
|
CandidateLowerAddress = 0;
|
||
|
CandidateUpperAddress = (UINTN)-1;
|
||
|
LowEntry = NULL;
|
||
|
UpperEntry = NULL;
|
||
|
LowObject = NULL;
|
||
|
UpperObject = NULL;
|
||
|
|
||
|
//
|
||
|
// Go through each object
|
||
|
//
|
||
|
Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
|
||
|
for (Index = 0; Index < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; Index++, Object++) {
|
||
|
if (Object->EntryCount == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// Go through each entry
|
||
|
//
|
||
|
Entry = Object->Entry;
|
||
|
for (SubIndex = 0; SubIndex < Object->EntryCount; SubIndex++, Entry++) {
|
||
|
if (Address != Entry->Rva + Object->BaseAddress) {
|
||
|
//
|
||
|
// Check for nearest address
|
||
|
//
|
||
|
if (Address > Entry->Rva + Object->BaseAddress) {
|
||
|
//
|
||
|
// Record it if Current RVA < Address
|
||
|
//
|
||
|
if (CandidateLowerAddress < Entry->Rva + Object->BaseAddress) {
|
||
|
CandidateLowerAddress = Entry->Rva + Object->BaseAddress;
|
||
|
LowEntry = Entry;
|
||
|
LowObject = Object;
|
||
|
}
|
||
|
} else {
|
||
|
//
|
||
|
// Record it if Current RVA > Address
|
||
|
//
|
||
|
if (CandidateUpperAddress > Entry->Rva + Object->BaseAddress) {
|
||
|
CandidateUpperAddress = Entry->Rva + Object->BaseAddress;
|
||
|
UpperEntry = Entry;
|
||
|
UpperObject = Object;
|
||
|
}
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// address match, return directly
|
||
|
//
|
||
|
*RetEntry = Entry;
|
||
|
*RetObject = Object;
|
||
|
return Address;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// No Match, provide latest symbol
|
||
|
//
|
||
|
|
||
|
if ((Address - CandidateLowerAddress) < EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE) {
|
||
|
//
|
||
|
// Check for lower address
|
||
|
//
|
||
|
if (((Type == EdbMatchSymbolTypeNearestAddress) &&
|
||
|
((CandidateUpperAddress - Address) > (Address - CandidateLowerAddress))) ||
|
||
|
(Type == EdbMatchSymbolTypeLowerAddress)) {
|
||
|
//
|
||
|
// return nearest lower address
|
||
|
//
|
||
|
*RetEntry = LowEntry;
|
||
|
*RetObject = LowObject;
|
||
|
return CandidateLowerAddress;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((CandidateUpperAddress - Address) < EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE) {
|
||
|
//
|
||
|
// Check for upper address
|
||
|
//
|
||
|
if (((Type == EdbMatchSymbolTypeNearestAddress) &&
|
||
|
((CandidateUpperAddress - Address) < (Address - CandidateLowerAddress))) ||
|
||
|
(Type == EdbMatchSymbolTypeUpperAddress)) {
|
||
|
//
|
||
|
// return nearest upper address
|
||
|
//
|
||
|
*RetEntry = UpperEntry;
|
||
|
*RetObject = UpperObject;
|
||
|
return CandidateUpperAddress;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// No match and nearest one, return NULL
|
||
|
//
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Unload symbol file by name.
|
||
|
|
||
|
@param DebuggerPrivate - EBC Debugger private data structure
|
||
|
@param FileName - Symbol file name
|
||
|
|
||
|
@retval EFI_SUCCESS - unload symbol successfully
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EdbUnloadSymbol (
|
||
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
||
|
IN CHAR16 *FileName
|
||
|
)
|
||
|
{
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
||
|
UINTN ObjectIndex;
|
||
|
UINTN Index;
|
||
|
EFI_DEBUGGER_SYMBOL_ENTRY *OldEntry;
|
||
|
UINTN OldEntryCount;
|
||
|
UINTN MaxEntryCount;
|
||
|
VOID **OldSourceBuffer;
|
||
|
|
||
|
//
|
||
|
// Find Symbol
|
||
|
//
|
||
|
Object = EdbFindSymbolFile (DebuggerPrivate, FileName, &ObjectIndex);
|
||
|
if (Object == NULL) {
|
||
|
EDBPrint (L"SymbolFile is not loaded!\n");
|
||
|
return EFI_DEBUG_CONTINUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Record old data
|
||
|
//
|
||
|
Object = DebuggerPrivate->DebuggerSymbolContext.Object;
|
||
|
OldEntry = Object->Entry;
|
||
|
OldSourceBuffer = Object->SourceBuffer;
|
||
|
MaxEntryCount = Object->MaxEntryCount;
|
||
|
OldEntryCount = Object->EntryCount;
|
||
|
|
||
|
//
|
||
|
// Remove the matched Object
|
||
|
//
|
||
|
for (Index = ObjectIndex; Index < DebuggerPrivate->DebuggerSymbolContext.ObjectCount - 1; Index++) {
|
||
|
CopyMem (&Object[Index], &Object[Index + 1], sizeof(EFI_DEBUGGER_SYMBOL_OBJECT));
|
||
|
}
|
||
|
ZeroMem (&Object[Index], sizeof(Object[Index]));
|
||
|
|
||
|
//
|
||
|
// Move old data to new place
|
||
|
//
|
||
|
Object[Index].Entry = OldEntry;
|
||
|
Object[Index].SourceBuffer = OldSourceBuffer;
|
||
|
Object[Index].MaxEntryCount = MaxEntryCount;
|
||
|
DebuggerPrivate->DebuggerSymbolContext.ObjectCount --;
|
||
|
|
||
|
//
|
||
|
// Clean old entry data
|
||
|
//
|
||
|
for (Index = 0; Index < OldEntryCount; Index++) {
|
||
|
ZeroMem (&OldEntry[Index], sizeof(OldEntry[Index]));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Free OldSourceBuffer
|
||
|
//
|
||
|
for (Index = 0; OldSourceBuffer[Index] != NULL; Index++) {
|
||
|
gBS->FreePool (OldSourceBuffer[Index]);
|
||
|
OldSourceBuffer[Index] = NULL;
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Load symbol file by name.
|
||
|
|
||
|
@param DebuggerPrivate - EBC Debugger private data structure
|
||
|
@param FileName - Symbol file name
|
||
|
@param BufferSize - Symbol file buffer size
|
||
|
@param Buffer - Symbol file buffer
|
||
|
|
||
|
@retval EFI_SUCCESS - load symbol successfully
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EdbLoadSymbol (
|
||
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
||
|
IN CHAR16 *FileName,
|
||
|
IN UINTN BufferSize,
|
||
|
IN VOID *Buffer
|
||
|
)
|
||
|
{
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
//
|
||
|
// Check duplicated File
|
||
|
//
|
||
|
Object = EdbFindSymbolFile (DebuggerPrivate, FileName, NULL);
|
||
|
if (Object != NULL) {
|
||
|
Status = EdbUnloadSymbol (DebuggerPrivate, FileName);
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
DEBUG ((DEBUG_ERROR, "Unload Duplicated Symbol File Error!\n"));
|
||
|
return Status;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check Count VS MaxCount
|
||
|
//
|
||
|
if (DebuggerPrivate->DebuggerSymbolContext.ObjectCount >= DebuggerPrivate->DebuggerSymbolContext.MaxObjectCount) {
|
||
|
//
|
||
|
// reallocate
|
||
|
// TBD
|
||
|
//
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
Object = &DebuggerPrivate->DebuggerSymbolContext.Object[DebuggerPrivate->DebuggerSymbolContext.ObjectCount];
|
||
|
|
||
|
//
|
||
|
// Init Object
|
||
|
//
|
||
|
Object->EntryCount = 0;
|
||
|
Object->MaxEntryCount = EFI_DEBUGGER_SYMBOL_ENTRY_MAX;
|
||
|
|
||
|
//
|
||
|
// Load SymbolEntry
|
||
|
//
|
||
|
DEBUG ((DEBUG_ERROR, "Symbol File: %s\n", FileName));
|
||
|
Status = EdbLoadSymbolEntry (Object, BufferSize, Buffer);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fill Object value
|
||
|
//
|
||
|
StrnCpyS (Object->Name, sizeof(Object->Name) / sizeof(CHAR16),
|
||
|
FileName, (sizeof(Object->Name) / sizeof(CHAR16)) - 1);
|
||
|
Object->BaseAddress = 0;
|
||
|
|
||
|
//
|
||
|
// Increase the object count
|
||
|
//
|
||
|
DebuggerPrivate->DebuggerSymbolContext.ObjectCount ++;
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Located PDB path name in PE image.
|
||
|
|
||
|
@param ImageBase - base of PE to search
|
||
|
|
||
|
@return Pointer into image at offset of PDB file name if PDB file name is found,
|
||
|
Otherwise a pointer to an empty string.
|
||
|
|
||
|
**/
|
||
|
CHAR8 *
|
||
|
GetPdbPath (
|
||
|
VOID *ImageBase
|
||
|
)
|
||
|
{
|
||
|
CHAR8 *PdbPath;
|
||
|
UINT32 DirCount;
|
||
|
EFI_IMAGE_DOS_HEADER *DosHdr;
|
||
|
EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
|
||
|
EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHdr32;
|
||
|
EFI_IMAGE_OPTIONAL_HEADER64 *OptionalHdr64;
|
||
|
EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
|
||
|
EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
|
||
|
VOID *CodeViewEntryPointer;
|
||
|
|
||
|
//
|
||
|
// Init value
|
||
|
//
|
||
|
CodeViewEntryPointer = NULL;
|
||
|
PdbPath = NULL;
|
||
|
DosHdr = ImageBase;
|
||
|
|
||
|
//
|
||
|
// Check magic
|
||
|
//
|
||
|
if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
|
||
|
return NULL;
|
||
|
}
|
||
|
NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) DosHdr + DosHdr->e_lfanew);
|
||
|
//
|
||
|
// Check Machine, filter for EBC
|
||
|
//
|
||
|
if (NtHdr->Pe32.FileHeader.Machine != EFI_IMAGE_MACHINE_EBC) {
|
||
|
//
|
||
|
// If not EBC, return NULL
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get DirectoryEntry
|
||
|
// EBC spec says PE32+, but implementation uses PE32. So check dynamically here.
|
||
|
//
|
||
|
if (NtHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||
|
OptionalHdr32 = (VOID *) &NtHdr->Pe32.OptionalHeader;
|
||
|
DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
|
||
|
} else if (NtHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||
|
OptionalHdr64 = (VOID *) &NtHdr->Pe32Plus.OptionalHeader;
|
||
|
DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
|
||
|
} else {
|
||
|
return NULL;
|
||
|
}
|
||
|
if (DirectoryEntry->VirtualAddress == 0) {
|
||
|
return NULL;
|
||
|
}
|
||
|
//
|
||
|
// Go through DirectoryEntry
|
||
|
//
|
||
|
for (DirCount = 0;
|
||
|
(DirCount < DirectoryEntry->Size / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) && CodeViewEntryPointer == NULL;
|
||
|
DirCount++
|
||
|
) {
|
||
|
DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (DirectoryEntry->VirtualAddress + (UINTN) ImageBase + DirCount * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
|
||
|
if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
|
||
|
//
|
||
|
// Match DebugEntry, only CODEVIEW_SIGNATURE_NB10 and CODEVIEW_SIGNATURE_RSDS are supported.
|
||
|
//
|
||
|
CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + (UINTN) ImageBase);
|
||
|
switch (*(UINT32 *) CodeViewEntryPointer) {
|
||
|
case CODEVIEW_SIGNATURE_NB10:
|
||
|
PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
|
||
|
break;
|
||
|
case CODEVIEW_SIGNATURE_RSDS:
|
||
|
PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Done successfully
|
||
|
//
|
||
|
return PdbPath;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Check whether PDB file and MAP file have same name.
|
||
|
|
||
|
@param PdbFileName - PDB file name
|
||
|
@param MapFileName - MAP file name
|
||
|
|
||
|
@retval TRUE - PDB and MAP file name match
|
||
|
@retval FALSE - PDB and MAP file name not match
|
||
|
|
||
|
**/
|
||
|
BOOLEAN
|
||
|
MatchPdbAndMap (
|
||
|
IN CHAR8 *PdbFileName,
|
||
|
IN CHAR16 *MapFileName
|
||
|
)
|
||
|
{
|
||
|
UINTN PdbNameSize;
|
||
|
UINTN MapNameSize;
|
||
|
CHAR8 *PurePdbFileName;
|
||
|
UINTN Index;
|
||
|
|
||
|
//
|
||
|
// remove dir name
|
||
|
//
|
||
|
PurePdbFileName = PdbFileName;
|
||
|
for (Index = 0; PdbFileName[Index] != 0; Index++) {
|
||
|
if (PdbFileName[Index] == '\\') {
|
||
|
PurePdbFileName = &PdbFileName[Index + 1];
|
||
|
}
|
||
|
}
|
||
|
PdbFileName = PurePdbFileName;
|
||
|
|
||
|
//
|
||
|
// get size
|
||
|
//
|
||
|
PdbNameSize = AsciiStrLen (PdbFileName);
|
||
|
MapNameSize = StrLen (MapFileName);
|
||
|
|
||
|
if (PdbNameSize != MapNameSize) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// check the name
|
||
|
//
|
||
|
for (Index = 0; Index < MapNameSize - 4; Index++) {
|
||
|
if ((PdbFileName[Index] | 0x20) != (MapFileName[Index] | 0x20)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// BUGBUG: work-around start
|
||
|
//
|
||
|
typedef struct {
|
||
|
EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable;
|
||
|
volatile UINT32 UpdateStatus;
|
||
|
UINT32 TableSize;
|
||
|
} EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD;
|
||
|
|
||
|
EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugImageInfoTableHeader;
|
||
|
|
||
|
/**
|
||
|
For compatibility consideration, we handle 2 cases:
|
||
|
|
||
|
1) IA32:
|
||
|
Old: New:
|
||
|
+------------------------+ +------------------------+
|
||
|
| EfiDebugImageInfoTable | | UpdateStatus |
|
||
|
+------------------------+ +------------------------+
|
||
|
| UpdateStatus | | TableSize |
|
||
|
+------------------------+ +------------------------+
|
||
|
| TableSize | | EfiDebugImageInfoTable |
|
||
|
+------------------------+ +------------------------+
|
||
|
|
||
|
2) X64 and IPF:
|
||
|
Old: New:
|
||
|
+------------------------+ +------------------------+
|
||
|
| EfiDebugImageInfoTable | | UpdateStatus |
|
||
|
| | +------------------------+
|
||
|
| | | TableSize |
|
||
|
+------------------------+ +------------------------+
|
||
|
| UpdateStatus | | EfiDebugImageInfoTable |
|
||
|
+------------------------+ | |
|
||
|
| TableSize | | |
|
||
|
+------------------------+ +------------------------+
|
||
|
|
||
|
@param DebugImageInfoTableHeader Point to the EFI_DEBUG_IMAGE_INFO_TABLE_HEADER structure.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
EdbFixDebugImageInfoTable (
|
||
|
IN OUT EFI_DEBUG_IMAGE_INFO_TABLE_HEADER **DebugImageInfoTableHeader
|
||
|
)
|
||
|
{
|
||
|
mDebugImageInfoTableHeader.EfiDebugImageInfoTable = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->EfiDebugImageInfoTable;
|
||
|
mDebugImageInfoTableHeader.UpdateStatus = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->UpdateStatus;
|
||
|
mDebugImageInfoTableHeader.TableSize = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->TableSize;
|
||
|
|
||
|
if ((*DebugImageInfoTableHeader)->UpdateStatus > 3) {
|
||
|
*DebugImageInfoTableHeader = &mDebugImageInfoTableHeader;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
if ((*DebugImageInfoTableHeader)->TableSize % (EFI_PAGE_SIZE / (sizeof (VOID *))) != 0) {
|
||
|
*DebugImageInfoTableHeader = &mDebugImageInfoTableHeader;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
//
|
||
|
// BUGBUG: work-around end
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
|
||
|
Patch symbol RVA.
|
||
|
|
||
|
@param DebuggerPrivate - EBC Debugger private data structure
|
||
|
@param FileName - Symbol file name
|
||
|
@param SearchType - Search type for Object
|
||
|
|
||
|
@retval EFI_SUCCESS - Patch symbol RVA successfully
|
||
|
@retval EFI_NOT_FOUND - Symbol RVA base not found
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EdbPatchSymbolRVA (
|
||
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
||
|
IN CHAR16 *FileName,
|
||
|
IN EDB_EBC_IMAGE_RVA_SEARCH_TYPE SearchType
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN ImageNumber;
|
||
|
EFI_DEBUG_IMAGE_INFO *ImageTable;
|
||
|
CHAR8 *PdbPath;
|
||
|
VOID *ImageBase;
|
||
|
VOID *CandidateImageBase;
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
||
|
|
||
|
if (SearchType < 0 || SearchType >= EdbEbcImageRvaSearchTypeMax) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the related object
|
||
|
//
|
||
|
Object = EdbFindSymbolFile (DebuggerPrivate, FileName, NULL);
|
||
|
if (Object == NULL) {
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Try again to get DebugImageInfoTable
|
||
|
//
|
||
|
if (mDebuggerPrivate.DebugImageInfoTableHeader == NULL) {
|
||
|
Status = EfiGetSystemConfigurationTable (
|
||
|
&gEfiDebugImageInfoTableGuid,
|
||
|
(VOID **) &mDebuggerPrivate.DebugImageInfoTableHeader
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
EDBPrint (L"DebugImageInfoTable not found!\n");
|
||
|
return Status;
|
||
|
}
|
||
|
}
|
||
|
DEBUG ((DEBUG_ERROR, "DebugImageInfoTableHeader: %x\n", mDebuggerPrivate.DebugImageInfoTableHeader));
|
||
|
|
||
|
//
|
||
|
// BUGBUG: work-around start
|
||
|
//
|
||
|
EdbFixDebugImageInfoTable (&mDebuggerPrivate.DebugImageInfoTableHeader);
|
||
|
//
|
||
|
// BUGBUG: work-around end
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Go through DebugImageInfoTable for each Image
|
||
|
//
|
||
|
CandidateImageBase = NULL;
|
||
|
ImageTable = mDebuggerPrivate.DebugImageInfoTableHeader->EfiDebugImageInfoTable;
|
||
|
for (ImageNumber = 0; ImageNumber < mDebuggerPrivate.DebugImageInfoTableHeader->TableSize; ImageNumber++) {
|
||
|
if (ImageTable[ImageNumber].NormalImage == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
ImageBase = ImageTable[ImageNumber].NormalImage->LoadedImageProtocolInstance->ImageBase;
|
||
|
//
|
||
|
// Get PDB path
|
||
|
//
|
||
|
PdbPath = GetPdbPath (ImageBase);
|
||
|
if (PdbPath == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// Check PDB name
|
||
|
//
|
||
|
if (!MatchPdbAndMap (PdbPath, FileName)) {
|
||
|
continue;
|
||
|
}
|
||
|
DEBUG ((DEBUG_ERROR, "ImageBase: %x\n", ImageBase));
|
||
|
|
||
|
//
|
||
|
// Check SearchType
|
||
|
//
|
||
|
if (SearchType == EdbEbcImageRvaSearchTypeAny || SearchType == EdbEbcImageRvaSearchTypeFirst) {
|
||
|
//
|
||
|
// Assign base address and return
|
||
|
//
|
||
|
Object->BaseAddress = (UINTN)ImageBase;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get CandidateImageBase for EdbEbcImageRvaSearchTypeLast
|
||
|
//
|
||
|
CandidateImageBase = ImageBase;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check EdbEbcImageRvaSearchTypeLast
|
||
|
//
|
||
|
if (SearchType == EdbEbcImageRvaSearchTypeLast) {
|
||
|
if (CandidateImageBase == NULL) {
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
//
|
||
|
// Assign base address and return
|
||
|
//
|
||
|
Object->BaseAddress = (UINTN)CandidateImageBase;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// No match
|
||
|
//
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Check whether OBJ file and COD file have same name.
|
||
|
|
||
|
@param ObjFileName - OBJ file name
|
||
|
@param CodFileName - COD file name
|
||
|
|
||
|
@retval TRUE - OBJ and COD file name match
|
||
|
@retval FALSE - OBJ and COD file name not match
|
||
|
|
||
|
**/
|
||
|
BOOLEAN
|
||
|
MatchObjAndCod (
|
||
|
IN CHAR8 *ObjFileName,
|
||
|
IN CHAR16 *CodFileName
|
||
|
)
|
||
|
{
|
||
|
UINTN ObjNameSize;
|
||
|
UINTN CodNameSize;
|
||
|
CHAR8 *PureObjFileName;
|
||
|
UINTN Index;
|
||
|
|
||
|
//
|
||
|
// remove library name
|
||
|
//
|
||
|
PureObjFileName = ObjFileName;
|
||
|
for (Index = 0; ObjFileName[Index] != 0; Index++) {
|
||
|
if (ObjFileName[Index] == ':') {
|
||
|
PureObjFileName = &ObjFileName[Index + 1];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
ObjFileName = PureObjFileName;
|
||
|
|
||
|
//
|
||
|
// get size
|
||
|
//
|
||
|
ObjNameSize = AsciiStrLen (ObjFileName);
|
||
|
CodNameSize = StrLen (CodFileName);
|
||
|
|
||
|
if (ObjNameSize != CodNameSize) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// check the name
|
||
|
//
|
||
|
for (Index = 0; Index < CodNameSize - 4; Index++) {
|
||
|
if ((ObjFileName[Index] | 0x20) != (CodFileName[Index] | 0x20)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
typedef enum {
|
||
|
EdbEbcCodParseStateUninitialized,
|
||
|
EdbEbcCodParseStateSymbolInitialized,
|
||
|
EdbEbcCodParseStateSymbolStart,
|
||
|
EdbEbcCodParseStateSymbolEnd,
|
||
|
EdbEbcCodParseStateMax,
|
||
|
} EDB_EBC_COD_PARSE_STATE;
|
||
|
|
||
|
/**
|
||
|
|
||
|
The following code depends on the COD file generated by IEC compiler.
|
||
|
|
||
|
**/
|
||
|
|
||
|
/**
|
||
|
|
||
|
Load code by symbol by Iec.
|
||
|
|
||
|
@param Name - Symbol file name
|
||
|
@param Buffer - Symbol file buffer
|
||
|
@param BufferSize - Symbol file buffer size
|
||
|
@param CodeBufferSize - Code buffer size
|
||
|
@param FuncOffset - Code funcion offset
|
||
|
|
||
|
@return CodeBuffer
|
||
|
|
||
|
**/
|
||
|
CHAR8 *
|
||
|
EdbLoadCodBySymbolByIec (
|
||
|
IN CHAR8 *Name,
|
||
|
IN VOID *Buffer,
|
||
|
IN UINTN BufferSize,
|
||
|
OUT UINTN *CodeBufferSize,
|
||
|
OUT UINTN *FuncOffset
|
||
|
)
|
||
|
{
|
||
|
CHAR8 *LineBuffer;
|
||
|
CHAR8 *FieldBuffer;
|
||
|
VOID *BufferStart;
|
||
|
VOID *BufferEnd;
|
||
|
UINTN Offset;
|
||
|
EDB_EBC_COD_PARSE_STATE CodParseState;
|
||
|
CHAR8 Char[2];
|
||
|
|
||
|
//
|
||
|
// Init
|
||
|
//
|
||
|
Char[0] = 9;
|
||
|
Char[1] = 0;
|
||
|
LineBuffer = AsciiStrGetNewTokenLine (Buffer, "\n\r");
|
||
|
Offset = (UINTN)-1;
|
||
|
BufferStart = NULL;
|
||
|
BufferEnd = NULL;
|
||
|
CodParseState = EdbEbcCodParseStateUninitialized;
|
||
|
|
||
|
//
|
||
|
// Check each line
|
||
|
//
|
||
|
while (LineBuffer != NULL) {
|
||
|
switch (CodParseState) {
|
||
|
case EdbEbcCodParseStateUninitialized:
|
||
|
//
|
||
|
// check mark_begin, begin to check line after this match
|
||
|
//
|
||
|
if (AsciiStrCmp (LineBuffer, "; mark_begin;") == 0) {
|
||
|
CodParseState = EdbEbcCodParseStateSymbolInitialized;
|
||
|
}
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
break;
|
||
|
|
||
|
case EdbEbcCodParseStateSymbolInitialized:
|
||
|
//
|
||
|
// check mark_end, not check line after this match
|
||
|
//
|
||
|
if (AsciiStrCmp (LineBuffer, "; mark_end;") == 0) {
|
||
|
CodParseState = EdbEbcCodParseStateUninitialized;
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// not check this line if the first char is as follows
|
||
|
//
|
||
|
if ((*LineBuffer == 0) ||
|
||
|
(*LineBuffer == '$') ||
|
||
|
(*LineBuffer == ';') ||
|
||
|
(*LineBuffer == '_') ||
|
||
|
(*LineBuffer == ' ')) {
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// get function name, function name is followed by char 0x09.
|
||
|
//
|
||
|
FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, Char);
|
||
|
ASSERT (FieldBuffer != NULL);
|
||
|
if (AsciiStriCmp (FieldBuffer, Name) == 0) {
|
||
|
BufferStart = FieldBuffer;
|
||
|
CodParseState = EdbEbcCodParseStateSymbolStart;
|
||
|
}
|
||
|
PatchForAsciiStrTokenAfter (FieldBuffer, 0x9);
|
||
|
|
||
|
//
|
||
|
// Get next line
|
||
|
//
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
break;
|
||
|
|
||
|
case EdbEbcCodParseStateSymbolStart:
|
||
|
//
|
||
|
// check mark_end, if this match, means the function is found successfully.
|
||
|
//
|
||
|
if (AsciiStrCmp (LineBuffer, "; mark_end;") == 0) {
|
||
|
CodParseState = EdbEbcCodParseStateSymbolEnd;
|
||
|
//
|
||
|
// prepare CodeBufferSize, FuncOffset, and FuncStart to return
|
||
|
//
|
||
|
BufferEnd = LineBuffer + sizeof("; mark_end;") - 1;
|
||
|
*CodeBufferSize = (UINTN)BufferEnd - (UINTN)BufferStart;
|
||
|
*FuncOffset = Offset;
|
||
|
PatchForAsciiStrTokenAfter (LineBuffer, '\n');
|
||
|
return BufferStart;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get function offset
|
||
|
//
|
||
|
if ((Offset == (UINTN)-1) &&
|
||
|
(*LineBuffer == ' ')) {
|
||
|
FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 2, " ");
|
||
|
Offset = AsciiXtoi (FieldBuffer);
|
||
|
PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get next line
|
||
|
//
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
break;
|
||
|
|
||
|
case EdbEbcCodParseStateSymbolEnd:
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// no function found
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Load code by symbol.
|
||
|
|
||
|
@param Name - Symbol file name
|
||
|
@param Buffer - Symbol file buffer
|
||
|
@param BufferSize - Symbol file buffer size
|
||
|
@param CodeBufferSize - Code buffer size
|
||
|
@param FuncOffset - Code funcion offset
|
||
|
|
||
|
@return CodeBuffer
|
||
|
|
||
|
**/
|
||
|
CHAR8 *
|
||
|
EdbLoadCodBySymbol (
|
||
|
IN CHAR8 *Name,
|
||
|
IN VOID *Buffer,
|
||
|
IN UINTN BufferSize,
|
||
|
OUT UINTN *CodeBufferSize,
|
||
|
OUT UINTN *FuncOffset
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// COD file format depends on the compiler.
|
||
|
//
|
||
|
// It is possible to check the different COD file format in this routine.
|
||
|
// Now only IEC is supported.
|
||
|
//
|
||
|
return EdbLoadCodBySymbolByIec (Name, Buffer, BufferSize, CodeBufferSize, FuncOffset);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Find code from object.
|
||
|
|
||
|
@param DebuggerPrivate EBC Debugger private data structure
|
||
|
@param Object - Symbol object
|
||
|
@param FileName - File name
|
||
|
|
||
|
**/
|
||
|
VOID *
|
||
|
EdbFindCodeFromObject (
|
||
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
||
|
IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
|
||
|
IN CHAR16 *FileName
|
||
|
)
|
||
|
{
|
||
|
UINTN EntryIndex;
|
||
|
|
||
|
//
|
||
|
// Go througn each Entry in this Object
|
||
|
//
|
||
|
for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
|
||
|
//
|
||
|
// This check is for Function only
|
||
|
//
|
||
|
if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
|
||
|
(Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// Skip match varbss_init function, because they has no source code
|
||
|
//
|
||
|
if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// check the name
|
||
|
//
|
||
|
if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// found it, return source buffer
|
||
|
//
|
||
|
if (Object->Entry[EntryIndex].CodBuffer != NULL) {
|
||
|
return Object->Entry[EntryIndex].SourceBuffer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// not found
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Load code.
|
||
|
|
||
|
@param DebuggerPrivate - EBC Debugger private data structure
|
||
|
@param MapFileName - Symbol file name
|
||
|
@param FileName - Code file name
|
||
|
@param BufferSize - Code file buffer size
|
||
|
@param Buffer - Code file buffer
|
||
|
|
||
|
@retval EFI_SUCCESS - Code loaded successfully
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EdbLoadCode (
|
||
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
||
|
IN CHAR16 *MapFileName,
|
||
|
IN CHAR16 *FileName,
|
||
|
IN UINTN BufferSize,
|
||
|
IN VOID *Buffer
|
||
|
)
|
||
|
{
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
||
|
UINTN ObjectIndex;
|
||
|
UINTN EntryIndex;
|
||
|
VOID *SourceBuffer;
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
//
|
||
|
// Find Symbol
|
||
|
//
|
||
|
Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, &ObjectIndex);
|
||
|
if (Object == NULL) {
|
||
|
EDBPrint (L"SymbolFile is not loaded!\n");
|
||
|
return EFI_NOT_FOUND;
|
||
|
} else {
|
||
|
//
|
||
|
// Check duplicated File
|
||
|
//
|
||
|
SourceBuffer = EdbFindCodeFromObject (DebuggerPrivate, Object, FileName);
|
||
|
if (SourceBuffer != NULL) {
|
||
|
//
|
||
|
// unnload duplicated code
|
||
|
//
|
||
|
Status = EdbUnloadCode (DebuggerPrivate, MapFileName, FileName, &SourceBuffer);
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
DEBUG ((DEBUG_ERROR, "Unload Duplicated Code File Error!\n"));
|
||
|
return Status;
|
||
|
}
|
||
|
Status = EdbDeleteCodeBuffer (DebuggerPrivate, MapFileName, FileName, SourceBuffer);
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
DEBUG ((DEBUG_ERROR, "Delete Duplicated Code File Error!\n"));
|
||
|
return Status;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Go through each SymbolEntry
|
||
|
//
|
||
|
for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
|
||
|
//
|
||
|
// load symbol for function only
|
||
|
//
|
||
|
if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
|
||
|
(Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// skip varbss_init
|
||
|
//
|
||
|
if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// Check the name
|
||
|
//
|
||
|
if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// load code for this symbol
|
||
|
//
|
||
|
Object->Entry[EntryIndex].CodBuffer = EdbLoadCodBySymbol (
|
||
|
Object->Entry[EntryIndex].Name,
|
||
|
Buffer,
|
||
|
BufferSize,
|
||
|
&Object->Entry[EntryIndex].CodBufferSize,
|
||
|
&Object->Entry[EntryIndex].FuncOffsetBase
|
||
|
);
|
||
|
if (Object->Entry[EntryIndex].CodBuffer != NULL) {
|
||
|
Object->Entry[EntryIndex].SourceBuffer = Buffer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// patch end '\0' for each code buffer
|
||
|
//
|
||
|
for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
|
||
|
if (Object->Entry[EntryIndex].CodBuffer != NULL) {
|
||
|
*((UINT8 *)Object->Entry[EntryIndex].CodBuffer + Object->Entry[EntryIndex].CodBufferSize) = 0;
|
||
|
DEBUG ((DEBUG_ERROR, " CodeSymbol: %a, FuncOffset: 0x05%x\n", Object->Entry[EntryIndex].Name, Object->Entry[EntryIndex].FuncOffsetBase));
|
||
|
// DEBUG ((DEBUG_ERROR, " [CODE]:\n%a\n", Object->Entry[EntryIndex].CodBuffer));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Done
|
||
|
//
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Unload code.
|
||
|
|
||
|
@param DebuggerPrivate - EBC Debugger private data structure
|
||
|
@param MapFileName - Symbol file name
|
||
|
@param FileName - Code file name
|
||
|
@param Buffer - Code file buffer
|
||
|
|
||
|
@retval EFI_SUCCESS - Code unloaded successfully
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EdbUnloadCode (
|
||
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
||
|
IN CHAR16 *MapFileName,
|
||
|
IN CHAR16 *FileName,
|
||
|
OUT VOID **Buffer
|
||
|
)
|
||
|
{
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
||
|
UINTN ObjectIndex;
|
||
|
UINTN EntryIndex;
|
||
|
|
||
|
//
|
||
|
// Find Symbol
|
||
|
//
|
||
|
Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, &ObjectIndex);
|
||
|
if (Object == NULL) {
|
||
|
EDBPrint (L"SymbolFile is not loaded!\n");
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find code
|
||
|
//
|
||
|
*Buffer = EdbFindCodeFromObject (DebuggerPrivate, Object, FileName);
|
||
|
if (*Buffer == NULL) {
|
||
|
EDBPrint (L"CodeFile is not loaded!\n");
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// go through each entry
|
||
|
//
|
||
|
for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
|
||
|
if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
|
||
|
(Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
|
||
|
continue;
|
||
|
}
|
||
|
if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// clean up the buffer
|
||
|
//
|
||
|
Object->Entry[EntryIndex].CodBuffer = NULL;
|
||
|
Object->Entry[EntryIndex].CodBufferSize = 0;
|
||
|
Object->Entry[EntryIndex].FuncOffsetBase = 0;
|
||
|
Object->Entry[EntryIndex].SourceBuffer = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Done
|
||
|
//
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Add code buffer.
|
||
|
|
||
|
@param DebuggerPrivate - EBC Debugger private data structure
|
||
|
@param MapFileName - Symbol file name
|
||
|
@param CodeFileName - Code file name
|
||
|
@param SourceBufferSize- Code buffer size
|
||
|
@param SourceBuffer - Code buffer
|
||
|
|
||
|
@retval EFI_SUCCESS - CodeBuffer added successfully
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EdbAddCodeBuffer (
|
||
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
||
|
IN CHAR16 *MapFileName,
|
||
|
IN CHAR16 *CodeFileName,
|
||
|
IN UINTN SourceBufferSize,
|
||
|
IN VOID *SourceBuffer
|
||
|
)
|
||
|
{
|
||
|
UINTN Index;
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
||
|
|
||
|
//
|
||
|
// Find Symbol
|
||
|
//
|
||
|
Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, NULL);
|
||
|
if (Object == NULL) {
|
||
|
EDBPrint (L"SymbolFile is not loaded!\n");
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add it to last entry
|
||
|
//
|
||
|
for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
|
||
|
;
|
||
|
}
|
||
|
Object->SourceBuffer[Index] = SourceBuffer;
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Delete code buffer.
|
||
|
|
||
|
@param DebuggerPrivate - EBC Debugger private data structure
|
||
|
@param MapFileName - Symbol file name
|
||
|
@param CodeFileName - Code file name
|
||
|
@param SourceBuffer - Code buffer
|
||
|
|
||
|
@retval EFI_SUCCESS - CodeBuffer deleted successfully
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EdbDeleteCodeBuffer (
|
||
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
||
|
IN CHAR16 *MapFileName,
|
||
|
IN CHAR16 *CodeFileName,
|
||
|
IN VOID *SourceBuffer
|
||
|
)
|
||
|
{
|
||
|
UINTN Index;
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
||
|
|
||
|
//
|
||
|
// Find Symbol
|
||
|
//
|
||
|
Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, NULL);
|
||
|
if (Object == NULL) {
|
||
|
EDBPrint (L"SymbolFile is not loaded!\n");
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
|
||
|
//
|
||
|
// free the buffer if match
|
||
|
//
|
||
|
if (Object->SourceBuffer[Index] == SourceBuffer) {
|
||
|
gBS->FreePool (SourceBuffer);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Object->SourceBuffer[Index] == NULL) {
|
||
|
//
|
||
|
// not return NOT_FOUND
|
||
|
//
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// remove the entry
|
||
|
//
|
||
|
Object->SourceBuffer[Index] = NULL;
|
||
|
for (Index = Index + 1; Object->SourceBuffer[Index] != NULL; Index++) {
|
||
|
Object->SourceBuffer[Index - 1] = Object->SourceBuffer[Index];
|
||
|
}
|
||
|
Object->SourceBuffer[Index - 1] = NULL;
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Find the symbol string according to address.
|
||
|
|
||
|
@param Address - Symbol address
|
||
|
|
||
|
@return Symbol string
|
||
|
|
||
|
**/
|
||
|
CHAR8 *
|
||
|
FindSymbolStr (
|
||
|
IN UINTN Address
|
||
|
)
|
||
|
{
|
||
|
UINTN ObjectIndex;
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
||
|
UINTN EntryIndex;
|
||
|
EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
|
||
|
|
||
|
//
|
||
|
// need we display symbol
|
||
|
//
|
||
|
if (!mDebuggerPrivate.DebuggerSymbolContext.DisplaySymbol) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Go through each object and entry
|
||
|
//
|
||
|
Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
|
||
|
for (ObjectIndex = 0; ObjectIndex < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
|
||
|
Entry = Object[ObjectIndex].Entry;
|
||
|
for (EntryIndex = 0; EntryIndex < Object[ObjectIndex].EntryCount; EntryIndex++) {
|
||
|
//
|
||
|
// if Address match, return Name
|
||
|
//
|
||
|
if (Address == (Entry[EntryIndex].Rva + Object[ObjectIndex].BaseAddress)) {
|
||
|
return Entry[EntryIndex].Name;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// not found
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Get line number and offset from this line in code file.
|
||
|
|
||
|
@param Line - Line buffer in code file
|
||
|
@param Offset - Offset to functin entry
|
||
|
|
||
|
@return Line number
|
||
|
|
||
|
**/
|
||
|
UINTN
|
||
|
EdbGetLineNumberAndOffsetFromThisLine (
|
||
|
IN VOID *Line,
|
||
|
OUT UINTN *Offset
|
||
|
)
|
||
|
{
|
||
|
UINTN LineNumber;
|
||
|
CHAR8 *LineBuffer;
|
||
|
CHAR8 *FieldBuffer;
|
||
|
|
||
|
LineNumber = (UINTN)-1;
|
||
|
LineBuffer = Line;
|
||
|
*Offset = (UINTN)-1;
|
||
|
|
||
|
while (LineBuffer != NULL) {
|
||
|
//
|
||
|
// Check candidate
|
||
|
//
|
||
|
if (*LineBuffer != ' ') {
|
||
|
return (UINTN)-1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get Offset
|
||
|
//
|
||
|
if (*(LineBuffer + 2) != ' ') {
|
||
|
if (*Offset == (UINTN)-1) {
|
||
|
FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 2, " ");
|
||
|
*Offset = AsciiXtoi (FieldBuffer);
|
||
|
PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 1. assembly instruction
|
||
|
//
|
||
|
FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, ":");
|
||
|
//
|
||
|
// 2. file path
|
||
|
//
|
||
|
FieldBuffer = AsciiStrGetNextTokenField (":");
|
||
|
PatchForAsciiStrTokenBefore (FieldBuffer, ':');
|
||
|
if (FieldBuffer == NULL) {
|
||
|
//
|
||
|
// candidate found
|
||
|
//
|
||
|
LineNumber = 0;
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// 3. line number
|
||
|
//
|
||
|
FieldBuffer = AsciiStrGetNextTokenField (":");
|
||
|
PatchForAsciiStrTokenBefore (FieldBuffer, ':');
|
||
|
if (FieldBuffer == NULL) {
|
||
|
//
|
||
|
// impossible, TBD?
|
||
|
//
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
LineNumber = AsciiAtoi (FieldBuffer);
|
||
|
//
|
||
|
// Not patch after
|
||
|
//
|
||
|
|
||
|
return LineNumber;
|
||
|
}
|
||
|
|
||
|
return (UINTN)-1;
|
||
|
}
|
||
|
|
||
|
typedef enum {
|
||
|
EdbEbcLineSearchTypeAny,
|
||
|
EdbEbcLineSearchTypeFirst,
|
||
|
EdbEbcLineSearchTypeLast,
|
||
|
EdbEbcLineSearchTypeMax,
|
||
|
} EDB_EBC_LINE_SEARCH_TYPE;
|
||
|
|
||
|
/**
|
||
|
|
||
|
Get line number from this code file.
|
||
|
|
||
|
@param Entry - Symbol entry
|
||
|
@param FuncOffset - Offset to functin entry
|
||
|
@param SearchType - Search type for the code
|
||
|
|
||
|
@return Line number
|
||
|
|
||
|
**/
|
||
|
UINTN
|
||
|
EdbGetLineNumberFromCode (
|
||
|
IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
|
||
|
IN UINTN FuncOffset,
|
||
|
IN EDB_EBC_LINE_SEARCH_TYPE SearchType
|
||
|
)
|
||
|
{
|
||
|
CHAR8 *LineBuffer;
|
||
|
UINTN LineNumber;
|
||
|
UINTN Offset;
|
||
|
UINTN CandidateLineNumber;
|
||
|
UINTN CandidateOffset;
|
||
|
|
||
|
if (SearchType < 0 || SearchType >= EdbEbcLineSearchTypeMax) {
|
||
|
return (UINTN)-1;
|
||
|
}
|
||
|
|
||
|
LineNumber = (UINTN)-1;
|
||
|
CandidateLineNumber = (UINTN)-1;
|
||
|
CandidateOffset = (UINTN)-1;
|
||
|
LineBuffer = AsciiStrGetNewTokenLine (Entry->CodBuffer, "\n");
|
||
|
while (LineBuffer != NULL) {
|
||
|
if (*LineBuffer != ' ') {
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get Info
|
||
|
//
|
||
|
LineNumber = EdbGetLineNumberAndOffsetFromThisLine (LineBuffer, &Offset);
|
||
|
|
||
|
//
|
||
|
// Check offset
|
||
|
//
|
||
|
if (Offset != FuncOffset) {
|
||
|
//
|
||
|
// Check last offset match
|
||
|
//
|
||
|
if (CandidateOffset == FuncOffset) {
|
||
|
if (SearchType == EdbEbcLineSearchTypeLast) {
|
||
|
PatchForAsciiStrTokenAfter (LineBuffer, '\n');
|
||
|
if (CandidateLineNumber != LineNumber) {
|
||
|
return CandidateLineNumber;
|
||
|
} else {
|
||
|
return (UINTN)-1;
|
||
|
}
|
||
|
} else {
|
||
|
//
|
||
|
// impossible, TBD?
|
||
|
//
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
CandidateLineNumber = LineNumber;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Offset match, more check
|
||
|
//
|
||
|
if (SearchType == EdbEbcLineSearchTypeAny) {
|
||
|
PatchForAsciiStrTokenAfter (LineBuffer, '\n');
|
||
|
return LineNumber;
|
||
|
}
|
||
|
|
||
|
if (SearchType == EdbEbcLineSearchTypeFirst) {
|
||
|
//
|
||
|
// Check last line
|
||
|
//
|
||
|
PatchForAsciiStrTokenAfter (LineBuffer, '\n');
|
||
|
if (CandidateLineNumber != LineNumber) {
|
||
|
return LineNumber;
|
||
|
} else {
|
||
|
return (UINTN)-1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CandidateLineNumber = LineNumber;
|
||
|
CandidateOffset = Offset;
|
||
|
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check last offset match
|
||
|
//
|
||
|
if (CandidateOffset == FuncOffset) {
|
||
|
if (SearchType == EdbEbcLineSearchTypeLast) {
|
||
|
return CandidateLineNumber;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (UINTN)-1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Get the source string from this code file by line.
|
||
|
|
||
|
@param Entry - Symbol entry
|
||
|
@param LineNumber - line number
|
||
|
@param FuncEnd - Function end
|
||
|
|
||
|
@return Funtion start
|
||
|
|
||
|
**/
|
||
|
VOID *
|
||
|
EdbGetSourceStrFromCodeByLine (
|
||
|
IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
|
||
|
IN UINTN LineNumber,
|
||
|
IN VOID **FuncEnd
|
||
|
)
|
||
|
{
|
||
|
CHAR8 *LineBuffer;
|
||
|
CHAR8 *FieldBuffer;
|
||
|
VOID *FuncStart;
|
||
|
UINTN Number;
|
||
|
|
||
|
FuncStart = NULL;
|
||
|
LineBuffer = AsciiStrGetNewTokenLine (Entry->CodBuffer, "\n");
|
||
|
while (LineBuffer != NULL) {
|
||
|
if (*LineBuffer != ';') {
|
||
|
if (FuncStart != NULL) {
|
||
|
//
|
||
|
// Over
|
||
|
//
|
||
|
*FuncEnd = LineBuffer - 1;
|
||
|
PatchForAsciiStrTokenAfter (LineBuffer, '\n');
|
||
|
return FuncStart;
|
||
|
}
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check LineNumber
|
||
|
//
|
||
|
FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 1, " ");
|
||
|
Number = AsciiAtoi (FieldBuffer);
|
||
|
PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
|
||
|
if (Number != LineNumber) {
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Line match, get line number
|
||
|
//
|
||
|
if (FuncStart == NULL) {
|
||
|
FuncStart = LineBuffer;
|
||
|
}
|
||
|
|
||
|
LineBuffer = AsciiStrGetNextTokenLine ("\n");
|
||
|
PatchForAsciiStrTokenBefore (LineBuffer, '\n');
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Get source string from this code file.
|
||
|
|
||
|
@param Entry - Symbol entry
|
||
|
@param FuncOffset - Offset to functin entry
|
||
|
@param FuncEnd - Function end
|
||
|
|
||
|
@retval Funtion start
|
||
|
|
||
|
**/
|
||
|
VOID *
|
||
|
EdbGetSourceStrFromCode (
|
||
|
IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
|
||
|
IN UINTN FuncOffset,
|
||
|
IN VOID **FuncEnd
|
||
|
)
|
||
|
{
|
||
|
UINTN LineNumber;
|
||
|
|
||
|
//
|
||
|
// Only search the last line, then display
|
||
|
//
|
||
|
LineNumber = EdbGetLineNumberFromCode (Entry, FuncOffset, EdbEbcLineSearchTypeLast);
|
||
|
if (LineNumber == (UINTN)-1) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return EdbGetSourceStrFromCodeByLine (Entry, LineNumber, FuncEnd);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Print source.
|
||
|
|
||
|
@param Address - Instruction address
|
||
|
@param IsPrint - Whether need to print
|
||
|
|
||
|
@retval 1 - find the source
|
||
|
@retval 0 - not find the source
|
||
|
|
||
|
**/
|
||
|
UINTN
|
||
|
EdbPrintSource (
|
||
|
IN UINTN Address,
|
||
|
IN BOOLEAN IsPrint
|
||
|
)
|
||
|
{
|
||
|
UINTN SymbolAddress;
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *RetObject;
|
||
|
EFI_DEBUGGER_SYMBOL_ENTRY *RetEntry;
|
||
|
UINTN FuncOffset;
|
||
|
UINT8 *FuncStart;
|
||
|
UINT8 *FuncEnd;
|
||
|
UINT8 *FuncIndex;
|
||
|
CHAR8 Buffer[EFI_DEBUG_MAX_PRINT_BUFFER];
|
||
|
UINTN BufferSize;
|
||
|
|
||
|
//
|
||
|
// need we display symbol
|
||
|
//
|
||
|
if (!mDebuggerPrivate.DebuggerSymbolContext.DisplaySymbol) {
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// find the symbol address
|
||
|
//
|
||
|
SymbolAddress = EbdFindSymbolAddress (
|
||
|
Address,
|
||
|
EdbMatchSymbolTypeLowerAddress,
|
||
|
&RetObject,
|
||
|
&RetEntry
|
||
|
);
|
||
|
if (SymbolAddress == 0) {
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
FuncOffset = Address - SymbolAddress + RetEntry->FuncOffsetBase;
|
||
|
|
||
|
//
|
||
|
// Get Func String
|
||
|
//
|
||
|
FuncStart = EdbGetSourceStrFromCode (RetEntry, FuncOffset, (VOID**) &FuncEnd);
|
||
|
if (FuncStart == NULL) {
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// check whether need to real print
|
||
|
//
|
||
|
if (!IsPrint) {
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
*(UINT8 *)FuncEnd = 0;
|
||
|
|
||
|
//
|
||
|
// seperate buffer by \n, so that \r can be added.
|
||
|
//
|
||
|
FuncIndex = FuncStart;
|
||
|
while (*FuncIndex != 0) {
|
||
|
if (*FuncIndex == '\n') {
|
||
|
if ((FuncIndex - FuncStart) < (EFI_DEBUG_MAX_PRINT_BUFFER - 3)) {
|
||
|
BufferSize = FuncIndex - FuncStart;
|
||
|
} else {
|
||
|
BufferSize = EFI_DEBUG_MAX_PRINT_BUFFER - 3;
|
||
|
}
|
||
|
if (BufferSize != 0) {
|
||
|
CopyMem (Buffer, FuncStart, BufferSize);
|
||
|
}
|
||
|
Buffer[BufferSize] = 0;
|
||
|
EDBPrint (L"%a\n", Buffer);
|
||
|
FuncStart = FuncIndex + 1;
|
||
|
FuncIndex = FuncStart;
|
||
|
} else {
|
||
|
FuncIndex ++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Patch the end
|
||
|
//
|
||
|
*(UINT8 *)FuncEnd = '\n';
|
||
|
|
||
|
return 1 ;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Get Mapfile and SymbolName from one symbol format: [MapFileName:]SymbolName.
|
||
|
|
||
|
@param Symbol - whole Symbol name
|
||
|
@param MapfileName - the mapfile name in the symbol
|
||
|
@param SymbolName - the symbol name in the symbol
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
GetMapfileAndSymbol (
|
||
|
IN CHAR16 *Symbol,
|
||
|
OUT CHAR16 **MapfileName,
|
||
|
OUT CHAR16 **SymbolName
|
||
|
)
|
||
|
{
|
||
|
CHAR16 *Ch;
|
||
|
|
||
|
*MapfileName = NULL;
|
||
|
*SymbolName = Symbol;
|
||
|
|
||
|
for (Ch = Symbol; *Ch != 0; Ch++) {
|
||
|
//
|
||
|
// Find split char
|
||
|
//
|
||
|
if (*Ch == L':') {
|
||
|
*MapfileName = Symbol;
|
||
|
*Ch = 0;
|
||
|
*SymbolName = Ch + 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Convert a symbol to an address.
|
||
|
|
||
|
@param Symbol - Symbol name
|
||
|
@param Address - Symbol address
|
||
|
|
||
|
@retval EFI_SUCCESS - symbol found and address returned.
|
||
|
@retval EFI_NOT_FOUND - symbol not found
|
||
|
@retval EFI_NO_MAPPING - duplicated symbol not found
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
Symboltoi (
|
||
|
IN CHAR16 *Symbol,
|
||
|
OUT UINTN *Address
|
||
|
)
|
||
|
{
|
||
|
UINTN ObjectIndex;
|
||
|
EFI_DEBUGGER_SYMBOL_OBJECT *Object;
|
||
|
UINTN EntryIndex;
|
||
|
EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
|
||
|
CHAR16 *SymbolName;
|
||
|
CHAR16 *MapfileName;
|
||
|
|
||
|
//
|
||
|
// Split one symbol to mapfile name and symbol name
|
||
|
//
|
||
|
GetMapfileAndSymbol (Symbol, &MapfileName, &SymbolName);
|
||
|
|
||
|
*Address = 0;
|
||
|
//
|
||
|
// Go through each object
|
||
|
//
|
||
|
Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
|
||
|
for (ObjectIndex = 0; ObjectIndex < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
|
||
|
//
|
||
|
// Check MapfileName
|
||
|
//
|
||
|
if ((MapfileName != NULL) && (StriCmp (Object[ObjectIndex].Name, MapfileName) != 0)) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// Go through each entry
|
||
|
//
|
||
|
Entry = Object[ObjectIndex].Entry;
|
||
|
for (EntryIndex = 0; EntryIndex < Object[ObjectIndex].EntryCount; EntryIndex++) {
|
||
|
//
|
||
|
// Check SymbolName (case sensitive)
|
||
|
//
|
||
|
if (StrCmpUnicodeAndAscii (SymbolName, Entry[EntryIndex].Name) == 0) {
|
||
|
if ((*Address != 0) && (MapfileName == NULL)) {
|
||
|
//
|
||
|
// Find the duplicated symbol
|
||
|
//
|
||
|
EDBPrint (L"Duplicated Symbol found!\n");
|
||
|
return EFI_NO_MAPPING;
|
||
|
} else {
|
||
|
//
|
||
|
// record Address
|
||
|
//
|
||
|
*Address = (Entry[EntryIndex].Rva + Object[ObjectIndex].BaseAddress);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (*Address == 0) {
|
||
|
//
|
||
|
// Not found
|
||
|
//
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|