mirror of https://github.com/acidanthera/audk.git
2670 lines
70 KiB
C
2670 lines
70 KiB
C
/*++
|
|
|
|
Copyright (c) 2007, 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);
|
|
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;
|
|
}
|