//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/***
*winxfltr.c - startup exception filter
*
*
*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.
*
*******************************************************************************/
#include <corecrt.h>
#include <excpt.h>
#include <signal.h>
#include <coredll.h>   // define debug zone information

/*
 * special code denoting no signal.
 */
#define NOSIG	-1

/*
 * global variable holding _PEXCEPTION_INFO_PTRS value
 */
void * _pxcptinfoptrs = NULL;

struct _XCPT_ACTION _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 _XcptActTabSize = sizeof _XcptActTab;

/*
 * number of entries in the exception-action table
 */
int _XcptActTabCount = (sizeof _XcptActTab)/sizeof(_XcptActTab[0]);


/*
 * function to look up the exception action table (_XcptActTab[]) corresponding
 * to the given exception
 */


static struct _XCPT_ACTION * xcptlookup(
    unsigned long
	);


#ifdef	DEBUG

/*
 * prototypes for debugging routines
 */
void prXcptActTabEntry(struct _XCPT_ACTION *);
void prXcptActTab(void);

#endif	/* DEBUG */

#ifdef _WIN32
/***
*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.
*
*	    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).
*
*	(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 _XcptFilter (
    unsigned long xcptnum,
    struct _EXCEPTION_POINTERS* pxcptinfoptrs
    )
{
	struct _XCPT_ACTION * pxcptact;
	_PHNDLR phandler;
	void *oldpxcptinfoptrs;
	/*
	 * first, determine if this exception needs to be passed on to the next
	 * higher exception handler. note that this includes any exception that
	 * is not recognized (i.e., is not in the table)
	 */
	if ( ((pxcptact = xcptlookup(xcptnum)) == NULL) ||
	     (pxcptact->XcptAction == SIG_DFL) ) {   
		/* 
		 * pass the buck to the next level exception handler
		 */
		return(UnhandledExceptionFilter(pxcptinfoptrs));
	}
#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
	 */

	(*phandler)(pxcptact->SigNum);

	/*
	 * restore the old value of _pxcptinfoptrs
	 */
#ifdef	_MT
	(*pptd)->_tpxcptinfoptrs = oldpxcptinfoptrs;
#else	/* not _MT */
	_pxcptinfoptrs = oldpxcptinfoptrs;
#endif	/* _MT */

	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	_MT

static struct _XCPT_ACTION * xcptlookup (
	unsigned long xcptnum,
	struct _XCPT_ACTION * pxcptacttab
	)

#else	/* not _MT */

static struct _XCPT_ACTION *  xcptlookup (
	unsigned long xcptnum
	)

#endif	/* _MT */

{
#ifdef	_MT
	struct _XCPT_ACTION *pxcptact = pxcptacttab;
#else	/* ndef _MT */
	struct _XCPT_ACTION *pxcptact = _XcptActTab;
#endif	/* _MT */

	/*
	 * walk thru the _xcptactab table looking for the proper entry
	 */
#ifdef	_MT

	while ( (pxcptact->XcptNum != xcptnum) && (++pxcptact <
	    pxcptacttab + _XcptActTabCount) ) ;

#else	/* not _MT */

	while ( (pxcptact->XcptNum != xcptnum) && (++pxcptact <
	    _XcptActTab + _XcptActTabCount) ) ;

#endif	/* _MT */

	/*
	 * if no table entry was found corresponding to xcptnum, return NULL
	 */
	if ( pxcptact->XcptNum != xcptnum )
		return(NULL);

	return(pxcptact);
}

#ifdef DEBUG
#if 0
#define STATUS_WAIT_0                    (0x00000000L)
#define STATUS_ABANDONED_WAIT_0          (0x00000080L)
#define STATUS_USER_APC                  (0x000000C0L)
#define STATUS_TIMEOUT                   (0x00000102L)
#define STATUS_PENDING                   (0x00000103L)
#define STATUS_GUARD_PAGE_VIOLATION      (0x80000001L)
#define STATUS_DATATYPE_MISALIGNMENT     (0x80000002L)
#define STATUS_BREAKPOINT                (0x80000003L)
#define STATUS_SINGLE_STEP               (0x80000004L)
#define STATUS_ACCESS_VIOLATION          (0xC0000005L)
#define STATUS_IN_PAGE_ERROR             (0xC0000006L)
#define STATUS_NO_MEMORY                 (0xC0000017L)
#define STATUS_ILLEGAL_INSTRUCTION       (0xC000001DL)
#define STATUS_NONCONTINUABLE_EXCEPTION  (0xC0000025L)
#define STATUS_INVALID_DISPOSITION       (0xC0000026L)
#define STATUS_ARRAY_BOUNDS_EXCEEDED     (0xC000008CL)
#define STATUS_FLOAT_DENORMAL_OPERAND    (0xC000008DL)
#define STATUS_FLOAT_DIVIDE_BY_ZERO      (0xC000008EL)
#define STATUS_FLOAT_INEXACT_RESULT      (0xC000008FL)
#define STATUS_FLOAT_INVALID_OPERATION   (0xC0000090L)
#define STATUS_FLOAT_OVERFLOW            (0xC0000091L)
#define STATUS_FLOAT_STACK_CHECK         (0xC0000092L)
#define STATUS_FLOAT_UNDERFLOW           (0xC0000093L)
#define STATUS_INTEGER_DIVIDE_BY_ZERO    (0xC0000094L)
#define STATUS_INTEGER_OVERFLOW          (0xC0000095L)
#define STATUS_PRIVILEGED_INSTRUCTION    (0xC0000096L)
#define STATUS_STACK_OVERFLOW            (0xC00000FDL)
#define STATUS_CONTROL_C_EXIT            (0xC000013AL)
#endif
/*
 * 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
	)
{

	DEBUGMSG(DBGEH,(TEXT("XcptNum    = %s\n"), XcptNumToStr(pxcptact->XcptNum)));
	DEBUGMSG(DBGEH,(TEXT("SigNum     = %s\n"), SigNumToStr(pxcptact->SigNum)));
	DEBUGMSG(DBGEH,(TEXT("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++ ) {
		DEBUGMSG(DBGEH,(TEXT("\n_XcptActTab[%d] = \n"), indx));
		prXcptActTabEntry(&_XcptActTab[indx]);
	}
}

#endif	/* DEBUG */

#endif /* DEBUG */



