update Windows' SEH, fix overflow exception, and non-Windows platform support

This commit is contained in:
RadWolfie 2020-05-29 20:56:38 -05:00
parent 64f69f78ae
commit b5358508d6
9 changed files with 147 additions and 184 deletions

View File

@ -986,15 +986,8 @@ typedef struct {
void WINAPI EmuFiberStartup(fiber_context_t* context)
{
__try
{
LPFIBER_START_ROUTINE pfStartRoutine = (LPFIBER_START_ROUTINE)context->lpStartRoutine;
pfStartRoutine(context->lpParameter);
}
__except (EmuException(GetExceptionInformation()))
{
EmuLog(LOG_LEVEL::WARNING, "Problem with ExceptionFilter");
}
LPFIBER_START_ROUTINE pfStartRoutine = (LPFIBER_START_ROUTINE)context->lpStartRoutine;
pfStartRoutine(context->lpParameter);
}
// ******************************************************************

View File

@ -88,14 +88,8 @@ public:
m_Pending = false;
}
__try {
BOOLEAN(__stdcall *ServiceRoutine)(xboxkrnl::PKINTERRUPT, void*) = (BOOLEAN(__stdcall *)(xboxkrnl::PKINTERRUPT, void*))Interrupt->ServiceRoutine;
BOOLEAN result = ServiceRoutine(Interrupt, Interrupt->ServiceContext);
}
__except (EmuException(GetExceptionInformation()))
{
EmuLogEx(CXBXR_MODULE::KRNL, LOG_LEVEL::WARNING, "Problem with ExceptionFilter!");
}
BOOLEAN(__stdcall *ServiceRoutine)(xboxkrnl::PKINTERRUPT, void*) = (BOOLEAN(__stdcall *)(xboxkrnl::PKINTERRUPT, void*))Interrupt->ServiceRoutine;
BOOLEAN result = ServiceRoutine(Interrupt, Interrupt->ServiceContext);
}
private:
bool m_Asserted = false;

View File

@ -301,17 +301,13 @@ void ExecuteDpcQueue()
// Set DpcRoutineActive to support KeIsExecutingDpc:
KeGetCurrentPrcb()->DpcRoutineActive = TRUE; // Experimental
EmuLog(LOG_LEVEL::DEBUG, "Global DpcQueue, calling DPC at 0x%.8X", pkdpc->DeferredRoutine);
__try {
// Call the Deferred Procedure :
pkdpc->DeferredRoutine(
pkdpc,
pkdpc->DeferredContext,
pkdpc->SystemArgument1,
pkdpc->SystemArgument2);
} __except (EmuException(GetExceptionInformation()))
{
EmuLog(LOG_LEVEL::WARNING, "Problem with ExceptionFilter!");
}
// Call the Deferred Procedure :
pkdpc->DeferredRoutine(
pkdpc,
pkdpc->DeferredContext,
pkdpc->SystemArgument1,
pkdpc->SystemArgument2);
KeGetCurrentPrcb()->DpcRoutineActive = FALSE; // Experimental
}

View File

