windows-nt/Source/XPSP1/NT/sdktools/debuggers/imagehlp/fecache.c
2020-09-26 16:20:57 +08:00

924 lines
28 KiB
C

//----------------------------------------------------------------------------
//
// Function entry cache.
//
// Copyright (C) Microsoft Corporation, 2000.
//
//----------------------------------------------------------------------------
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntimage.h>
#define NOEXTAPI
#include <wdbgexts.h>
#include <ntdbg.h>
#include "private.h"
#include "symbols.h"
#include "globals.h"
#include "fecache.hpp"
//----------------------------------------------------------------------------
//
// FunctionEntryCache.
//
//----------------------------------------------------------------------------
FunctionEntryCache::FunctionEntryCache(ULONG ImageDataSize,
ULONG CacheDataSize,
ULONG Machine)
{
m_ImageDataSize = ImageDataSize;
m_CacheDataSize = CacheDataSize;
m_Machine = Machine;
m_Entries = NULL;
}
FunctionEntryCache::~FunctionEntryCache(void)
{
if (m_Entries != NULL)
{
MemFree(m_Entries);
}
}
BOOL
FunctionEntryCache::Initialize(ULONG MaxEntries, ULONG ReplaceAt)
{
// Already initialized.
if (m_Entries != NULL) {
return TRUE;
}
m_Entries = (FeCacheEntry*)MemAlloc(sizeof(FeCacheEntry) * MaxEntries);
if (m_Entries == NULL) {
return FALSE;
}
m_MaxEntries = MaxEntries;
m_ReplaceAt = ReplaceAt;
m_Used = 0;
m_Next = 0;
return TRUE;
}
FeCacheEntry*
FunctionEntryCache::Find(
HANDLE Process,
ULONG64 CodeOffset,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry
)
{
FeCacheEntry* FunctionEntry;
FE_DEBUG(("\nFunctionEntryCache::Find(ControlPc=%.8I64x, Machine=%X)\n",
CodeOffset, m_Machine));
// Look for a static or dynamic function entry.
FunctionEntry = FindDirect( Process, CodeOffset, ReadMemory,
GetModuleBase, GetFunctionEntry );
if (FunctionEntry == NULL) {
return NULL;
}
//
// The capability exists for more than one function entry
// to map to the same function. This permits a function to
// have discontiguous code segments described by separate
// function table entries. If the ending prologue address
// is not within the limits of the begining and ending
// address of the function table entry, then the prologue
// ending address is the address of the primary function
// table entry that accurately describes the ending prologue
// address.
//
FunctionEntry = SearchForPrimaryEntry(FunctionEntry, Process, ReadMemory,
GetModuleBase, GetFunctionEntry);
#if DBG
if (tlsvar(DebugFunctionEntries)) {
if (FunctionEntry == NULL) {
dbPrint("FunctionEntryCache::Find returning NULL\n");
} else {
if (FunctionEntry->Address) {
dbPrint("FunctionEntryCache::Find returning "
"FunctionEntry=%.8I64x %s\n",
FunctionEntry->Address,
FunctionEntry->Description);
} else {
dbPrint("FunctionEntryCache::Find returning "
"FunctionEntry=%.8I64x %s\n",
(ULONG64)(LONG64)(LONG_PTR)FunctionEntry,
FunctionEntry->Description);
}
}
}
#endif
return FunctionEntry;
}
FeCacheEntry*
FunctionEntryCache::FindDirect(
HANDLE Process,
ULONG64 CodeOffset,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry
)
{
FeCacheEntry* FunctionEntry;
ULONG64 ModuleBase;
//
// Look for function entry in static function tables.
//
FunctionEntry = FindStatic( Process, CodeOffset, ReadMemory,
GetModuleBase, GetFunctionEntry,
&ModuleBase );
FE_DEBUG((" FindDirect: ControlPc=0x%I64x functionEntry=0x%p\n"
" FindStatic %s\n", CodeOffset, FunctionEntry,
FunctionEntry != NULL ? "succeeded" : "FAILED"));
if (FunctionEntry != NULL) {
return FunctionEntry;
}
//
// If not in static image range and no static function entry
// found use FunctionEntryCallback routine (if present) for
// dynamic function entry or some other source of pdata (e.g.
// saved pdata information for ROM images).
//
PPROCESS_ENTRY ProcessEntry = FindProcessEntry( Process );
if (ProcessEntry == NULL) {
return NULL;
}
PVOID RawEntry;
if (!ModuleBase) {
if (!IsImageMachineType64(m_Machine) &&
ProcessEntry->pFunctionEntryCallback32) {
RawEntry = ProcessEntry->pFunctionEntryCallback32
(Process, (ULONG)CodeOffset,
(PVOID)ProcessEntry->FunctionEntryUserContext);
if (RawEntry) {
IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY Ent64;
// This currently only happens for Axp32 so
// upconvert.
ConvertAlphaRf32To64
((PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY)RawEntry, &Ent64);
FunctionEntry = FillTemporary(Process, &Ent64);
FE_SET_DESC(FunctionEntry, "from FunctionEntryCallback32");
}
} else if (ProcessEntry->pFunctionEntryCallback64) {
RawEntry = ProcessEntry->pFunctionEntryCallback64
(Process, CodeOffset, ProcessEntry->FunctionEntryUserContext);
if (RawEntry != NULL) {
FunctionEntry = FillTemporary(Process, RawEntry);
FE_SET_DESC(FunctionEntry, "from FunctionEntryCallback64");
}
}
if (FunctionEntry != NULL) {
FE_DEBUG((" FindDirect: got dynamic entry\n"));
} else if (GetFunctionEntry != NULL) {
// VC 6 didn't supply a GetModuleBase callback so this code is
// to make stack walking backward compatible.
//
// If we don't have a function by now, use the old-style function
// entry callback and let VC give it to us. Note that MSDN
// documentation indicates that this callback should return
// a 3-field IMAGE_FUNCTION_ENTRY structure, but VC 6 actually
// returns the 5-field IMAGE_RUNTIME_FUNCTION_ENTRY. Since
// the purpose of this hack is to make VC 6 work just go with the
// way VC 6 does it rather than what MSDN says.
RawEntry = GetFunctionEntry(Process, CodeOffset);
if (RawEntry != NULL) {
FunctionEntry = FillTemporary(Process, RawEntry);
FE_SET_DESC(FunctionEntry, "from GetFunctionEntry");
FE_DEBUG((" FindDirect: got user entry\n"));
}
}
} else {
// Nothing has turned up a function entry but we do have a
// module base address. One possibility is that this is the
// kernel debugger and the pdata section is not paged in.
// The last ditch attempt for a function entry will be an
// internal dbghelp call to get the pdata entry from the
// debug info. This is not great because the data in the debug
// section is incomplete and potentially out of date, but in
// most cases it works and makes it possible to get user-mode
// stack traces in the kernel debugger.
PIMGHLP_RVA_FUNCTION_DATA RvaEntry =
GetFunctionEntryFromDebugInfo( ProcessEntry, CodeOffset );
if (RvaEntry != NULL) {
FeCacheData Data;
TranslateRvaDataToRawData(RvaEntry, ModuleBase, &Data);
FunctionEntry = FillTemporary(Process, &Data);
FE_SET_DESC(FunctionEntry, "from GetFunctionEntryFromDebugInfo");
FE_DEBUG((" FindDirect: got debug info entry\n"));
}
}
return FunctionEntry;
}
FeCacheEntry*
FunctionEntryCache::FindStatic(
HANDLE Process,
ULONG64 CodeOffset,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
PULONG64 ModuleBase
)
{
ULONG RelCodeOffset;
*ModuleBase = GetModuleBase( Process, CodeOffset );
if (CodeOffset - *ModuleBase > 0xffffffff) {
return NULL;
}
RelCodeOffset = (ULONG)(CodeOffset - *ModuleBase);
FE_DEBUG((" FindStatic: ControlPc=0x%I64x ImageBase=0x%I64x\n"
" biasedControlPc=0x%lx\n",
CodeOffset, *ModuleBase, RelCodeOffset));
FeCacheEntry* FunctionEntry;
ULONG Index;
//
// Check the array of recently fetched function entries
//
FunctionEntry = m_Entries;
for (Index = 0; Index < m_Used; Index++) {
if (FunctionEntry->Process == Process &&
FunctionEntry->ModuleBase == *ModuleBase &&
RelCodeOffset >= FunctionEntry->RelBegin &&
RelCodeOffset < FunctionEntry->RelEnd) {
FE_DEBUG((" FindStatic: cache hit - index=%ld\n", Index));
return FunctionEntry;
}
FunctionEntry++;
}
//
// If an image was found that included the specified code, then locate the
// function table for the image.
//
if (*ModuleBase == 0) {
return NULL;
}
ULONG64 FunctionTable;
ULONG SizeOfFunctionTable;
FunctionTable = FunctionTableBase( Process, ReadMemory, *ModuleBase,
&SizeOfFunctionTable );
if (FunctionTable == NULL) {
return NULL;
}
FE_DEBUG((" FindStatic: functionTable=0x%I64x "
"sizeOfFunctionTable=%ld count:%ld\n",
FunctionTable, SizeOfFunctionTable,
SizeOfFunctionTable / m_ImageDataSize));
LONG High;
LONG Low;
LONG Middle;
//
// If a function table is located, then search the function table
// for a function table entry for the specified code offset.
//
Low = 0;
High = (SizeOfFunctionTable / m_ImageDataSize) - 1;
//
// Perform binary search on the function table for a function table
// entry that subsumes the specified code offset.
//
while (High >= Low) {
//
// Compute next probe index and test entry. If the specified PC
// is greater than of equal to the beginning address and less
// than the ending address of the function table entry, then
// return the address of the function table entry. Otherwise,
// continue the search.
//
Middle = (Low + High) >> 1;
ULONG64 NextFunctionTableEntry = FunctionTable +
Middle * m_ImageDataSize;
//
// Fetch the function entry and bail if there is an error reading it
//
FunctionEntry = ReadImage( Process, NextFunctionTableEntry,
ReadMemory, GetModuleBase );
if (FunctionEntry == NULL) {
FE_DEBUG((" FindStatic: ReadImage "
"functionEntryAddress=0x%I64x FAILED\n",
NextFunctionTableEntry));
return NULL;
}
if (RelCodeOffset < FunctionEntry->RelBegin) {
High = Middle - 1;
} else if (RelCodeOffset >= FunctionEntry->RelEnd) {
Low = Middle + 1;
} else {
return Promote( FunctionEntry );
}
}
return NULL;
}
FeCacheEntry*
FunctionEntryCache::ReadImage(
HANDLE Process,
ULONG64 Address,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase
)
{
FeCacheEntry* FunctionEntry;
ULONG Index;
// Check the array of recently fetched function entries.
FunctionEntry = m_Entries;
for (Index = 0; Index < m_Used; Index++) {
if (FunctionEntry->Process == Process &&
FunctionEntry->Address == Address ) {
return FunctionEntry;
}
FunctionEntry++;
}
FeCacheData Data;
DWORD Done;
if (!ReadMemory(Process, Address, &Data, m_ImageDataSize, &Done) ||
Done != m_ImageDataSize) {
return NULL;
}
// If not in the cache, replace the entry that m_Next
// points to. m_Next cycles through the last part of the
// table and function entries we want to keep are promoted to the first
// part of the table so they don't get overwritten by new ones being read
// as part of the binary search through function entry tables.
if (m_Used < m_MaxEntries) {
m_Used++;
m_Next = m_Used;
} else {
m_Next++;
if (m_Next >= m_MaxEntries) {
m_Next = m_ReplaceAt + 1;
}
}
FunctionEntry = m_Entries + (m_Next - 1);
FunctionEntry->Data = Data;
FunctionEntry->Address = Address;
FunctionEntry->Process = Process;
FunctionEntry->ModuleBase = GetModuleBase(Process, Address);
FE_SET_DESC(FunctionEntry, "from target process");
// Translate after all other information is filled in so
// the translation routine can use it.
TranslateRawData(FunctionEntry);
return FunctionEntry;
}
void
FunctionEntryCache::InvalidateProcessOrModule(HANDLE Process, ULONG64 Base)
{
FeCacheEntry* FunctionEntry;
ULONG Index;
FunctionEntry = m_Entries;
Index = 0;
while (Index < m_Used) {
if (FunctionEntry->Process == Process &&
(Base == 0 || FunctionEntry->ModuleBase == Base)) {
// Pull the last entry down into this slot
// to keep things packed. There's no need
// to update m_Next as this will open a
// new slot for use and m_Next will be reset
// when it is used.
*FunctionEntry = m_Entries[--m_Used];
} else {
Index++;
FunctionEntry++;
}
}
}
FeCacheEntry*
FunctionEntryCache::Promote(FeCacheEntry* Entry)
{
ULONG Index;
ULONG Move;
Index = (ULONG)(Entry - m_Entries);
// Make sure it's promoted out of the temporary area.
if (Index >= m_ReplaceAt) {
Move = Index - (m_ReplaceAt - 3);
} else {
Move = ( Index >= 3 ) ? 3 : 1;
}
if (Index > Move) {
FeCacheEntry Temp = *Entry;
*Entry = m_Entries[Index - Move];
m_Entries[Index - Move] = Temp;
Index -= Move;
}
return m_Entries + Index;
}
ULONG64
FunctionEntryCache::FunctionTableBase(
HANDLE Process,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
ULONG64 Base,
PULONG Size
)
{
ULONG64 NtHeaders;
ULONG64 ExceptionDirectoryEntryAddress;
IMAGE_DATA_DIRECTORY ExceptionData;
IMAGE_DOS_HEADER DosHeaderData;
DWORD Done;
// Read DOS header to calculate the address of the NT header.
if (!ReadMemory( Process, Base, &DosHeaderData, sizeof(DosHeaderData),
&Done ) ||
Done != sizeof(DosHeaderData)) {
return 0;
}
if (DosHeaderData.e_magic != IMAGE_DOS_SIGNATURE) {
return 0;
}
NtHeaders = Base + DosHeaderData.e_lfanew;
if (IsImageMachineType64(m_Machine)) {
ExceptionDirectoryEntryAddress = NtHeaders +
FIELD_OFFSET(IMAGE_NT_HEADERS64,OptionalHeader) +
FIELD_OFFSET(IMAGE_OPTIONAL_HEADER64,DataDirectory) +
IMAGE_DIRECTORY_ENTRY_EXCEPTION * sizeof(IMAGE_DATA_DIRECTORY);
} else {
ExceptionDirectoryEntryAddress = NtHeaders +
FIELD_OFFSET(IMAGE_NT_HEADERS32,OptionalHeader) +
FIELD_OFFSET(IMAGE_OPTIONAL_HEADER32,DataDirectory) +
IMAGE_DIRECTORY_ENTRY_EXCEPTION * sizeof(IMAGE_DATA_DIRECTORY);
}
// Read NT header to get the image data directory.
if (!ReadMemory( Process, ExceptionDirectoryEntryAddress, &ExceptionData,
sizeof(IMAGE_DATA_DIRECTORY), &Done ) ||
Done != sizeof(IMAGE_DATA_DIRECTORY)) {
return 0;
}
*Size = ExceptionData.Size;
return Base + ExceptionData.VirtualAddress;
}
FeCacheEntry*
FunctionEntryCache::SearchForPrimaryEntry(
FeCacheEntry* CacheEntry,
HANDLE Process,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry
)
{
// Assume all entries are primary.
return CacheEntry;
}
//----------------------------------------------------------------------------
//
// Ia64FunctionEntryCache.
//
//----------------------------------------------------------------------------
void
Ia64FunctionEntryCache::TranslateRawData(FeCacheEntry* Entry)
{
Entry->RelBegin = Entry->Data.Ia64.BeginAddress & ~15;
Entry->RelEnd = (Entry->Data.Ia64.EndAddress + 15) & ~15;
}
void
Ia64FunctionEntryCache::TranslateRvaDataToRawData
(PIMGHLP_RVA_FUNCTION_DATA RvaData, ULONG64 ModuleBase,
FeCacheData* Data)
{
Data->Ia64.BeginAddress = RvaData->rvaBeginAddress;
Data->Ia64.EndAddress = RvaData->rvaEndAddress;
Data->Ia64.UnwindInfoAddress = RvaData->rvaPrologEndAddress;
}
#if DBG
void
ShowRuntimeFunctionIa64(
FeCacheEntry* FunctionEntry,
PSTR Label
)
{
if (!tlsvar(DebugFunctionEntries)) {
return;
}
if ( FunctionEntry ) {
if (FunctionEntry->Address) {
dbPrint(" 0x%I64x: %s\n", FunctionEntry->Address,
Label ? Label : "" );
}
else {
dbPrint(" %s\n", Label ? Label : "" );
}
dbPrint(" BeginAddress = 0x%x\n"
" EndAddress = 0x%x\n"
" UnwindInfoAddress = 0x%x\n",
FunctionEntry->Data.Ia64.BeginAddress,
FunctionEntry->Data.Ia64.EndAddress,
FunctionEntry->Data.Ia64.UnwindInfoAddress );
}
else {
dbPrint(" FunctionEntry NULL: %s\n", Label ? Label : "" );
}
}
#endif // #if DBG
//----------------------------------------------------------------------------
//
// Amd64FunctionEntryCache.
//
//----------------------------------------------------------------------------
void
Amd64FunctionEntryCache::TranslateRawData(FeCacheEntry* Entry)
{
Entry->RelBegin = Entry->Data.Amd64.BeginAddress;
Entry->RelEnd = Entry->Data.Amd64.EndAddress;
}
void
Amd64FunctionEntryCache::TranslateRvaDataToRawData
(PIMGHLP_RVA_FUNCTION_DATA RvaData, ULONG64 ModuleBase,
FeCacheData* Data)
{
Data->Amd64.BeginAddress = RvaData->rvaBeginAddress;
Data->Amd64.EndAddress = RvaData->rvaEndAddress;
Data->Amd64.UnwindInfoAddress = RvaData->rvaPrologEndAddress;
}
//----------------------------------------------------------------------------
//
// AlphaFunctionEntryCache.
//
//----------------------------------------------------------------------------
void
AlphaFunctionEntryCache::TranslateRvaDataToRawData
(PIMGHLP_RVA_FUNCTION_DATA RvaData, ULONG64 ModuleBase,
FeCacheData* Data)
{
Data->Axp64.BeginAddress = ModuleBase + RvaData->rvaBeginAddress;
Data->Axp64.EndAddress = ModuleBase + RvaData->rvaEndAddress;
Data->Axp64.ExceptionHandler = 0;
Data->Axp64.HandlerData = 0;
Data->Axp64.PrologEndAddress = ModuleBase + RvaData->rvaPrologEndAddress;
}
FeCacheEntry*
AlphaFunctionEntryCache::SearchForPrimaryEntry(
FeCacheEntry* CacheEntry,
HANDLE Process,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry
)
{
PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY FunctionEntry =
&CacheEntry->Data.Axp64;
if ((ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry) <
ALPHA_RF_BEGIN_ADDRESS(FunctionEntry)) ||
(ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry) >=
ALPHA_RF_END_ADDRESS(FunctionEntry))) {
FE_ShowRuntimeFunctionAxp64
((CacheEntry, "SearchForPrimaryEntry: secondary entry"));
// Officially the PrologEndAddress field in secondary function entries
// doesn't have the exception mode bits there have been some versions
// of alpha tools that put them there. Strip them off to be safe.
CacheEntry = ReadImage( Process,
ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry),
ReadMemory, GetModuleBase );
if (!CacheEntry) {
return NULL;
}
CacheEntry = Promote( CacheEntry );
} else if (ALPHA_RF_IS_FIXED_RETURN(FunctionEntry)) {
ULONG64 FixedReturn = ALPHA_RF_FIXED_RETURN64(FunctionEntry);
FE_ShowRuntimeFunctionAxp64
((CacheEntry, "SearchForPrimaryEntry: fixed return entry"));
// Recursively call Find to ensure we get a
// primary function entry here.
// Check for incorrectly formed function entry where the fixed
// return points to itself.
if ((FixedReturn < ALPHA_RF_BEGIN_ADDRESS(FunctionEntry)) ||
(FixedReturn >= ALPHA_RF_END_ADDRESS(FunctionEntry))) {
CacheEntry = Find( Process, ALPHA_RF_FIXED_RETURN64(FunctionEntry),
ReadMemory, GetModuleBase, GetFunctionEntry );
}
}
FE_ShowRuntimeFunctionAxp64
((CacheEntry, "SearchForPrimaryEntry: primary entry"));
return CacheEntry;
}
void
ConvertAlphaRf32To64(
PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY rf32,
PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY rf64
)
{
rf64->BeginAddress = (ULONG64)(LONG64)(LONG)rf32->BeginAddress;
rf64->EndAddress = (ULONG64)(LONG64)(LONG)rf32->EndAddress;
rf64->ExceptionHandler = (ULONG64)(LONG64)(LONG)rf32->ExceptionHandler;
rf64->HandlerData = (ULONG64)(LONG64)(LONG)rf32->HandlerData;
rf64->PrologEndAddress = (ULONG64)(LONG64)(LONG)rf32->PrologEndAddress;
}
#if DBG
#define MAXENTRYTYPE 2
const char *EntryTypeName[] = {
"ALPHA_RF_NOT_CONTIGUOUS", // 0
"ALPHA_RF_ALT_ENT_PROLOG", // 1
"ALPHA_RF_NULL_CONTEXT", // 2
"***INVALID***"
};
void
ShowRuntimeFunctionAxp64(
FeCacheEntry* FunctionEntry,
PSTR Label
)
{
BOOL Secondary = FALSE;
BOOL FixedReturn = FALSE;
ULONG EntryType = 0;
ULONG NullCount = 0;
if (tlsvar(DebugFunctionEntries)) {
if (FunctionEntry != NULL && FunctionEntry->Address) {
dbPrint(" %.8I64x: ", FunctionEntry->Address );
} else {
dbPrint(" ");
}
if (Label) {
dbPrint(Label);
}
dbPrint("\n");
if (FunctionEntry) {
PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY Axp64 =
&FunctionEntry->Data.Axp64;
if ((ALPHA_RF_PROLOG_END_ADDRESS(Axp64) <
ALPHA_RF_BEGIN_ADDRESS(Axp64)) ||
(ALPHA_RF_PROLOG_END_ADDRESS(Axp64) >
ALPHA_RF_END_ADDRESS(Axp64))) {
Secondary = TRUE;
EntryType = ALPHA_RF_ENTRY_TYPE(Axp64);
if (EntryType > MAXENTRYTYPE) {
EntryType = MAXENTRYTYPE;
}
} else if (ALPHA_RF_IS_FIXED_RETURN(Axp64)) {
FixedReturn = TRUE;
}
NullCount = ALPHA_RF_NULL_CONTEXT_COUNT(Axp64);
dbPrint(" BeginAddress = %16.8I64x\n", Axp64->BeginAddress);
dbPrint(" EndAddress = %16.8I64x", Axp64->EndAddress);
if (NullCount) {
dbPrint(" %d null-context instructions", NullCount);
}
dbPrint("\n");
dbPrint(" ExceptionHandler = %16.8I64x",
Axp64->ExceptionHandler);
if (Axp64->ExceptionHandler != 0) {
if (Secondary) {
ULONG64 AlternateProlog = ALPHA_RF_ALT_PROLOG64(Axp64);
switch( EntryType ) {
case ALPHA_RF_NOT_CONTIGUOUS:
case ALPHA_RF_ALT_ENT_PROLOG:
if ((AlternateProlog >=
ALPHA_RF_BEGIN_ADDRESS(Axp64)) &&
(AlternateProlog <= Axp64->EndAddress)) {
dbPrint(" alternate PrologEndAddress");
}
break;
case ALPHA_RF_NULL_CONTEXT:
dbPrint(" stack adjustment");
}
} else if (FixedReturn) {
dbPrint(" fixed return address");
}
}
dbPrint("\n");
dbPrint(" HandlerData = %16.8I64x", Axp64->HandlerData);
if (Secondary) {
dbPrint(" type %d: %s", EntryType, EntryTypeName[EntryType] );
}
dbPrint("\n");
dbPrint(" PrologEndAddress = %16.8I64x\n",
Axp64->PrologEndAddress );
}
}
}
#endif // #if DBG
//----------------------------------------------------------------------------
//
// Axp32FunctionEntryCache.
//
//----------------------------------------------------------------------------
void
Axp32FunctionEntryCache::TranslateRawData(FeCacheEntry* Entry)
{
IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY Ent64;
// Convert to 64-bit so that Alpha function entries are
// always stored as 64-bit for code commonality.
ConvertAlphaRf32To64(&Entry->Data.Axp32, &Ent64);
Entry->Data.Axp64 = Ent64;
Entry->RelBegin = (ULONG)
(Entry->Data.Axp64.BeginAddress - Entry->ModuleBase);
Entry->RelEnd = (ULONG)
(Entry->Data.Axp64.EndAddress - Entry->ModuleBase);
}
//----------------------------------------------------------------------------
//
// Axp64FunctionEntryCache.
//
//----------------------------------------------------------------------------
void
Axp64FunctionEntryCache::TranslateRawData(FeCacheEntry* Entry)
{
Entry->RelBegin = (ULONG)
(Entry->Data.Axp64.BeginAddress - Entry->ModuleBase);
Entry->RelEnd = (ULONG)
(Entry->Data.Axp64.EndAddress - Entry->ModuleBase);
}
//----------------------------------------------------------------------------
//
// Functions.
//
//----------------------------------------------------------------------------
FunctionEntryCache*
GetFeCache(ULONG Machine, BOOL Create)
{
FunctionEntryCache* Cache;
switch(Machine) {
case IMAGE_FILE_MACHINE_ALPHA:
if (tlsvar(Axp32FunctionEntries) == NULL && Create) {
tlsvar(Axp32FunctionEntries) = new Axp32FunctionEntryCache;
if (tlsvar(Axp32FunctionEntries) == NULL) {
return NULL;
}
}
Cache = tlsvar(Axp32FunctionEntries);
break;
case IMAGE_FILE_MACHINE_ALPHA64:
if (tlsvar(Axp64FunctionEntries) == NULL && Create) {
tlsvar(Axp64FunctionEntries) = new Axp64FunctionEntryCache;
if (tlsvar(Axp64FunctionEntries) == NULL) {
return NULL;
}
}
Cache = tlsvar(Axp64FunctionEntries);
break;
case IMAGE_FILE_MACHINE_AMD64:
if (tlsvar(Amd64FunctionEntries) == NULL && Create) {
tlsvar(Amd64FunctionEntries) = new Amd64FunctionEntryCache;
if (tlsvar(Amd64FunctionEntries) == NULL) {
return NULL;
}
}
Cache = tlsvar(Amd64FunctionEntries);
break;
case IMAGE_FILE_MACHINE_IA64:
if (tlsvar(Ia64FunctionEntries) == NULL && Create) {
tlsvar(Ia64FunctionEntries) = new Ia64FunctionEntryCache;
if (tlsvar(Ia64FunctionEntries) == NULL) {
return NULL;
}
}
Cache = tlsvar(Ia64FunctionEntries);
break;
default:
return NULL;
}
if (Cache && !Cache->Initialize(60, 40)) {
return NULL;
}
return Cache;
}
void
ClearFeCaches(void)
{
if (tlsvar(Axp32FunctionEntries)) {
delete (Axp32FunctionEntryCache*)tlsvar(Axp32FunctionEntries);
tlsvar(Axp32FunctionEntries) = NULL;
}
if (tlsvar(Axp64FunctionEntries)) {
delete (Axp64FunctionEntryCache*)tlsvar(Axp64FunctionEntries);
tlsvar(Axp64FunctionEntries) = NULL;
}
if (tlsvar(Ia64FunctionEntries)) {
delete (Ia64FunctionEntryCache*)tlsvar(Ia64FunctionEntries);
tlsvar(Ia64FunctionEntries) = NULL;
}
if (tlsvar(Amd64FunctionEntries)) {
delete (Amd64FunctionEntryCache*)tlsvar(Amd64FunctionEntries);
tlsvar(Amd64FunctionEntries) = NULL;
}
}