/* $Id: oslibexcept.cpp,v 1.7 2001-06-04 21:18:40 sandervl Exp $ */ /* * Exception handler util. procedures * * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl) * */ #define INCL_BASE #define INCL_DOSEXCEPTIONS #define INCL_DOSMEMMGR #define INCL_DOSPROCESS #include //Odin32 OS/2 api wrappers #include #include #include #include #include #include #include #include "oslibexcept.h" #define DBG_LOCALLOG DBG_oslibexcept #include "dbglocal.h" /** * Converts the OS/2 exception information to the Win32 exception information. * * Returns TRUE on succes and FALSE otherwise. */ BOOL APIENTRY OSLibConvertExceptionInfo(PEXCEPTIONREPORTRECORD pReportRec, PCONTEXTRECORD pContextRec, PWINEXCEPTION_RECORD pWinReportRec, PWINCONTEXT pWinContextRec, TEB *pWinTEB) { memset(pWinReportRec, 0, sizeof(*pWinReportRec)); memcpy(pWinReportRec, pReportRec, sizeof(*pReportRec)); switch (pReportRec->ExceptionNum) { case XCPT_FLOAT_DENORMAL_OPERAND: pWinReportRec->ExceptionCode = EXCEPTION_FLT_DENORMAL_OPERAND; break; case XCPT_FLOAT_DIVIDE_BY_ZERO: pWinReportRec->ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO; break; case XCPT_FLOAT_INEXACT_RESULT: pWinReportRec->ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT; break; case XCPT_FLOAT_INVALID_OPERATION: pWinReportRec->ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; break; case XCPT_FLOAT_OVERFLOW: pWinReportRec->ExceptionCode = EXCEPTION_FLT_OVERFLOW; break; case XCPT_FLOAT_STACK_CHECK: pWinReportRec->ExceptionCode = EXCEPTION_FLT_STACK_CHECK; break; case XCPT_FLOAT_UNDERFLOW: pWinReportRec->ExceptionCode = EXCEPTION_FLT_UNDERFLOW; break; case XCPT_INTEGER_DIVIDE_BY_ZERO: pWinReportRec->ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO; break; case XCPT_INTEGER_OVERFLOW: pWinReportRec->ExceptionCode = EXCEPTION_INT_OVERFLOW; break; case XCPT_PRIVILEGED_INSTRUCTION: pWinReportRec->ExceptionCode = EXCEPTION_PRIV_INSTRUCTION; break; case XCPT_BREAKPOINT: pWinReportRec->ExceptionCode = EXCEPTION_BREAKPOINT; break; case XCPT_SINGLE_STEP: pWinReportRec->ExceptionCode = EXCEPTION_SINGLE_STEP; break; case XCPT_ARRAY_BOUNDS_EXCEEDED: pWinReportRec->ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; break; case XCPT_DATATYPE_MISALIGNMENT: pWinReportRec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; break; case XCPT_ILLEGAL_INSTRUCTION: pWinReportRec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; case XCPT_INVALID_LOCK_SEQUENCE: pWinReportRec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; case XCPT_GUARD_PAGE_VIOLATION: pWinReportRec->ExceptionCode = EXCEPTION_GUARD_PAGE; break; case XCPT_UNABLE_TO_GROW_STACK: pWinReportRec->ExceptionCode = EXCEPTION_STACK_OVERFLOW; break; case XCPT_IN_PAGE_ERROR: pWinReportRec->ExceptionCode = EXCEPTION_IN_PAGE_ERROR; break; case XCPT_ACCESS_VIOLATION: pWinReportRec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION; break; default: // no other exceptions should be dispatched to win32 apps return FALSE; } // TODO: // According to the Wine folks the flags are the same in OS/2 and win32 // Let's assume for now the rest is identical as well // copy context record info memset(pWinContextRec, 0, sizeof(*pWinContextRec)); if (pContextRec->ContextFlags & CONTEXT_CONTROL) { pWinContextRec->ContextFlags |= WINCONTEXT_CONTROL; pWinContextRec->Ebp = pContextRec->ctx_RegEbp; pWinContextRec->Eip = pContextRec->ctx_RegEip; pWinContextRec->SegCs = pContextRec->ctx_SegCs; pWinContextRec->EFlags = pContextRec->ctx_EFlags; pWinContextRec->Esp = pContextRec->ctx_RegEsp; pWinContextRec->SegSs = pContextRec->ctx_SegSs; } if (pContextRec->ContextFlags & CONTEXT_INTEGER) { pWinContextRec->ContextFlags |= WINCONTEXT_INTEGER; pWinContextRec->Edi = pContextRec->ctx_RegEdi; pWinContextRec->Esi = pContextRec->ctx_RegEsi; pWinContextRec->Ebx = pContextRec->ctx_RegEbx; pWinContextRec->Edx = pContextRec->ctx_RegEdx; pWinContextRec->Ecx = pContextRec->ctx_RegEcx; pWinContextRec->Eax = pContextRec->ctx_RegEax; } if (pContextRec->ContextFlags & CONTEXT_SEGMENTS) { pWinContextRec->ContextFlags |= WINCONTEXT_SEGMENTS; pWinContextRec->SegGs = pContextRec->ctx_SegGs; // set Wn32 TEB if we run in switch FS mode if (pWinTEB) pWinContextRec->SegFs = pWinTEB->teb_sel; else pWinContextRec->SegFs = pContextRec->ctx_SegFs; pWinContextRec->SegEs = pContextRec->ctx_SegEs; pWinContextRec->SegDs = pContextRec->ctx_SegDs; } if (pContextRec->ContextFlags & CONTEXT_FLOATING_POINT) { pWinContextRec->ContextFlags |= WINCONTEXT_FLOATING_POINT; //TODO: First 7 dwords the same? memcpy(&pWinContextRec->FloatSave, pContextRec->ctx_env, sizeof(pContextRec->ctx_env)); memcpy(&pWinContextRec->FloatSave.RegisterArea, pContextRec->ctx_stack, sizeof(pContextRec->ctx_stack)); } return TRUE; } /** * Converts the Win32 exception handler result to the OS/2 exception handler * result. * * Returns TRUE if the OS/2 exception handler result should be * XCPT_CONTINUE_EXECUTION and FALSE otherwise. */ BOOL APIENTRY OSLibConvertExceptionResult(ULONG rc, PWINCONTEXT pWinContextRec, PCONTEXTRECORD pContextRec) { if (rc != ExceptionContinueExecution) { dprintf(("Win32 exception handler returned %s (%d)", rc == ExceptionContinueSearch ? "ExceptionContinueSearch" : "???", rc)); return FALSE; } dprintf(("Win32 exception handler returned ExceptionContinueExecution (%d)", ExceptionContinueExecution)); if (pWinContextRec->ContextFlags & WINCONTEXT_CONTROL) { pContextRec->ctx_RegEbp = pWinContextRec->Ebp; pContextRec->ctx_RegEip = pWinContextRec->Eip; pContextRec->ctx_SegCs = pWinContextRec->SegCs; pContextRec->ctx_EFlags = pWinContextRec->EFlags; pContextRec->ctx_RegEsp = pWinContextRec->Esp; pContextRec->ctx_SegSs = pWinContextRec->SegSs; } if (pWinContextRec->ContextFlags & WINCONTEXT_INTEGER) { pContextRec->ctx_RegEdi = pWinContextRec->Edi; pContextRec->ctx_RegEsi = pWinContextRec->Esi; pContextRec->ctx_RegEbx = pWinContextRec->Ebx; pContextRec->ctx_RegEdx = pWinContextRec->Edx; pContextRec->ctx_RegEcx = pWinContextRec->Ecx; pContextRec->ctx_RegEax = pWinContextRec->Eax; } #if 0 // This is not a good idea if (pWinContextRec->ContextFlags & WINCONTEXT_SEGMENTS) { pContextRec->ctx_SegGs = pWinContextRec->SegGs; pContextRec->ctx_SegFs = pWinContextRec->SegFs; pContextRec->ctx_SegEs = pWinContextRec->SegEs; pContextRec->ctx_SegDs = pWinContextRec->SegDs; } #endif if (pWinContextRec->ContextFlags & WINCONTEXT_FLOATING_POINT) { //TODO: First 7 dwords the same? memcpy(pContextRec->ctx_env, &pWinContextRec->FloatSave, sizeof(pContextRec->ctx_env)); memcpy(pContextRec->ctx_stack, &pWinContextRec->FloatSave.RegisterArea, sizeof(pContextRec->ctx_stack)); } if (pContextRec->ContextFlags & CONTEXT_CONTROL) /* check flags */ dprintf((" SS:ESP=%04x:%08x EFLAGS=%08x\n", pContextRec->ctx_SegSs, pContextRec->ctx_RegEsp, pContextRec->ctx_EFlags)); dprintf((" CS:EIP=%04x:%08x EBP =%08x\n", pContextRec->ctx_SegCs, pContextRec->ctx_RegEip, pContextRec->ctx_RegEbp)); if (pContextRec->ContextFlags & CONTEXT_INTEGER) /* check flags */ dprintf((" EAX=%08x EBX=%08x ESI=%08x\n", pContextRec->ctx_RegEax, pContextRec->ctx_RegEbx, pContextRec->ctx_RegEsi)); dprintf((" ECX=%08x EDX=%08x EDI=%08x\n", pContextRec->ctx_RegEcx, pContextRec->ctx_RegEdx, pContextRec->ctx_RegEdi)); if (pContextRec->ContextFlags & CONTEXT_SEGMENTS) /* check flags */ dprintf((" DS=%04x ES=%08x" " FS=%04x GS=%04x\n", pContextRec->ctx_SegDs, pContextRec->ctx_SegEs, pContextRec->ctx_SegFs, pContextRec->ctx_SegGs)); if (pContextRec->ContextFlags & CONTEXT_FLOATING_POINT) /* check flags */ { ULONG ulCounter; /* temporary local counter for fp stack */ dprintf((" Env[0]=%08x Env[1]=%08x Env[2]=%08x Env[3]=%08x\n", pContextRec->ctx_env[0], pContextRec->ctx_env[1], pContextRec->ctx_env[2], pContextRec->ctx_env[3])); dprintf((" Env[4]=%08x Env[5]=%08x Env[6]=%08x\n", pContextRec->ctx_env[4], pContextRec->ctx_env[5], pContextRec->ctx_env[6])); for (ulCounter = 0; ulCounter < 8; /* see TOOLKIT\INCLUDE\BSEEXPT.H, _CONTEXT structure */ ulCounter ++) dprintf((" FP-Stack[%u] losig=%08x hisig=%08x signexp=%04x\n", ulCounter, pContextRec->ctx_stack[0].losig, pContextRec->ctx_stack[0].hisig, pContextRec->ctx_stack[0].signexp)); } return TRUE; } /** * Dispatches OS/2 exception to win32 handler. * * Returns TRUE if the Win32 exception handler returned * ExceptionContinueExecution and FALSE otherwise. */ BOOL APIENTRY OSLibDispatchExceptionWin32(PEXCEPTIONREPORTRECORD pReportRec, PEXCEPTIONREGISTRATIONRECORD pRegistrationRec, PCONTEXTRECORD pContextRec, PVOID p) { WINEXCEPTION_RECORD winReportRec; WINCONTEXT winContextRec; ULONG rc; TEB *pWinTEB = GetThreadTEB(); OSLibConvertExceptionInfo(pReportRec, pContextRec, &winReportRec, &winContextRec, pWinTEB); // It doesn't seem correct if we dispatch real exceptions to win32 apps // Some just call RtlUnwind and continue as if they were processing an // exception thrown by C++ code. (instead of real OS exception) // We need to reset FS to its original (Win32) value, otherwise we'll likely // fuck up the Win32 exception handlers. They could end up using the wrong // exception chain if they access FS:[0] directly. DWORD oldsel = SetReturnFS(pWinTEB->teb_sel); switch(pReportRec->ExceptionNum) { case XCPT_FLOAT_DENORMAL_OPERAND: case XCPT_FLOAT_DIVIDE_BY_ZERO: case XCPT_FLOAT_INEXACT_RESULT: case XCPT_FLOAT_INVALID_OPERATION: case XCPT_FLOAT_OVERFLOW: case XCPT_FLOAT_STACK_CHECK: case XCPT_FLOAT_UNDERFLOW: rc = RtlDispatchException(&winReportRec, &winContextRec); break; case XCPT_ACCESS_VIOLATION: rc = RtlDispatchException(&winReportRec, &winContextRec); break; case XCPT_ILLEGAL_INSTRUCTION: case XCPT_PRIVILEGED_INSTRUCTION: case XCPT_INTEGER_DIVIDE_BY_ZERO: case XCPT_UNABLE_TO_GROW_STACK: case XCPT_GUARD_PAGE_VIOLATION: #ifndef DEBUG case XCPT_BREAKPOINT: #endif rc = RtlDispatchException(&winReportRec, &winContextRec); break; #ifdef DEBUG case XCPT_BREAKPOINT: #endif case XCPT_INTEGER_OVERFLOW: case XCPT_SINGLE_STEP: case XCPT_ARRAY_BOUNDS_EXCEEDED: case XCPT_DATATYPE_MISALIGNMENT: case XCPT_INVALID_LOCK_SEQUENCE: case XCPT_IN_PAGE_ERROR: default: SetFS(oldsel); //restore FS return FALSE; //let's not dispatch those for now } SetFS(oldsel); //restore FS return OSLibConvertExceptionResult(rc, &winContextRec, pContextRec); }