@ -643,19 +643,14 @@ xboxkrnl::VOID NTAPI xboxkrnl::KiTimerExpiration
{
/* Call the DPC */
EmuLog(LOG_LEVEL::DEBUG, "%s, calling DPC at 0x%.8X", __func__, DpcEntry[i].Routine);
__try {
// Call the Deferred Procedure :
DpcEntry[i].Routine(
DpcEntry[i].Dpc,
DpcEntry[i].Context,
UlongToPtr(SystemTime.u.LowPart),
UlongToPtr(SystemTime.u.HighPart)
);
}
__except (EmuException(GetExceptionInformation()))
{
EmuLog(LOG_LEVEL::WARNING, "Problem with ExceptionFilter!");
}
// Call the Deferred Procedure :
DpcEntry[i].Routine(
DpcEntry[i].Dpc,
DpcEntry[i].Context,
UlongToPtr(SystemTime.u.LowPart),
UlongToPtr(SystemTime.u.HighPart)
);
}
/* Reset accounting */
@ -691,19 +686,14 @@ xboxkrnl::VOID NTAPI xboxkrnl::KiTimerExpiration
{
/* Call the DPC */
EmuLog(LOG_LEVEL::DEBUG, "%s, calling DPC at 0x%.8X", __func__, DpcEntry[i].Routine);
__try {
// Call the Deferred Procedure :
DpcEntry[i].Routine(
DpcEntry[i].Dpc,
DpcEntry[i].Context,
UlongToPtr(SystemTime.u.LowPart),
UlongToPtr(SystemTime.u.HighPart)
);
}
__except (EmuException(GetExceptionInformation()))
{
EmuLog(LOG_LEVEL::WARNING, "Problem with ExceptionFilter!");
}
// Call the Deferred Procedure :
DpcEntry[i].Routine(
DpcEntry[i].Dpc,
DpcEntry[i].Context,
UlongToPtr(SystemTime.u.LowPart),
UlongToPtr(SystemTime.u.HighPart)
);
}
/* Reset accounting */
@ -736,19 +726,14 @@ xboxkrnl::VOID NTAPI xboxkrnl::KiTimerExpiration
{
/* Call the DPC */
EmuLog(LOG_LEVEL::DEBUG, "%s, calling DPC at 0x%.8X", __func__, DpcEntry[i].Routine);
__try {
// Call the Deferred Procedure :
DpcEntry[i].Routine(
DpcEntry[i].Dpc,
DpcEntry[i].Context,
UlongToPtr(SystemTime.u.LowPart),
UlongToPtr(SystemTime.u.HighPart)
);
}
__except (EmuException(GetExceptionInformation()))
{
EmuLog(LOG_LEVEL::WARNING, "Problem with ExceptionFilter!");
}
// Call the Deferred Procedure :
DpcEntry[i].Routine(
DpcEntry[i].Dpc,
DpcEntry[i].Context,
UlongToPtr(SystemTime.u.LowPart),
UlongToPtr(SystemTime.u.HighPart)
);
}
/* Lower IRQL if we need to */
@ -851,19 +836,14 @@ xboxkrnl::VOID FASTCALL xboxkrnl::KiTimerListExpire
{
/* Call the DPC */
EmuLog(LOG_LEVEL::DEBUG, "%s, calling DPC at 0x%.8X", __func__, DpcEntry[i].Routine);
__try {
// Call the Deferred Procedure :
DpcEntry[i].Routine(
DpcEntry[i].Dpc,
DpcEntry[i].Context,
UlongToPtr(SystemTime.u.LowPart),
UlongToPtr(SystemTime.u.HighPart)
);
}
__except (EmuException(GetExceptionInformation()))
{
EmuLog(LOG_LEVEL::WARNING, "Problem with ExceptionFilter!");
}
// Call the Deferred Procedure :
DpcEntry[i].Routine(
DpcEntry[i].Dpc,
DpcEntry[i].Context,
UlongToPtr(SystemTime.u.LowPart),
UlongToPtr(SystemTime.u.HighPart)
);
}
/* Lower IRQL */

View File

@ -137,19 +137,12 @@ static unsigned int WINAPI PCSTProxy
SuspendThread(GetCurrentThread());
}
__try
{
auto routine = (xboxkrnl::PKSYSTEM_ROUTINE)SystemRoutine;
// Debugging notice : When the below line shows up with an Exception dialog and a
// message like: "Exception thrown at 0x00026190 in cxbx.exe: 0xC0000005: Access
// violation reading location 0xFD001804.", then this is AS-DESIGNED behaviour!
// (To avoid repetitions, uncheck "Break when this exception type is thrown").
routine(xboxkrnl::PKSTART_ROUTINE(StartRoutine), StartContext);
}
__except (EmuException(GetExceptionInformation()))
{
EmuLog(LOG_LEVEL::WARNING, "Problem with ExceptionFilter!");
}
auto routine = (xboxkrnl::PKSYSTEM_ROUTINE)SystemRoutine;
// Debugging notice : When the below line shows up with an Exception dialog and a
// message like: "Exception thrown at 0x00026190 in cxbx.exe: 0xC0000005: Access
// violation reading location 0xFD001804.", then this is AS-DESIGNED behaviour!
// (To avoid repetitions, uncheck "Break when this exception type is thrown").
routine(xboxkrnl::PKSTART_ROUTINE(StartRoutine), StartContext);
// This will also handle thread notification :
LOG_TEST_CASE("Thread returned from SystemRoutine");
@ -165,15 +158,8 @@ void PspSystemThreadStartup
IN PVOID StartContext
)
{
__try
{
(StartRoutine)(StartContext);
}
__except (EmuException(GetExceptionInformation()))
// TODO : Call PspUnhandledExceptionInSystemThread(GetExceptionInformation())
{
EmuLog(LOG_LEVEL::WARNING, "Problem with ExceptionFilter!"); // TODO : Disable?
}
(StartRoutine)(StartContext);
xboxkrnl::PsTerminateSystemThread(STATUS_SUCCESS);
}

