669 lines
20 KiB
C
669 lines
20 KiB
C
/***
|
|
*winxfltr.c - startup exception filter
|
|
*
|
|
* Copyright (c) 1990-2001, 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-06-93 SKS Replace _CRTAPI* with __cdecl
|
|
* 04-19-93 SKS Move XcptActTabSize under MTHREAD switch
|
|
* 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.
|
|
* 07-28-93 GJF For SIGFPE, must reset the XcptAction field for all
|
|
* FPE entries to SIG_DFL before calling the user's
|
|
* handler.
|
|
* 09-06-94 CFW Replace MTHREAD with _MT.
|
|
* 08-16-96 GJF Fixed potential overrun of _XcptActTab. Also, detab-ed.
|
|
* 08-21-96 GJF Fixed _MT part of overrun fix.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#ifndef _POSIX_
|
|
|
|
#include <cruntime.h>
|
|
#include <float.h>
|
|
#include <mtdll.h>
|
|
#include <oscalls.h>
|
|
#include <signal.h>
|
|
#include <stddef.h>
|
|
|
|
|
|
/*
|
|
* special code denoting no signal.
|
|
*/
|
|
#define NOSIG -1
|
|
|
|
|
|
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 }
|
|
*/
|
|
};
|
|
|
|
/*
|
|
* WARNING!!!! The definition below amounts to defining that:
|
|
*
|
|
* XcptActTab[ _First_FPE_Indx ]
|
|
*
|
|
* is the very FIRST entry in the table corresponding to a floating point
|
|
* exception. Whenever the definition of the XcptActTab[] table is changed,
|
|
* this #define must be review to ensure correctness.
|
|
*/
|
|
int _First_FPE_Indx = 3;
|
|
|
|
/*
|
|
* There are _Num_FPE (currently, 7) entries in XcptActTab corresponding to
|
|
* floating point exceptions.
|
|
*/
|
|
int _Num_FPE = 7;
|
|
|
|
#ifdef _MT
|
|
|
|
/*
|
|
* size of the exception-action table (in bytes)
|
|
*/
|
|
int _XcptActTabSize = sizeof _XcptActTab;
|
|
|
|
#endif
|
|
|
|
/*
|
|
* number of entries in the exception-action table
|
|
*/
|
|
int _XcptActTabCount = (sizeof _XcptActTab)/sizeof(_XcptActTab[0]);
|
|
|
|
|
|
#ifdef _MT
|
|
|
|
/*
|
|
* 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 _fpecode = _FPE_EXPLICITGEN;
|
|
|
|
#define FPECODE _fpecode
|
|
|
|
/*
|
|
* global variable holding _PEXCEPTION_INFO_PTRS value
|
|
*/
|
|
void * _pxcptinfoptrs = NULL;
|
|
|
|
#define PXCPTINFOPTRS _pxcptinfoptrs
|
|
|
|
#endif /* _MT */
|
|
|
|
/*
|
|
* function to look up the exception action table (_XcptActTab[]) corresponding
|
|
* to the given exception
|
|
*/
|
|
|
|
#ifdef _MT
|
|
|
|
static struct _XCPT_ACTION * __cdecl xcptlookup(
|
|
unsigned long,
|
|
struct _XCPT_ACTION *
|
|
);
|
|
|
|
#else /* ndef _MT */
|
|
|
|
static struct _XCPT_ACTION * __cdecl xcptlookup(
|
|
unsigned long
|
|
);
|
|
|
|
#endif /* _MT */
|
|
|
|
#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 __cdecl _XcptFilter (
|
|
unsigned long xcptnum,
|
|
PEXCEPTION_POINTERS pxcptinfoptrs
|
|
)
|
|
{
|
|
struct _XCPT_ACTION * pxcptact;
|
|
_PHNDLR phandler;
|
|
void *oldpxcptinfoptrs;
|
|
int oldfpecode;
|
|
int indx;
|
|
|
|
#ifdef _MT
|
|
_ptiddata ptd = _getptd();
|
|
#endif /* _MT */
|
|
|
|
/*
|
|
* first, take care of all unrecognized exceptions and exceptions with
|
|
* XcptAction values of SIG_DFL.
|
|
*/
|
|
#ifdef _MT
|
|
if ( ((pxcptact = xcptlookup(xcptnum, ptd->_pxcptacttab)) == NULL)
|
|
|| (pxcptact->XcptAction == SIG_DFL) )
|
|
#else /* not _MT */
|
|
if ( ((pxcptact = xcptlookup(xcptnum)) == NULL) ||
|
|
(pxcptact->XcptAction == SIG_DFL) )
|
|
#endif /* _MT */
|
|
|
|
#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.
|
|
*/
|
|
phandler = pxcptact->XcptAction;
|
|
|
|
/*
|
|
* 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 ) {
|
|
|
|
/*
|
|
* reset the XcptAction field to the default for all entries
|
|
* corresponding to SIGFPE.
|
|
*/
|
|
for ( indx = _First_FPE_Indx ;
|
|
indx < _First_FPE_Indx + _Num_FPE ;
|
|
indx++ )
|
|
{
|
|
#ifdef _MT
|
|
( (struct _XCPT_ACTION *)(ptd->_pxcptacttab) +
|
|
indx )->XcptAction = SIG_DFL;
|
|
#else
|
|
_XcptActTab[indx].XcptAction = SIG_DFL;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* 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 code to support
|
|
* old MS-C programs whose SIGFPE handlers expect two args.
|
|
*
|
|
* NOTE: THE CAST AND CALL BELOW DEPEND ON __cdecl BEING
|
|
* CALLER CLEANUP!
|
|
*/
|
|
(*(void (__cdecl *)(int, int))phandler)(SIGFPE, FPECODE);
|
|
|
|
/*
|
|
* restore the old value of _fpecode
|
|
*/
|
|
FPECODE = oldfpecode;
|
|
}
|
|
else {
|
|
/*
|
|
* reset the XcptAction field to the default, then call the
|
|
* user-supplied handler
|
|
*/
|
|
pxcptact->XcptAction = SIG_DFL;
|
|
(*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 _MT
|
|
|
|
static struct _XCPT_ACTION * __cdecl xcptlookup (
|
|
unsigned long xcptnum,
|
|
struct _XCPT_ACTION * pxcptacttab
|
|
)
|
|
|
|
#else /* not _MT */
|
|
|
|
static struct _XCPT_ACTION * __cdecl 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
|
|
*/
|
|
#ifdef _MT
|
|
if ( (pxcptact >= pxcptacttab + _XcptActTabCount) ||
|
|
#else /* not _MT */
|
|
if ( (pxcptact >= _XcptActTab + _XcptActTabCount) ||
|
|
#endif /* _MT */
|
|
(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_ */
|