diff options
Diffstat (limited to 'private/crt32/misc/winxfltr.c')
-rw-r--r-- | private/crt32/misc/winxfltr.c | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/private/crt32/misc/winxfltr.c b/private/crt32/misc/winxfltr.c new file mode 100644 index 000000000..22b4f08f4 --- /dev/null +++ b/private/crt32/misc/winxfltr.c @@ -0,0 +1,618 @@ +/*** +*winxfltr.c - startup exception filter +* +* Copyright (c) 1990-1993, Microsoft Corporation. All rights reserved +* +*Purpose: +* Defines _XcptFilter(), the function called by the exception filter +* expression in the startup code. +* +*Revision History: +* 10-31-91 GJF Module created. Copied from the original xcptfltr.c +* then extensively revised. +* 11-08-91 GJF Cleaned up header files usage. +* 12-13-91 GJF Fixed multi-thread build. +* 01-17-92 GJF Changed default handling under Win32 - unhandled +* exceptions are now passed to UnhandledExceptionFilter. +* Dosx32 behavior in unchanged. Also, used a couple of +* local macros to simplify handling of single-thread vs +* multi-thread code [_Win32_]. +* 02-16-93 GJF Changed for new _getptd(). +* 04-27-93 GJF Removed (commented out) entries in _XcptActTab which +* corresponded to C RTEs. These will now simply be +* passed on through to the system exception handler. +* +*******************************************************************************/ + +#ifndef _POSIX_ + +#include <cruntime.h> +#include <float.h> +#include <os2dll.h> +#include <oscalls.h> +#include <signal.h> +#include <stddef.h> + + +/* + * special code denoting no signal. + */ +#define NOSIG -1 + + +struct _XCPT_ACTION _VARTYPE1 _XcptActTab[] = { + +/* + * Exceptions corresponding to the same signal (e.g., SIGFPE) must be grouped + * together. + * + * XcptNum SigNum XcptAction + * ------------------------------------------------------------------- + */ + { (unsigned long)STATUS_ACCESS_VIOLATION, SIGSEGV, SIG_DFL }, + + { (unsigned long)STATUS_ILLEGAL_INSTRUCTION, SIGILL, SIG_DFL }, + + { (unsigned long)STATUS_PRIVILEGED_INSTRUCTION, SIGILL, SIG_DFL }, + +/* { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION, NOSIG, SIG_DIE }, + */ +/* { (unsigned long)STATUS_INVALID_DISPOSITION, NOSIG, SIG_DIE }, + */ + { (unsigned long)STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_INEXACT_RESULT, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_INVALID_OPERATION, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_OVERFLOW, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_STACK_CHECK, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_UNDERFLOW, SIGFPE, SIG_DFL }, + +/* { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO, NOSIG, SIG_DIE }, + */ +/* { (unsigned long)STATUS_STACK_OVERFLOW, NOSIG, SIG_DIE } + */ +}; + +/* + * size of the exception-action table (in bytes) + */ +int _CRTVAR1 _XcptActTabSize = sizeof _XcptActTab; + +/* + * number of entries in the exception-action table + */ +int _CRTVAR1 _XcptActTabCount = (sizeof _XcptActTab)/sizeof(_XcptActTab[0]); + + +#ifdef MTHREAD + +/* + * the FPECODE and PXCPTINFOPTRS macros are intended to simplify some of + * single vs multi-thread code in the filter function. basically, each macro + * is conditionally defined to be a global variable or the corresponding + * field in the per-thread data structure. NOTE THE ASSUMPTION THAT THE + * _ptiddata VARIABLE IS ALWAYS NAMED ptd!!!! + */ + +#define FPECODE ptd->_tfpecode + +#define PXCPTINFOPTRS ptd->_tpxcptinfoptrs + +#else + +/* + * global variable containing the floating point exception code + */ +int _VARTYPE1 _fpecode = _FPE_EXPLICITGEN; + +#define FPECODE _fpecode + +/* + * global variable holding _PEXCEPTION_INFO_PTRS value + */ +void * _VARTYPE1 _pxcptinfoptrs = NULL; + +#define PXCPTINFOPTRS _pxcptinfoptrs + +#endif /* MTHREAD */ + +/* + * function to look up the exception action table (_XcptActTab[]) corresponding + * to the given exception + */ + +#ifdef MTHREAD + +static struct _XCPT_ACTION * _CRTAPI3 xcptlookup( + unsigned long, + struct _XCPT_ACTION * + ); + +#else /* ndef MTHREAD */ + +static struct _XCPT_ACTION * _CRTAPI3 xcptlookup( + unsigned long + ); + +#endif /* MTHREAD */ + +#ifdef DEBUG + +/* + * prototypes for debugging routines + */ +void prXcptActTabEntry(struct _XCPT_ACTION *); +void prXcptActTab(void); + +#endif /* DEBUG */ + +/*** +*int _XcptFilter(xcptnum, pxcptptrs) - Identify exception and the action to +* be taken with it +* +*Purpose: +* _XcptFilter() is called by the exception filter expression of the +* _try - _except statement, in the startup code, which guards the call +* to the user's main(). _XcptFilter() consults the _XcptActTab[] table +* to identify the exception and determine its disposition. The +* is disposition of an exception corresponding to a C signal may be +* modified by a call to signal(). There are three broad cases: +* +* (1) Unrecognized exceptions and exceptions for which the XcptAction +* value is SIG_DFL. +* +#ifndef DOSX32 +* In both of these cases, UnhandledExceptionFilter() is called and +* its return value is returned. +#else +* In both of these cases, EXCEPTION_CONTINUE_SEARCH is returned to +* cause the OS exception dispatcher to pass the exception onto the +* next exception handler in the chain (usually a system default +* handler). +#endif +* +* (2) Exceptions corresponding to C signals with an XcptAction value +* NOT equal to SIG_DFL. +* +* These are the C signals whose disposition has been affected by a +* call to signal() or whose default semantics differ slightly from +* from the corresponding OS exception. In all cases, the appropriate +* disposition of the C signal is made by the function (e.g., calling +* a user-specified signal handler). Then, EXCEPTION_CONTINUE_EXECU- +* TION is returned to cause the OS exception dispatcher to dismiss +* the exception and resume execution at the point where the +* exception occurred. +* +* (3) Exceptions for which the XcptAction value is SIG_DIE. +* +* These are the exceptions corresponding to fatal C runtime errors. +* _XCPT_HANDLE is returned to cause control to pass into the +* _except-block of the _try - _except statement. There, the runtime +* error is identified, an appropriate error message is printed out +* and the program is terminated. +* +*Entry: +* +*Exit: +* +*Exceptions: +* That's what it's all about! +* +*******************************************************************************/ + +int _CRTAPI1 _XcptFilter ( + unsigned long xcptnum, + PEXCEPTION_POINTERS pxcptinfoptrs + ) +{ + struct _XCPT_ACTION * pxcptact; + _PHNDLR phandler; + void *oldpxcptinfoptrs; + int oldfpecode; + +#ifdef MTHREAD + _ptiddata ptd = _getptd(); +#endif /* MTHREAD */ + + /* + * first, take care of all unrecognized exceptions and exceptions with + * XcptAction values of SIG_DFL. + */ +#ifdef MTHREAD + if ( ((pxcptact = xcptlookup(xcptnum, ptd->_pxcptacttab)) == NULL) + || (pxcptact->XcptAction == SIG_DFL) ) +#else /* not MTHREAD */ + if ( ((pxcptact = xcptlookup(xcptnum)) == NULL) || + (pxcptact->XcptAction == SIG_DFL) ) +#endif /* MTHREAD */ + +#ifndef DOSX32 + /* + * pass the buck to the UnhandledExceptionFilter + */ + return( UnhandledExceptionFilter(pxcptinfoptrs) ); +#else + /* + * pass the buck to the next level exception handler + */ + return(EXCEPTION_CONTINUE_SEARCH); +#endif + +#ifdef DEBUG + prXcptActTabEntry(pxcptact); +#endif /* DEBUG */ + + /* + * next, weed out all of the exceptions that need to be handled by + * dying, perhaps with a runtime error message + */ + if ( pxcptact->XcptAction == SIG_DIE ) { + /* + * reset XcptAction (in case of recursion) and drop into the + * except-clause. + */ + pxcptact->XcptAction = SIG_DFL; + return(EXCEPTION_EXECUTE_HANDLER); + } + + /* + * next, weed out all of the exceptions that are simply ignored + */ + if ( pxcptact->XcptAction == SIG_IGN ) + /* + * resume execution + */ + return(EXCEPTION_CONTINUE_EXECUTION); + + /* + * the remaining exceptions all correspond to C signals which have + * signal handlers associated with them. for some, special setup + * is required before the signal handler is called. in all cases, + * if the signal handler returns, -1 is returned by this function + * to resume execution at the point where the exception occurred. + * + * before calling the signal handler, the XcptAction field of the + * exception-action table entry must be reset. + */ + phandler = pxcptact->XcptAction; + + /* + * reset the action to be the default + */ + pxcptact->XcptAction = SIG_DFL; + + /* + * save the old value of _pxcptinfoptrs (in case this is a nested + * exception/signal) and store the current one. + */ + oldpxcptinfoptrs = PXCPTINFOPTRS; + PXCPTINFOPTRS = pxcptinfoptrs; + + /* + * call the user-supplied signal handler + * + * floating point exceptions must be handled specially since, from + * the C point-of-view, there is only one signal. the exact identity + * of the exception is passed in the global variable _fpecode. + */ + if ( pxcptact->SigNum == SIGFPE ) { + /* + * Save the current _fpecode in case it is a nested floating + * point exception (not clear that we need to support this, + * but it's easy). + */ + oldfpecode = FPECODE; + + /* + * there are no exceptions corresponding to + * following _FPE_xxx codes: + * + * _FPE_UNEMULATED + * _FPE_SQRTNEG + * + * futhermore, STATUS_FLOATING_STACK_CHECK is + * raised for both floating point stack under- + * flow and overflow. thus, the exception does + * not distinguish between _FPE_STACKOVERLOW + * and _FPE_STACKUNDERFLOW. arbitrarily, _fpecode + * is set to the former value. + * + * the following should be a switch statement but, alas, the + * compiler doesn't like switching on unsigned longs... + */ + if ( pxcptact->XcptNum == STATUS_FLOAT_DIVIDE_BY_ZERO ) + + FPECODE = _FPE_ZERODIVIDE; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_INVALID_OPERATION ) + + FPECODE = _FPE_INVALID; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_OVERFLOW ) + + FPECODE = _FPE_OVERFLOW; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_UNDERFLOW ) + + FPECODE = _FPE_UNDERFLOW; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_DENORMAL_OPERAND ) + + FPECODE = _FPE_DENORMAL; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_INEXACT_RESULT ) + + FPECODE = _FPE_INEXACT; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_STACK_CHECK ) + + FPECODE = _FPE_STACKOVERFLOW; + + /* + * call the SIGFPE handler. note the special hack to support + * old MS-C programs whose SIGFPE handlers expect two args. + * + * NOTE: THE CAST AND CALL BELOW DEPEND ON _CRTAPI1 BEING + * CALLER CLEANUP! + */ + (*(void (* _CRTAPI1)(int, int))phandler)(SIGFPE, FPECODE); + + /* + * restore the old value of _fpecode + */ + FPECODE = oldfpecode; + } + else + (*phandler)(pxcptact->SigNum); + + /* + * restore the old value of _pxcptinfoptrs + */ + PXCPTINFOPTRS = oldpxcptinfoptrs; + + return(EXCEPTION_CONTINUE_EXECUTION); + +} + + +/*** +*struct _XCPT_ACTION * xcptlookup(xcptnum, pxcptrec) - look up exception-action +* table entry for xcptnum +* +*Purpose: +* Find the in _XcptActTab[] whose Xcptnum field is xcptnum. +* +*Entry: +* unsigned long xcptnum - exception type +* +* _PEXCEPTIONREPORTRECORD pxcptrec - pointer to exception report record +* (used only to distinguish different types of XCPT_SIGNAL) +* +*Exit: +* If successful, pointer to the table entry. If no such entry, NULL is +* returned. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +static struct _XCPT_ACTION * _CRTAPI3 xcptlookup ( + unsigned long xcptnum, + struct _XCPT_ACTION * pxcptacttab + ) + +#else /* not MTHREAD */ + +static struct _XCPT_ACTION * _CRTAPI3 xcptlookup ( + unsigned long xcptnum + ) + +#endif /* MTHREAD */ + +{ +#ifdef MTHREAD + struct _XCPT_ACTION *pxcptact = pxcptacttab; +#else /* ndef MTHREAD */ + struct _XCPT_ACTION *pxcptact = _XcptActTab; +#endif /* MTHREAD */ + + /* + * walk thru the _xcptactab table looking for the proper entry + */ +#ifdef MTHREAD + + while ( (pxcptact->XcptNum != xcptnum) && (++pxcptact < + pxcptacttab + _XcptActTabCount) ) ; + +#else /* not MTHREAD */ + + while ( (pxcptact->XcptNum != xcptnum) && (++pxcptact < + _XcptActTab + _XcptActTabCount) ) ; + +#endif /* MTHREAD */ + + /* + * if no table entry was found corresponding to xcptnum, return NULL + */ + if ( pxcptact->XcptNum != xcptnum ) + return(NULL); + + return(pxcptact); +} + +#ifdef DEBUG + +/* + * DEBUGGING TOOLS! + */ +struct xcptnumstr { + unsigned long num; + char *str; +}; + +struct xcptnumstr XcptNumStr[] = { + + { (unsigned long)STATUS_DATATYPE_MISALIGNMENT, + "STATUS_DATATYPE_MISALIGNMENT" }, + + { (unsigned long)STATUS_ACCESS_VIOLATION, + "STATUS_ACCESS_VIOLATION" }, + + { (unsigned long)STATUS_ILLEGAL_INSTRUCTION, + "STATUS_ILLEGAL_INSTRUCTION" }, + + { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION, + "STATUS_NONCONTINUABLE_EXCEPTION" }, + + { (unsigned long)STATUS_INVALID_DISPOSITION, + "STATUS_INVALID_DISPOSITION" }, + + { (unsigned long)STATUS_FLOAT_DENORMAL_OPERAND, + "STATUS_FLOAT_DENORMAL_OPERAND" }, + + { (unsigned long)STATUS_FLOAT_DIVIDE_BY_ZERO, + "STATUS_FLOAT_DIVIDE_BY_ZERO" }, + + { (unsigned long)STATUS_FLOAT_INEXACT_RESULT, + "STATUS_FLOAT_INEXACT_RESULT" }, + + { (unsigned long)STATUS_FLOAT_INVALID_OPERATION, + "STATUS_FLOAT_INVALID_OPERATION" }, + + { (unsigned long)STATUS_FLOAT_OVERFLOW, + "STATUS_FLOAT_OVERFLOW" }, + + { (unsigned long)STATUS_FLOAT_STACK_CHECK, + "STATUS_FLOAT_STACK_CHECK" }, + + { (unsigned long)STATUS_FLOAT_UNDERFLOW, + "STATUS_FLOAT_UNDERFLOW" }, + + { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO, + "STATUS_INTEGER_DIVIDE_BY_ZERO" }, + + { (unsigned long)STATUS_PRIVILEGED_INSTRUCTION, + "STATUS_PRIVILEGED_INSTRUCTION" }, + + { (unsigned long)_STATUS_STACK_OVERFLOW, + "_STATUS_STACK_OVERFLOW" } +}; + +#define XCPTNUMSTR_SZ ( sizeof XcptNumStr / sizeof XcptNumStr[0] ) + +/* + * return string mnemonic for exception + */ +char * XcptNumToStr ( + unsigned long xcptnum + ) +{ + int indx; + + for ( indx = 0 ; indx < XCPTNUMSTR_SZ ; indx++ ) + if ( XcptNumStr[indx].num == xcptnum ) + return(XcptNumStr[indx].str); + + return(NULL); +} + +struct signumstr { + int num; + char *str; +}; + +struct signumstr SigNumStr[] = { + { SIGINT, "SIGINT" }, + { SIGILL, "SIGILL" }, + { SIGFPE, "SIGFPE" }, + { SIGSEGV, "SIGSEGV" }, + { SIGTERM, "SIGTERM" }, + { SIGBREAK, "SIGBREAK" }, + { SIGABRT, "SIGABRT" } +}; + +#define SIGNUMSTR_SZ ( sizeof SigNumStr / sizeof SigNumStr[0] ) + +/* + * return string mnemonic for signal + */ +char * SigNumToStr ( + int signum + ) +{ + int indx; + + for ( indx = 0 ; indx < SIGNUMSTR_SZ ; indx++ ) + if ( SigNumStr[indx].num == signum ) + return(SigNumStr[indx].str); + + return(NULL); +} + +struct actcodestr { + _PHNDLR code; + char *str; +}; + +struct actcodestr ActCodeStr[] = { + { SIG_DFL, "SIG_DFL" }, + { SIG_IGN, "SIG_IGN" }, + { SIG_DIE, "SIG_DIE" } +}; + +#define ACTCODESTR_SZ ( sizeof ActCodeStr / sizeof ActCodeStr[0] ) + +/* + * return string mnemonic for action code + */ +char * ActCodeToStr ( + _PHNDLR action + ) +{ + int indx; + + for ( indx = 0 ; indx < ACTCODESTR_SZ ; indx++ ) + if ( ActCodeStr[indx].code == action) + return(ActCodeStr[indx].str); + + return("FUNCTION ADDRESS"); +} + +/* + * print out exception-action table entry + */ +void prXcptActTabEntry ( + struct _XCPT_ACTION *pxcptact + ) +{ + printf("XcptNum = %s\n", XcptNumToStr(pxcptact->XcptNum)); + printf("SigNum = %s\n", SigNumToStr(pxcptact->SigNum)); + printf("XcptAction = %s\n", ActCodeToStr(pxcptact->XcptAction)); +} + +/* + * print out all entries in the exception-action table + */ +void prXcptActTab ( + void + ) +{ + int indx; + + for ( indx = 0 ; indx < _XcptActTabCount ; indx++ ) { + printf("\n_XcptActTab[%d] = \n", indx); + prXcptActTabEntry(&_XcptActTab[indx]); + } +} + +#endif /* DEBUG */ + +#endif /* _POSIX_ */ |