In function EdbLoadCodBySymbolByIec(), AsciiStrGetNewTokenField() at line 1589 will return NULL if the first character in 'LineBuffer' is '\0'. But the previous if statement at line 1576 ensures the above case will not happen. This commit adds ASSERT as warnings for the case that will not happen. Cc: Jiewen Yao <jiewen.yao@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2671 lines
70 KiB
C
2671 lines
70 KiB
C
/*++
|
|
|
|
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.
|
|
|
|
Module Name:
|
|
|
|
EdbSymbol.c
|
|
|
|
Abstract:
|
|
|
|
|
|
--*/
|
|
|
|
#include "Edb.h"
|
|
|
|
EFI_STATUS
|
|
EdbLoadSymbolSingleEntry (
|
|
IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
|
|
IN CHAR8 *Name,
|
|
IN CHAR8 *ObjName,
|
|
IN UINTN Address,
|
|
IN EFI_DEBUGGER_SYMBOL_TYPE Type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load single symbol entry
|
|
|
|
Arguments:
|
|
|
|
Object - Symbol file object
|
|
Name - Symbol name
|
|
ObjName - Object name
|
|
Address - Symbol address
|
|
Type - Symbol type
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - add single symbol entry successfully
|
|
|
|
--*/
|
|
{
|
|
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
|
|
===============================================================================
|
|
|
|
--*/
|
|
EFI_STATUS
|
|
EdbLoadSymbolEntryByIec (
|
|
IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load symbol entry by Iec
|
|
|
|
Arguments:
|
|
|
|
DebuggerPrivate - EBC Debugger private data structure
|
|
Object - Symbol file object
|
|
BufferSize - Symbol file buffer size
|
|
Buffer - Symbol file buffer
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - add symbol entry successfully
|
|
|
|
--*/
|
|
{
|
|
CHAR8 *LineBuffer;
|
|
CHAR8 *FieldBuffer;
|
|
EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
|
|
EDB_EBC_MAP_PARSE_STATE MapParseState;
|
|
EDB_EBC_SYMBOL_PARSE_STATE SymbolParseState;
|
|
CHAR8 *Name;
|
|
CHAR8 *ObjName;
|
|
UINTN Address;
|
|
EFI_DEBUGGER_SYMBOL_TYPE Type;
|
|
|
|
Entry = Object->Entry;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EdbLoadSymbolEntry (
|
|
IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load symbol entry
|
|
|
|
Arguments:
|
|
|
|
Object - Symbol file object
|
|
BufferSize - Symbol file buffer size
|
|
Buffer - Symbol file buffer
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - add symbol entry successfully
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
EFI_DEBUGGER_SYMBOL_OBJECT *
|
|
EdbFindSymbolFile (
|
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
|
IN CHAR16 *FileName,
|
|
IN OUT UINTN *Index OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find symbol file by name
|
|
|
|
Arguments:
|
|
|
|
DebuggerPrivate - EBC Debugger private data structure
|
|
FileName - Symbol file name
|
|
Index - Symbol file index
|
|
|
|
Returns:
|
|
|
|
Object
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
UINTN
|
|
EbdFindSymbolAddress (
|
|
IN UINTN Address,
|
|
IN EDB_MATCH_SYMBOL_TYPE Type,
|
|
OUT EFI_DEBUGGER_SYMBOL_OBJECT **RetObject,
|
|
OUT EFI_DEBUGGER_SYMBOL_ENTRY **RetEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find symbol by address
|
|
|
|
Arguments:
|
|
|
|
Address - Symbol address
|
|
Type - Search type
|
|
RetObject - Symbol object
|
|
RetEntry - Symbol entry
|
|
|
|
Returns:
|
|
|
|
Nearest symbol address
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EdbUnloadSymbol (
|
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
|
IN CHAR16 *FileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unload symbol file by name
|
|
|
|
Arguments:
|
|
|
|
DebuggerPrivate - EBC Debugger private data structure
|
|
FileName - Symbol file name
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - unload symbol successfully
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EdbLoadSymbol (
|
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
|
IN CHAR16 *FileName,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load symbol file by name
|
|
|
|
Arguments:
|
|
|
|
DebuggerPrivate - EBC Debugger private data structure
|
|
FileName - Symbol file name
|
|
BufferSize - Symbol file buffer size
|
|
Buffer - Symbol file buffer
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - load symbol successfully
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
CHAR8 *
|
|
GetPdbPath (
|
|
VOID *ImageBase
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Located PDB path name in PE image
|
|
|
|
Arguments:
|
|
|
|
ImageBase - base of PE to search
|
|
|
|
Returns:
|
|
|
|
Pointer into image at offset of PDB file name if PDB file name is found,
|
|
Otherwise a pointer to an empty string.
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
BOOLEAN
|
|
MatchPdbAndMap (
|
|
IN CHAR8 *PdbFileName,
|
|
IN CHAR16 *MapFileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check whether PDB file and MAP file have same name
|
|
|
|
Arguments:
|
|
|
|
PdbFileName - PDB file name
|
|
MapFileName - MAP file name
|
|
|
|
Returns:
|
|
|
|
TRUE - PDB and MAP file name match
|
|
FALSE - PDB and MAP file name not match
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
|
|
VOID
|
|
EdbFixDebugImageInfoTable (
|
|
IN OUT EFI_DEBUG_IMAGE_INFO_TABLE_HEADER **DebugImageInfoTableHeader
|
|
)
|
|
/*
|
|
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 | | |
|
|
+------------------------+ +------------------------+
|
|
|
|
*/
|
|
{
|
|
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
|
|
//
|
|
|
|
EFI_STATUS
|
|
EdbPatchSymbolRVA (
|
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
|
IN CHAR16 *FileName,
|
|
IN EDB_EBC_IMAGE_RVA_SEARCH_TYPE SearchType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Patch symbol RVA
|
|
|
|
Arguments:
|
|
|
|
DebuggerPrivate - EBC Debugger private data structure
|
|
FileName - Symbol file name
|
|
SearchType - Search type for Object
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Patch symbol RVA successfully
|
|
EFI_NOT_FOUND - Symbol RVA base not found
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
BOOLEAN
|
|
MatchObjAndCod (
|
|
IN CHAR8 *ObjFileName,
|
|
IN CHAR16 *CodFileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check whether OBJ file and COD file have same name
|
|
|
|
Arguments:
|
|
|
|
ObjFileName - OBJ file name
|
|
CodFileName - COD file name
|
|
|
|
Returns:
|
|
|
|
TRUE - OBJ and COD file name match
|
|
FALSE - OBJ and COD file name not match
|
|
|
|
--*/
|
|
{
|
|
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.
|
|
|
|
Sample as follows: EbcTest.cod
|
|
===============================================================================
|
|
; -- Machine type EFI
|
|
; mark_description "Intel(R) C Compiler for EFI Byte Code, Version 1.2 Build 20040123";
|
|
; mark_description "XXX";
|
|
;ident "Intel(R) C Compiler for EFI Byte Code, Version 1.2 Build 20040123"
|
|
;ident "XXX"
|
|
.686P
|
|
.387
|
|
_TEXT SEGMENT PARA PUBLIC USE32 'CODE'
|
|
_TEXT ENDS
|
|
_DATA SEGMENT PARA PUBLIC USE32 'DATA'
|
|
ALIGN 010H
|
|
_DATA ENDS
|
|
_BSS SEGMENT PARA PUBLIC USE32 'BSS'
|
|
ALIGN 010H
|
|
_BSS ENDS
|
|
_VARBSS SEGMENT PARA PUBLIC USE32 'BSS'
|
|
ALIGN 010H
|
|
_VARBSS ENDS
|
|
ASSUME CS:FLAT,DS:FLAT,SS:FLAT
|
|
_DATA SEGMENT PARA PUBLIC USE32 'DATA'
|
|
TestVariable2 DD 000000003H,000000000H ; u64
|
|
_DATA ENDS
|
|
_DATA SEGMENT PARA PUBLIC USE32 'DATA'
|
|
_DATA ENDS
|
|
_TEXT SEGMENT PARA PUBLIC USE32 'CODE'
|
|
; -- Begin EfiMain
|
|
; mark_begin;
|
|
PUBLIC EfiMain
|
|
EfiMain PROC NEAR
|
|
$B3$1:; 11a
|
|
$LN45:
|
|
|
|
;117 ; {
|
|
|
|
0011a 60 00 70 80 MOVqw R0, R0(+0,-112) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:117
|
|
$LN46:
|
|
|
|
;118 ; UINT16 test = 0x1234;
|
|
|
|
0011e 77 58 58 00 34
|
|
12 MOVIww @R0(+0,+88), +4660 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:118
|
|
$LN47:
|
|
|
|
;121 ; EFI_STATUS Status;
|
|
;121 ;
|
|
;121 ; SystemTable->ConOut->OutputString (
|
|
|
|
00124 72 87 01 12 MOVnw R7, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:121
|
|
00128 72 f7 85 21 MOVnw R7, @R7(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:121
|
|
$LN48:
|
|
|
|
;122 ; SystemTable->ConOut,
|
|
|
|
0012c 72 84 01 12 MOVnw R4, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
|
|
00130 72 c8 85 21 MOVnw @R0, @R4(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
|
|
00134 b9 34 00 00 00
|
|
00 MOVreld R4, __STRING$1 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
|
|
0013a b2 48 01 10 MOVnw @R0(+1,+0), R4 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
|
|
0013e 83 2f 01 00 00
|
|
10 CALLEX @R7(+1,+0) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
|
|
$B3$2:; 144
|
|
$LN49:
|
|
|
|
;125 ; L"Hello EBC Test!\n\r"
|
|
;125 ; );
|
|
;125 ; EFI_BREAKPOINT ();
|
|
|
|
00144 00 03 BREAK 3 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:125
|
|
$B3$3:; 146
|
|
$LN50:
|
|
|
|
;126 ; TestVariable1 = 6;
|
|
|
|
00146 b9 37 00 00 00
|
|
00 MOVreld R7, TestVariable1 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:126
|
|
0014c 78 0f 06 00 MOVInw @R7, (0,6) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:126
|
|
$LN51:
|
|
|
|
;127 ; TestSubRoutineSub (1, 5);
|
|
|
|
00150 78 08 01 00 MOVInw @R0, (0,1) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:127
|
|
00154 78 48 01 10 05
|
|
00 MOVInw @R0(1,0), (0,5) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:127
|
|
0015a 83 10 00 00 00
|
|
00 CALL TestSubRoutineSub ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:127
|
|
$B3$4:; 160
|
|
$LN52:
|
|
|
|
;129 ;
|
|
;129 ; SystemTable->ConOut->OutputString (
|
|
|
|
00160 72 87 01 12 MOVnw R7, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:129
|
|
00164 72 f7 85 21 MOVnw R7, @R7(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:129
|
|
$LN53:
|
|
|
|
;130 ; SystemTable->ConOut,
|
|
|
|
00168 72 84 01 12 MOVnw R4, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:130
|
|
0016c 72 c8 85 21 MOVnw @R0, @R4(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:130
|
|
$LN54:
|
|
|
|
;131 ; TestStr
|
|
|
|
00170 b9 34 00 00 00
|
|
00 MOVreld R4, TestStr ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:131
|
|
00176 b2 c8 01 10 MOVnw @R0(+1, +0), @R4 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:131
|
|
0017a 83 2f 01 00 00
|
|
10 CALLEX @R7(+1,+0) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:131
|
|
$B3$5:; 180
|
|
$LN55:
|
|
|
|
;134 ; );
|
|
;134 ;
|
|
;134 ; test = test & 0xFF;
|
|
|
|
00180 de 88 58 00 58
|
|
00 MOVww @R0(+0,+88), @R0(+0,+88) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:134
|
|
$LN56:
|
|
|
|
;139 ; if (test != 0x34) {
|
|
;139 ; // EFI_BREAKPOINT ();
|
|
;139 ; }
|
|
;139 ;
|
|
;139 ; Status = TestSubRoutine (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
|
|
|
00186 78 08 01 00 MOVInw @R0, (0,1) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
0018a 78 48 01 10 02
|
|
00 MOVInw @R0(1,0), (0,2) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
00190 78 48 02 10 03
|
|
00 MOVInw @R0(2,0), (0,3) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
00196 78 48 03 10 04
|
|
00 MOVInw @R0(3,0), (0,4) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
0019c 78 48 04 20 05
|
|
00 MOVInw @R0(4,0), (0,5) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
001a2 78 48 05 20 06
|
|
00 MOVInw @R0(5,0), (0,6) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
001a8 78 48 06 20 07
|
|
00 MOVInw @R0(6,0), (0,7) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
001ae 78 48 07 20 08
|
|
00 MOVInw @R0(7,0), (0,8) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
001b4 78 48 08 20 09
|
|
00 MOVInw @R0(8,0), (0,9) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
001ba 78 48 09 20 0a
|
|
00 MOVInw @R0(9,0), (0,10) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
001c0 83 10 00 00 00
|
|
00 CALL TestSubRoutine ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
$B3$10:; 1c6
|
|
001c6 b2 78 60 00 MOVnw @R0(+0,+96), R7 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
$B3$6:; 1ca
|
|
$LN57:
|
|
001ca f2 88 50 00 60
|
|
00 MOVnw @R0(+0,+80), @R0(+0,+96) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
|
|
$LN58:
|
|
|
|
;141 ;
|
|
;141 ; SystemTable->ConOut->OutputString (
|
|
|
|
001d0 72 87 01 12 MOVnw R7, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:141
|
|
001d4 72 f7 85 21 MOVnw R7, @R7(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:141
|
|
$LN59:
|
|
|
|
;142 ; SystemTable->ConOut,
|
|
|
|
001d8 72 84 01 12 MOVnw R4, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
|
|
001dc 72 c8 85 21 MOVnw @R0, @R4(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
|
|
001e0 b9 34 00 00 00
|
|
00 MOVreld R4, __STRING$2 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
|
|
001e6 b2 48 01 10 MOVnw @R0(+1,+0), R4 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
|
|
001ea 83 2f 01 00 00
|
|
10 CALLEX @R7(+1,+0) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
|
|
$B3$7:; 1f0
|
|
$LN60:
|
|
|
|
;146 ; L"Goodbye EBC Test!\n\r"
|
|
;146 ; );
|
|
;146 ;
|
|
;146 ; return Status;
|
|
|
|
001f0 72 87 50 00 MOVnw R7, @R0(+0,+80) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:146
|
|
001f4 60 00 70 00 MOVqw R0, R0(+0,+112) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:146
|
|
001f8 04 00 RET ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:146
|
|
; mark_end;
|
|
EfiMain ENDP
|
|
_TEXT ENDS
|
|
_DATA SEGMENT PARA PUBLIC USE32 'DATA'
|
|
DB 3 DUP (0) ; pad
|
|
__STRING$2 DW 71 ; u16
|
|
DW 111 ; u16
|
|
DW 111 ; u16
|
|
DW 100 ; u16
|
|
DW 98 ; u16
|
|
DW 121 ; u16
|
|
DW 101 ; u16
|
|
DW 32 ; u16
|
|
DW 69 ; u16
|
|
DW 66 ; u16
|
|
DW 67 ; u16
|
|
DW 32 ; u16
|
|
DW 84 ; u16
|
|
DW 101 ; u16
|
|
DW 115 ; u16
|
|
DW 116 ; u16
|
|
DW 33 ; u16
|
|
DW 10 ; u16
|
|
DW 13 ; u16
|
|
DW 0 ; u16
|
|
__STRING$1 DW 72 ; u16
|
|
DW 101 ; u16
|
|
DW 108 ; u16
|
|
DW 108 ; u16
|
|
DW 111 ; u16
|
|
DW 32 ; u16
|
|
DW 69 ; u16
|
|
DW 66 ; u16
|
|
DW 67 ; u16
|
|
DW 32 ; u16
|
|
DW 84 ; u16
|
|
DW 101 ; u16
|
|
DW 115 ; u16
|
|
DW 116 ; u16
|
|
DW 33 ; u16
|
|
DW 10 ; u16
|
|
DW 13 ; u16
|
|
DW 0 ; u16
|
|
_DATA ENDS
|
|
_DATA SEGMENT PARA PUBLIC USE32 'DATA'
|
|
_DATA ENDS
|
|
; -- End EfiMain
|
|
_DATA SEGMENT PARA PUBLIC USE32 'DATA'
|
|
__STRING$0 DW 55 ; u16
|
|
DW 56 ; u16
|
|
DW 57 ; u16
|
|
DW 52 ; u16
|
|
DW 53 ; u16
|
|
DW 54 ; u16
|
|
DW 49 ; u16
|
|
DW 50 ; u16
|
|
DW 51 ; u16
|
|
DW 13 ; u16
|
|
DW 10 ; u16
|
|
DW 0 ; u16
|
|
_DATA ENDS
|
|
_VARBSS SEGMENT PARA PUBLIC USE32 'BSS'
|
|
PUBLIC TestStr
|
|
TestStr DD 2 DUP (?) ; pad
|
|
PUBLIC TestVariable1
|
|
TestVariable1 DD 2 DUP (?) ; pad
|
|
_VARBSS ENDS
|
|
_VARBSS_INIT SEGMENT DWORD PUBLIC USE32 'CODE'
|
|
; -- Begin varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2
|
|
PUBLIC varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2
|
|
varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2 PROC NEAR
|
|
00000 b9 34 00 00 00
|
|
00 MOVreld R4, TestStr
|
|
00006 b9 35 00 00 00
|
|
00 MOVreld R5, __STRING$0
|
|
0000c 33 5c MOVnd @R4, R5
|
|
0000e b9 34 00 00 00
|
|
00 MOVreld R4, TestVariable1
|
|
00014 78 0c 04 00 MOVInw @R4, (0,4)
|
|
00018 04 00 RET
|
|
; -- End varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2
|
|
_VARBSS_INIT ENDS
|
|
_DATA SEGMENT PARA PUBLIC USE32 'DATA'
|
|
_DATA ENDS
|
|
EXTRN TestSubRoutineSub:PROC
|
|
END
|
|
|
|
===============================================================================
|
|
|
|
--*/
|
|
CHAR8 *
|
|
EdbLoadCodBySymbolByIec (
|
|
IN CHAR8 *Name,
|
|
IN VOID *Buffer,
|
|
IN UINTN BufferSize,
|
|
OUT UINTN *CodeBufferSize,
|
|
OUT UINTN *FuncOffset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load code by symbol by Iec
|
|
|
|
Arguments:
|
|
|
|
Name - Symbol file name
|
|
BufferSize - Symbol file buffer size
|
|
Buffer - Symbol file buffer
|
|
CodeBufferSize - Code buffer size
|
|
FuncOffset - Code funcion offset
|
|
|
|
Returns:
|
|
|
|
CodeBuffer
|
|
|
|
--*/
|
|
{
|
|
CHAR8 *LineBuffer;
|
|
CHAR8 *FieldBuffer;
|
|
VOID *BufferStart;
|
|
VOID *BufferEnd;
|
|
UINTN Offset;
|
|
EDB_EBC_COD_PARSE_STATE CodParseState;
|
|
CHAR8 Char[2] = {9, 0};
|
|
|
|
//
|
|
// Init
|
|
//
|
|
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;
|
|
}
|
|
|
|
CHAR8 *
|
|
EdbLoadCodBySymbol (
|
|
IN CHAR8 *Name,
|
|
IN VOID *Buffer,
|
|
IN UINTN BufferSize,
|
|
OUT UINTN *CodeBufferSize,
|
|
OUT UINTN *FuncOffset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load code by symbol
|
|
|
|
Arguments:
|
|
|
|
Name - Symbol file name
|
|
BufferSize - Symbol file buffer size
|
|
Buffer - Symbol file buffer
|
|
CodeBufferSize - Code buffer size
|
|
FuncOffset - Code funcion offset
|
|
|
|
Returns:
|
|
|
|
CodeBuffer
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
VOID *
|
|
EdbFindCodeFromObject (
|
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
|
IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
|
|
IN CHAR16 *FileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find code from object
|
|
|
|
Arguments:
|
|
|
|
Object - Symbol object
|
|
FileName - File name
|
|
|
|
Returns:
|
|
|
|
CodeBuffer
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EdbLoadCode (
|
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
|
IN CHAR16 *MapFileName,
|
|
IN CHAR16 *FileName,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load code
|
|
|
|
Arguments:
|
|
|
|
DebuggerPrivate - EBC Debugger private data structure
|
|
MapFileName - Symbol file name
|
|
FileName - Code file name
|
|
BufferSize - Code file buffer size
|
|
Buffer - Code file buffer
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Code loaded successfully
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EdbUnloadCode (
|
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
|
IN CHAR16 *MapFileName,
|
|
IN CHAR16 *FileName,
|
|
OUT VOID **Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unload code
|
|
|
|
Arguments:
|
|
|
|
DebuggerPrivate - EBC Debugger private data structure
|
|
MapFileName - Symbol file name
|
|
FileName - Code file name
|
|
Buffer - Code file buffer
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Code unloaded successfully
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EdbAddCodeBuffer (
|
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
|
IN CHAR16 *MapFileName,
|
|
IN CHAR16 *CodeFileName,
|
|
IN UINTN SourceBufferSize,
|
|
IN VOID *SourceBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add code buffer
|
|
|
|
Arguments:
|
|
|
|
DebuggerPrivate - EBC Debugger private data structure
|
|
MapFileName - Symbol file name
|
|
CodeFileName - Code file name
|
|
SourceBufferSize- Code buffer size
|
|
SourceBuffer - Code buffer
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - CodeBuffer added successfully
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EdbDeleteCodeBuffer (
|
|
IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
|
|
IN CHAR16 *MapFileName,
|
|
IN CHAR16 *CodeFileName,
|
|
IN VOID *SourceBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete code buffer
|
|
|
|
Arguments:
|
|
|
|
DebuggerPrivate - EBC Debugger private data structure
|
|
MapFileName - Symbol file name
|
|
CodeFileName - Code file name
|
|
SourceBuffer - Code buffer
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - CodeBuffer deleted successfully
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
CHAR8 *
|
|
FindSymbolStr (
|
|
IN UINTN Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find the symbol string according to address
|
|
|
|
Arguments:
|
|
|
|
Address - Symbol address
|
|
|
|
Returns:
|
|
|
|
Symbol string
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
UINTN
|
|
EdbGetLineNumberAndOffsetFromThisLine (
|
|
IN VOID *Line,
|
|
OUT UINTN *Offset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get line number and offset from this line in code file
|
|
|
|
Arguments:
|
|
|
|
Line - Line buffer in code file
|
|
Offset - Offset to functin entry
|
|
|
|
Returns:
|
|
|
|
Line number
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
|
|
UINTN
|
|
EdbGetLineNumberFromCode (
|
|
IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
|
|
IN UINTN FuncOffset,
|
|
IN EDB_EBC_LINE_SEARCH_TYPE SearchType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get line number from this code file
|
|
|
|
Arguments:
|
|
|
|
Entry - Symbol entry
|
|
FuncOffset - Offset to functin entry
|
|
SearchType - Search type for the code
|
|
|
|
Returns:
|
|
|
|
Line number
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
VOID *
|
|
EdbGetSourceStrFromCodeByLine (
|
|
IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
|
|
IN UINTN LineNumber,
|
|
IN VOID **FuncEnd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the source string from this code file by line
|
|
|
|
Arguments:
|
|
|
|
Entry - Symbol entry
|
|
LineNumber - line number
|
|
FuncEnd - Function end
|
|
|
|
Returns:
|
|
|
|
Funtion start
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
VOID *
|
|
EdbGetSourceStrFromCode (
|
|
IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
|
|
IN UINTN FuncOffset,
|
|
IN VOID **FuncEnd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get source string from this code file
|
|
|
|
Arguments:
|
|
|
|
Entry - Symbol entry
|
|
FuncOffset - Offset to functin entry
|
|
FuncEnd - Function end
|
|
|
|
Returns:
|
|
|
|
Funtion start
|
|
|
|
--*/
|
|
{
|
|
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);
|
|
}
|
|
|
|
UINTN
|
|
EdbPrintSource (
|
|
IN UINTN Address,
|
|
IN BOOLEAN IsPrint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Print source
|
|
|
|
Arguments:
|
|
|
|
Address - Instruction address
|
|
IsPrint - Whether need to print
|
|
|
|
Returns:
|
|
|
|
1 - find the source
|
|
0 - not find the source
|
|
|
|
--*/
|
|
{
|
|
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 ;
|
|
}
|
|
|
|
VOID
|
|
GetMapfileAndSymbol (
|
|
IN CHAR16 *Symbol,
|
|
OUT CHAR16 **MapfileName,
|
|
OUT CHAR16 **SymbolName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get Mapfile and SymbolName from one symbol format: [MapFileName:]SymbolName
|
|
|
|
Arguments:
|
|
|
|
Symbol - whole Symbol name
|
|
MapfileName - the mapfile name in the symbol
|
|
SymbolName - the symbol name in the symbol
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
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 ;
|
|
}
|
|
|
|
EFI_STATUS
|
|
Symboltoi (
|
|
IN CHAR16 *Symbol,
|
|
OUT UINTN *Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a symbol to an address
|
|
|
|
Arguments:
|
|
|
|
Symbol - Symbol name
|
|
Address - Symbol address
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - symbol found and address returned.
|
|
EFI_NOT_FOUND - symbol not found
|
|
EFI_NO_MAPPING - duplicated symbol not found
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|