singrdk/base/Kernel/Native/ix64/halexn.cpp

335 lines
11 KiB
C++

//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// * searching exception table
// * make machine faults raise CIL exceptions
//
// C code should always invoke the filter BartokMachineFaultFilter
// before it attempts to handle any of the machine faults handled
// below. BartokMachineFaultFilter causes an appropriate exception
// to be thrown if a machine fault occurred in CIL code.
# include "hal.h"
extern BOOL KdDebuggerNotPresent;
#ifndef NOEVENTING
#include "eventing.h"
#endif
// See bartok\tables\ExceptionTable.cs for a description of ExceptionTableEntry
//////////////////////////////////////////////////////////////////////////////
//
struct ExceptionTableEntry {
uintptr scopeBaseAddr;
union {
struct {
Class_System_Type *exceptionClass; // low bit is zero
uintptr handlerAddr;
};
struct {
uintptr frameSetupInfo; // low bit is one
uintptr spillSize;
};
};
};
struct TableEntry {
ExceptionTableEntry * tableBaseAddr;
ExceptionTableEntry * tableEndAddr;
};
extern TableEntry TableBase[1];
extern TableEntry TableBound[1];
// TODO: BUGBUG_X64:
// ExceptionTableLookupReturn breaks down with 64-bit pointers.
// We will need to revisit the code
// that uses the ExceptionTableLookupReturn result (__throwDispatcher*).
#ifdef ISA_IX64
struct PtrPair {
uintptr a;
uintptr b;
};
typedef PtrPair lookupReturnType;
#else
typedef uint64 lookupReturnType;
#endif
union ExceptionTableLookupReturn {
lookupReturnType etlReturn;
struct {
Class_System_Type *exceptionClass;
uintptr handlerAddr;
};
struct {
uintptr frameSetupInfo;
uintptr spillSize;
};
};
static uintptr LookupTable(uintptr throwAddr,
ExceptionTableEntry **tableBaseEntry,
ExceptionTableEntry **tableEndEntry) {
#if 0
printf("LookupTable(throwAddr=%p, tableBase=%p, tableEnd=%p)\n",
throwAddr, tableBaseEntry, tableEndEntry);
printf(" TableBase=%p, TableBound=%p, maxIndex = %d\n",
TableBase, TableBound, TableBound - TableBase);
printf(" callSiteTableCount=%d\n",
Class_System_GCs_CallStack::c_callSiteTableCount);
printf(" codeBaseStartTable=%p\n",
Class_System_GCs_CallStack::c_codeBaseStartTable);
printf(" returnAddressToCallSiteSetNumbers=%p\n",
Class_System_GCs_CallStack::c_returnAddressToCallSiteSetNumbers);
printf(" callSiteSetCount=%p\n",
Class_System_GCs_CallStack::c_callSiteSetCount);
#endif
// search to find which table to use
int maxIndex = (int) (TableBound - TableBase);
uintptr codeBase = (uintptr) -1;
uintptr relCodeAddr = 0;
for (int i = 0; i < maxIndex; i++) {
TableEntry *entry = &TableBase[i];
#if 0
printf(" TableBase[%d] base=%p end=%p codeBaseStartTable[]=%p\n",
i, entry->tableBaseAddr, entry->tableEndAddr,
Class_System_GCs_CallStack::c_codeBaseStartTable[i]);
#endif
codeBase =
((uintptr*)Class_System_GCs_CallStack::c_codeBaseStartTable)[i];
if (throwAddr < codeBase) {
continue;
}
relCodeAddr = throwAddr - codeBase;
*tableBaseEntry = entry->tableBaseAddr;
*tableEndEntry = entry->tableEndAddr;
#if 0
printf(" relCodeAddr = %p\n", relCodeAddr);
printf(" tableBase scopeBaseAddr=%p class=%p handler=%p\n",
(*tableBaseEntry)->scopeBaseAddr,
(*tableBaseEntry)->exceptionClass,
(*tableBaseEntry)->handlerAddr);
printf(" tableEnd scopeBaseAddr=%p class=%p handler=%p\n",
(*tableEndEntry)->scopeBaseAddr,
(*tableEndEntry)->exceptionClass,
(*tableEndEntry)->handlerAddr);
#endif
if ((relCodeAddr >= (*tableBaseEntry)->scopeBaseAddr)
&& (relCodeAddr <= (*tableEndEntry)->scopeBaseAddr)) {
return codeBase;
}
}
return (uintptr) -1;
//exit(-2);
//__asm int 3;
}
Class_System_VTable * getRealVTable(Class_System_VTable * vt)
{
return (Class_System_VTable *)((uintptr)vt & (~((uintptr)3)));
}
//////////////////////////////////////////////////////////////////////////////
// ExceptionAssert is called when an unexpected condition happens during
// exception processing
void ExceptionAssert()
{
#if SPIN
// Useful for native cases when no debugger is avaiable
while (1)
;
#endif
__debugbreak();
}
// search an exception table
//////////////////////////////////////////////////////////////////////////////
// search an exception table
// - Returns the exception in eax.
// - Returns the handler address in edx.
// OR if the shared unwind handler should be used
// - Returns the frameSetupInfo in eax.
// - Returns the spill area size in edx.
lookupReturnType __fastcall ExceptionTableLookup(Class_System_Exception *exception,
uintptr throwAddr) {
#if 0
printf("\n");
printf("ExceptionTableLookup(exception=%p, vtable=%p, throwAddr=%p)\n",
exception, ((uintptr *)exception)[0], throwAddr);
#endif
if (exception->_throwAddress == NULL) {
exception->_throwAddress = throwAddr;
}
// search for table using throwAddr
ExceptionTableEntry *baseEntry = NULL;
ExceptionTableEntry *endEntry = NULL;
uintptr codeBase = LookupTable(throwAddr, &baseEntry, &endEntry);
#if SINGULARITY_KERNEL
#if 0
printf(" codeBase=%p baseEntry=%p endEntry=%p\n",
codeBase, baseEntry, endEntry);
#endif
#endif
if (codeBase == (uintptr) -1) {
#if SINGULARITY_KERNEL
#if 0
printf("Exception outside of any known code regions!\n");
#endif
if (!KdDebuggerNotPresent) {
ExceptionAssert();
}
#if 0
printf("Terminating by exception!\n");
#endif
Class_System_VTable::g_TerminateByException(exception);
ExceptionAssert();
#elif SINGULARITY_PROCESS
Assert("Exception outside of any known code regions!\n");
Class_System_VTable::g_TerminateByException(exception);
#endif
}
// bsearch for throwAddr
int minIndex = 0;
int maxIndex = (int) (endEntry-baseEntry);
throwAddr -= codeBase;
if (throwAddr < baseEntry[minIndex].scopeBaseAddr ||
throwAddr > baseEntry[maxIndex].scopeBaseAddr) {
// BUGBUG: callback to C# code that may trigger GC
#if SINGULARITY_KERNEL
#if 0
printf("Exception outside of known code region for %p\n", codeBase);
#endif
if (!KdDebuggerNotPresent) {
__debugbreak();
}
Class_System_VTable::g_TerminateByException(exception);
#if 0
printf("top-level exception handling code failed\n");
#endif
__debugbreak();
#elif SINGULARITY_PROCESS
Assert("Exception outside of known code region for.\n");
Class_System_VTable::g_TerminateByException(exception);
Assert("top-level exception handling code failed\n");
#endif
}
while (minIndex+1 < maxIndex) {
int midIndex = (minIndex+maxIndex)/2;
uintptr midAddr = baseEntry[midIndex].scopeBaseAddr;
if (throwAddr < midAddr) {
maxIndex = midIndex;
} else {
minIndex = midIndex;
}
}
ExceptionTableEntry *entry = &baseEntry[minIndex];
// back up to first entry containing throwAddr (there may be several)
uintptr baseAddr;
for (baseAddr = entry->scopeBaseAddr;
entry->scopeBaseAddr == baseAddr && entry >= baseEntry;
entry--) {
continue;
}
// check each of the handlers in turn
for (entry++; entry->scopeBaseAddr <= throwAddr; entry++) {
#if 0
printf(" entry=%p[%d] "
"scopeBaseAddr=%p exceptionClass=%p handler=%p\n",
entry, entry - baseEntry,
entry->scopeBaseAddr, entry->exceptionClass, entry->handlerAddr);
#endif
// 0 now means "no frame pointer omission and no callee save registers
// have been saved to the stack":
// Assert(entry->exceptionClass);
Assert(((entry->frameSetupInfo & 0x1) != 0)
|| (entry->handlerAddr != NULL));
if (((entry->frameSetupInfo & 0x1) != 0)
|| Class_System_VTable::g_IsExceptionHandler(entry->exceptionClass,
exception)) {
#if 0
printf("Found matching exception entry: %p\n", entry);
#endif
break;
}
}
Assert(entry->scopeBaseAddr == baseAddr);
ExceptionTableLookupReturn retval;
if((entry->frameSetupInfo & 0x1) != 0) {
retval.frameSetupInfo = entry->frameSetupInfo;
retval.spillSize = entry->spillSize;
#ifndef NOEVENTING
LogExceptionInfo((UIntPtr)(codeBase + throwAddr),
0,
getRealVTable(exception->postHeader.vtableObject)->vtableType->name);
#endif
} else {
retval.exceptionClass = entry->exceptionClass;
retval.handlerAddr = entry->handlerAddr + codeBase;
#ifndef NOEVENTING
LogExceptionInfo((UIntPtr)(codeBase + throwAddr),
(UIntPtr)(retval.handlerAddr),
getRealVTable(exception->postHeader.vtableObject)->vtableType->name);
#endif
}
#if SINGULARITY_KERNEL
if (!exception->_notifiedDebugger && !KdDebuggerNotPresent) {
exception->_notifiedDebugger = true;
bool iflag =
Class_Microsoft_Singularity_Processor::g_DisableInterrupts();
Class_System_VTable * vtable = getRealVTable(exception->postHeader.vtableObject);
#if 0
if ((entry->frameSetupInfo & 0x1) != 0) {
printf("\n---- First chance %ls at %p. Handler is shared ----\n",
&(vtable->vtableType->name->m_firstChar),
codeBase + throwAddr);
}
else {
printf("\n---- First chance %ls at %p. Handler is %p ----\n",
&(vtable->vtableType->name->m_firstChar),
codeBase + throwAddr,
retval.handlerAddr);
}
if (exception->_message != NULL) {
printf("------ Message: %ls\n",
&(exception->_message->m_firstChar));
}
#endif
KdNotifyException(exception, (uint32) throwAddr);
Class_Microsoft_Singularity_Processor::g_RestoreInterrupts(iflag);
}
#endif
return(retval.etlReturn);
}