View File

@ -171,14 +171,7 @@ void SetupPerTitleKeys()
void CxbxLaunchXbe(void(*Entry)())
{
__try
{
Entry();
}
__except (EmuException(GetExceptionInformation()))
{
EmuLog(LOG_LEVEL::WARNING, "Problem with ExceptionFilter");
}
Entry();
}
// Entry point address XOR keys per Xbe type (Retail, Debug or Chihiro) :
@ -1205,6 +1198,8 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res
ImportLibraries((XbeImportEntry*)CxbxKrnl_Xbe->m_Header.dwNonKernelImportDirAddr);
}
g_ExceptionManager = new ExceptionManager(); // If in need to add VEHs, move this line earlier. (just in case)
// Launch the XBE :
{
// Load TLS
@ -1822,6 +1817,12 @@ void CxbxKrnlShutDown()
}
EmuShared::Cleanup();
if (g_ExceptionManager) {
delete g_ExceptionManager;
g_ExceptionManager = nullptr;
}
TerminateProcess(g_CurrentProcessHandle, 0);
}

View File

@ -217,7 +217,14 @@ bool IsXboxCodeAddress(xbaddr addr)
// Note : Not IS_USER_ADDRESS(), that would include host DLL code
}
#include "distorm.h"
bool EmuX86_DecodeOpcode(const uint8_t* Eip, _DInst& info);
void EmuX86_DistormLogInstruction(const uint8_t* Eip, _DInst& info, LOG_LEVEL log_level);
void genericException(EXCEPTION_POINTERS *e) {
_DInst info;
if (EmuX86_DecodeOpcode((uint8_t*)e->ContextRecord->Eip, info)) {
EmuX86_DistormLogInstruction((uint8_t*)e->ContextRecord->Eip, info, LOG_LEVEL::FATAL);
}
// Try to report this exception to the debugger, which may allow handling of this exception
if (CxbxDebugger::CanReport()) {
bool DebuggerHandled = false;
@ -278,8 +285,6 @@ bool lleTryHandleException(EXCEPTION_POINTERS *e)
return true;
}
genericException(e);
// We do not need EmuException to handle it again.
bOverrideException = true;
@ -288,7 +293,7 @@ bool lleTryHandleException(EXCEPTION_POINTERS *e)
}
// Only for LLE emulation coding (to help performance a little bit better)
LONG NTAPI lleException(EXCEPTION_POINTERS *e)
LONG WINAPI lleException(EXCEPTION_POINTERS *e)
{
g_bEmuException = true;
LONG result = lleTryHandleException(e) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
@ -302,6 +307,7 @@ bool EmuTryHandleException(EXCEPTION_POINTERS *e)
// Check if lle exception is already called first before emu exception.
if (bOverrideException) {
genericException(e);
return false;
}
@ -346,7 +352,7 @@ bool EmuTryHandleException(EXCEPTION_POINTERS *e)
return false;
}
int EmuException(EXCEPTION_POINTERS *e)
long WINAPI EmuException(struct _EXCEPTION_POINTERS* e)
{
g_bEmuException = true;
LONG result = EmuTryHandleException(e) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
@ -355,6 +361,7 @@ int EmuException(EXCEPTION_POINTERS *e)
}
// exception handle for that tough final exit :)
// TODO: We might just well as delete this, duplicate of EmuExceptionNonBreakpointUnhandledShow
int ExitException(LPEXCEPTION_POINTERS e)
{
static int count = 0;
@ -395,15 +402,25 @@ ExceptionManager::ExceptionManager()
ExceptionManager::~ExceptionManager()
{
for (auto i_handle : veh_handles) {
RemoveVectoredExceptionHandler(i_handle);
(void)RemoveVectoredExceptionHandler(i_handle);
}
veh_handles.clear();
#ifdef _MSC_VER // Windows' C++ exception is using SEH, we cannot use VEH for error reporter system.
(void)SetUnhandledExceptionFilter(nullptr);
#endif
}
// Require to be set right before we call xbe's entry point.
void ExceptionManager::EmuX86_Init()
{
accept_request = false; // Do not allow add VEH during emulation.
AddVEH(1, lleException, true); // Front line call
// Last call plus show exception error than terminate early.
#ifdef _MSC_VER // Windows' C++ exception is using SEH, we cannot use VEH for error reporter system.
(void)SetUnhandledExceptionFilter(EmuException);
#else // Untested for other platforms, may will behave as expected.
AddVEH(0, EmuException, true);
#endif
}
bool ExceptionManager::AddVEH(unsigned long first, PVECTORED_EXCEPTION_HANDLER veh_handler)

View File

@ -35,8 +35,6 @@
std::string FormatTitleId(uint32_t title_id);
// exception handler
extern LONG NTAPI lleException(EXCEPTION_POINTERS *e);
int EmuException(EXCEPTION_POINTERS *e);
class ExceptionManager {
public:
ExceptionManager();

View File

@ -57,6 +57,8 @@ extern std::atomic_bool g_bEnableAllInterrupts;
static int field_pin = 0;
static thread_local bool g_tls_isEmuX86Managed;
uint32_t EmuX86_IORead(xbaddr addr, int size)
{
switch (addr) {
@ -110,48 +112,36 @@ void EmuX86_IOWrite(xbaddr addr, uint32_t value, int size)
uint32_t EmuX86_Mem_Read(xbaddr addr, int size)
{
__try {
switch (size) {
case sizeof(uint32_t) :
return *(uint32_t*)addr;
case sizeof(uint16_t) :
return *(uint16_t*)addr;
case sizeof(uint8_t) :
return *(uint8_t*)addr;
default:
// UNREACHABLE(size);
assert(false);
return 0;
}
}
__except (true) { // TODO : EXCEPTION_EXECUTE_HANDLER instead of true?
EmuLog(LOG_LEVEL::WARNING, "EmuX86_Mem_Read Failed (0x%08X, %d)", addr, size);
switch (size) {
case sizeof(uint32_t) :
return *(uint32_t*)addr;
case sizeof(uint16_t) :
return *(uint16_t*)addr;
case sizeof(uint8_t) :
return *(uint8_t*)addr;
default:
// UNREACHABLE(size);
assert(false);
return 0;
}
}
void EmuX86_Mem_Write(xbaddr addr, uint32_t value, int size)
{
__try {
switch (size) {
case sizeof(uint32_t) :
*(uint32_t*)addr = (uint32_t)value;
break;
case sizeof(uint16_t) :
*(uint16_t*)addr = (uint16_t)value;
break;
case sizeof(uint8_t) :
*(uint8_t*)addr = (uint8_t)value;
break;
default:
// UNREACHABLE(size);
assert(false);
return;
}
}
__except (true) { // TODO : EXCEPTION_EXECUTE_HANDLER instead of true?
EmuLog(LOG_LEVEL::WARNING, "EmuX86_Mem_Write Failed (0x%08X, 0x%08X, %d)", addr, value, size);
switch (size) {
case sizeof(uint32_t) :
*(uint32_t*)addr = (uint32_t)value;
break;
case sizeof(uint16_t) :
*(uint16_t*)addr = (uint16_t)value;
break;
case sizeof(uint8_t) :
*(uint8_t*)addr = (uint8_t)value;
break;
default:
// UNREACHABLE(size);
assert(false);
return;
}
}
@ -187,23 +177,25 @@ uint32_t EmuX86_Read(xbaddr addr, int size)
uint32_t value;
if (addr >= XBOX_FLASH_ROM_BASE) { // 0xFFF00000 - 0xFFFFFFF
value = EmuFlash_Read32(addr - XBOX_FLASH_ROM_BASE); // TODO : Make flash access size-aware
} else if(addr == 0xFE80200C) {
// TODO: Remove this once we have an LLE APU Device
return GetAPUTime();
} else {
// Pass the Read to the PCI Bus, this will handle devices with BARs set to MMIO addresses
if (g_PCIBus->MMIORead(addr, &value, size)) {
return value;
}
//pass the memory-access through to normal memory :
value = EmuX86_Mem_Read(addr, size);
EmuLog(LOG_LEVEL::DEBUG, "Read(0x%08X, %d) = 0x%08X", addr, size, value);
return EmuFlash_Read32(addr - XBOX_FLASH_ROM_BASE); // TODO : Make flash access size-aware
}
return value;
// TODO: Remove this once we have an LLE APU Device
if(addr == 0xFE80200C) {
return GetAPUTime();
}
// Pass the Read to the PCI Bus, this will handle devices with BARs set to MMIO addresses
if (g_PCIBus->MMIORead(addr, &value, size)) {
return value;
}
// EmuX86 is not suppose to do direct read to host memory and should be handle from
// redirect from above statements. If it doesn't meet any requirement, then should be
// handle as possible fatal crash instead of return corrupt value.
g_tls_isEmuX86Managed = false;
return 0;
}
void EmuX86_Write(xbaddr addr, uint32_t value, int size)
@ -224,9 +216,10 @@ void EmuX86_Write(xbaddr addr, uint32_t value, int size)
return;
}
// Pass the memory-access through to normal memory :
EmuLog(LOG_LEVEL::DEBUG, "Write(0x%.8X, 0x%.8X, %d)", addr, value, size);
EmuX86_Mem_Write(addr, value, size);
// EmuX86 is not suppose to do direct write to host memory and should be handle from
// redirect from above statements. If it doesn't meet any requirement, then should be
// handle as possible fatal crash instead of set corrupt value.
g_tls_isEmuX86Managed = false;
}
int ContextRecordOffsetByRegisterType[/*_RegisterType*/R_DR7 + 1] = { 0 };
@ -2786,7 +2779,7 @@ void output_segment(std::stringstream &output, _DInst &info)
output << Distorm_RegStrings[SEGMENT_GET(info.segment)] << ":";
}
void EmuX86_DistormLogInstruction(const uint8_t *Eip, _DInst &info)
void EmuX86_DistormLogInstruction(const uint8_t *Eip, _DInst &info, LOG_LEVEL log_level)
{
std::stringstream output;
@ -2907,7 +2900,7 @@ void EmuX86_DistormLogInstruction(const uint8_t *Eip, _DInst &info)
#define FLAG_GET_PREFIX(flags) ((flags) & 7) // To get the LOCK/REPNZ/REP prefixes.
*/
EmuLog(LOG_LEVEL::DEBUG, output.str().c_str());
EmuLog(log_level, output.str().c_str());
}
int EmuX86_OpcodeSize(uint8_t *Eip)
@ -2928,10 +2921,9 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
// However, if for any reason, an opcode operand cannot be read from or written to,
// that case may be logged, but it shouldn't fail the opcode handler.
_DInst info;
g_tls_isEmuX86Managed = true;
DWORD StartingEip = e->ContextRecord->Eip;
LOG_CHECK_ENABLED(LOG_LEVEL::DEBUG) {
EmuLog(LOG_LEVEL::DEBUG, "Starting instruction emulation from 0x%08X", e->ContextRecord->Eip);
}
EmuLog(LOG_LEVEL::DEBUG, "Starting instruction emulation from 0x%08X", e->ContextRecord->Eip);
// Execute op-codes until we hit an unhandled instruction, or an error occurs
//while (true)
@ -2947,7 +2939,7 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
}
LOG_CHECK_ENABLED(LOG_LEVEL::DEBUG) {
EmuX86_DistormLogInstruction((uint8_t*)e->ContextRecord->Eip, info);
EmuX86_DistormLogInstruction((uint8_t*)e->ContextRecord->Eip, info, LOG_LEVEL::DEBUG);
}
switch (info.opcode) { // Keep these cases alphabetically ordered and condensed
@ -3295,10 +3287,15 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
return true;
} // switch info.opcode
e->ContextRecord->Eip += info.size;
if (g_tls_isEmuX86Managed) {
e->ContextRecord->Eip += info.size;
}
else {
break;
}
} // while true
return true;
return g_tls_isEmuX86Managed;
opcode_error:
EmuLog(LOG_LEVEL::WARNING, "0x%08X: Error while handling instruction %s (%u)", e->ContextRecord->Eip, Distorm_OpcodeString(info.opcode), info.opcode);
@ -3310,7 +3307,8 @@ void EmuX86_Init()
{
EmuLog(LOG_LEVEL::DEBUG, "Initializing distorm version %d", distorm_version());
AddVectoredExceptionHandler(/*FirstHandler=*/ULONG(true), lleException);
// Initialize emulation exception to ensure they are front and last line of exception.
g_ExceptionManager->EmuX86_Init();
EmuX86_InitContextRecordOffsetByRegisterType();
EmuX86_InitMemoryBackedRegisters();