| #include "lock.h" |
| #include <stdio.h> |
| #include <signal.h> |
| #include <errno.h> |
| #include <windows.h> |
| |
| #define _lock(n) (0) |
| #define _unlock(n) (0) |
| #define MAX_TRIES 10 |
| |
| //void __cdecl _unlock(int); |
| static __p_sig_fn_t ctrlc_action = SIG_DFL; /* SIGINT */ |
| static __p_sig_fn_t ctrlbreak_action = SIG_DFL; /* SIGBREAK */ |
| static __p_sig_fn_t abort_action = SIG_DFL; /* SIGABRT */ |
| static __p_sig_fn_t term_action = SIG_DFL; /* SIGTERM */ |
| //static int ConsoleCtrlHandler_Installed = 0; |
| //extern void *g_hMainThread; |
| struct _XCPT_ACTION { |
| |
| /* |
| * exception code or number. defined by the host OS. |
| */ |
| unsigned long XcptNum; |
| |
| /* |
| * signal code or number. defined by the C runtime. |
| */ |
| int SignalNumber; |
| |
| /* |
| * exception action code. either a special code or the address of |
| * a handler function. always determines how the exception filter |
| * should dispose of the exception. |
| */ |
| __p_sig_fn_t XcptAction; |
| }; |
| //extern struct _XCPT_ACTION _XcptActTab[]; |
| static struct _XCPT_ACTION _XcptActTab[] = { |
| |
| /* |
| * Exceptions corresponding to the same signal (e.g., SIGFPE) must be grouped |
| * together. |
| * |
| * XcptNum SigNumber 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 } |
| */ |
| }; |
| static int _XcptActTabCount; |
| static void * _pxcptinfoptrs = NULL; |
| |
| #if 0 |
| static unsigned long int GetCurrentProcessOfThread(void *hThread) |
| { |
| PBYTE pData; |
| pData = (PBYTE)((DWORD)hThread & 0x1FFFFFFC) + 0x80000000; // (struct _HDATA)pData |
| pData = *(PBYTE*)(pData + 0x18); // pData == (struct Thread)pvObj |
| pData = *(PBYTE*)(pData + 0xC); // pData == (struct Process)pProc |
| pData = *(PBYTE*)(pData + 0x8); // pData == (HANDLE)hProc |
| return (DWORD)pData; |
| } |
| |
| static unsigned long int ControlCHandler() |
| { |
| unsigned long int *Stack; |
| CONTEXT ctx; |
| int tries; |
| |
| for(tries=0;tries<MAX_TRIES;tries++) |
| { |
| Sleep(1); |
| |
| ctx.ContextFlags = CONTEXT_FULL; |
| |
| if( -1 == SuspendThread((void *)GetCurrentThreadId())) |
| { |
| continue; |
| } |
| if((GetCurrentProcessId() != GetCurrentProcessOfThread((void *)GetCurrentThreadId())) ) |
| { |
| ResumeThread((void *)GetCurrentThreadId()); |
| continue; |
| } |
| if(!GetThreadContext((void *)GetCurrentThreadId(), &ctx)) |
| { |
| ResumeThread((void *)GetCurrentThreadId()); |
| continue; |
| } |
| break; |
| } |
| if(tries == MAX_TRIES) |
| { |
| return 0; |
| } |
| |
| SetThreadContext((void *)GetCurrentThreadId(), &ctx); |
| ResumeThread((void *)GetCurrentThreadId()); |
| |
| return 1; |
| } |
| |
| static int ctrlevent_capture(unsigned long int CtrlType) |
| { |
| |
| /* |
| * Identify the type of event and fetch the corresponding action |
| * description. |
| */ |
| |
| if((ctrlc_action != SIG_DFL) && (ctrlc_action != SIG_IGN) ) |
| { |
| _unlock(_SIGNAL_LOCK); |
| ControlCHandler(); |
| return 1; |
| } |
| |
| if ( ctrlc_action == SIG_DFL ) { |
| /* |
| * return false, indicating the event has NOT been handled |
| */ |
| _unlock(_SIGNAL_LOCK); |
| return 0; |
| } |
| |
| /* |
| * SIG_IGN - nothing special to do except release the lock |
| */ |
| _unlock(_SIGNAL_LOCK); |
| |
| /* |
| * Return true, indicating the event has been handled (which may |
| * mean it's being ignored) |
| */ |
| return 1; |
| } |
| #endif |
| |
| static struct _XCPT_ACTION * __cdecl siglookup(int sig) |
| { |
| struct _XCPT_ACTION *pxcptact = _XcptActTab; |
| |
| /* |
| * walk thru the _xcptactab table looking for the proper entry. note |
| * that in the case where more than one exception corresponds to the |
| * same signal, the first such instance in the table is the one |
| * returned. |
| */ |
| |
| while ( (pxcptact->SignalNumber != sig) && |
| (++pxcptact < _XcptActTab + _XcptActTabCount) ) ; |
| |
| |
| if ( (pxcptact < (_XcptActTab + _XcptActTabCount)) && |
| (pxcptact->SignalNumber == sig) ) |
| /* |
| * found a table entry corresponding to the signal |
| */ |
| return(pxcptact); |
| |
| /* |
| * found no table entry corresponding to the signal |
| */ |
| return(NULL); |
| } |
| |
| __p_sig_fn_t signal(int sig, __p_sig_fn_t act){ |
| struct _XCPT_ACTION *pxcptact; |
| __p_sig_fn_t oldsigact = 0; |
| |
| /* |
| * Check for values of sigact supported on other platforms but not |
| * on this one. Also, make sure sigact is not SIG_DIE |
| */ |
| if ( (act == SIG_ACK) || (act == SIG_SGE) ) |
| goto sigreterror; |
| |
| /* |
| * Take care of all signals which do not correspond to exceptions |
| * in the host OS. Those are: |
| * |
| * SIGINT |
| * SIGBREAK |
| * SIGABRT |
| * SIGTERM |
| * |
| */ |
| if ( (sig == SIGINT) || (sig == SIGBREAK) || (sig == SIGABRT) |
| || (sig == SIGTERM) ) { |
| |
| _lock(_SIGNAL_LOCK); |
| |
| /* |
| * if SIGINT or SIGBREAK, make sure the handler is installed |
| * to capture ^C and ^Break events. |
| */ |
| /* |
| if ( ((sig == SIGINT) || (sig == SIGBREAK)) && |
| !ConsoleCtrlHandler_Installed ) |
| if ( SetConsoleCtrlHandler(ctrlevent_capture(NULL), 1) == 1 ) ConsoleCtrlHandler_Installed = 1; |
| else { |
| _unlock(_SIGNAL_LOCK); |
| goto sigreterror; |
| } |
| */ |
| switch (sig) { |
| |
| case SIGINT: |
| oldsigact = ctrlc_action; |
| ctrlc_action = act; |
| break; |
| |
| case SIGBREAK: |
| oldsigact = ctrlbreak_action; |
| ctrlbreak_action = act; |
| break; |
| |
| case SIGABRT: |
| oldsigact = abort_action; |
| abort_action = act; |
| break; |
| |
| case SIGTERM: |
| oldsigact = term_action; |
| term_action = act; |
| break; |
| } |
| |
| _unlock(_SIGNAL_LOCK); |
| goto sigretok; |
| } |
| |
| /* |
| * If we reach here, SignalNumber is supposed to be one the signals which |
| * correspond to exceptions in the host OS. Those are: |
| * |
| * SIGFPE |
| * SIGILL |
| * SIGSEGV |
| */ |
| |
| /* |
| * Make sure SignalNumber is one of the remaining supported signals. |
| */ |
| if ( (sig != SIGFPE) && (sig != SIGILL) && (sig != SIGSEGV) ) |
| goto sigreterror; |
| |
| |
| /* |
| * look up the proper entry in the exception-action table. note that |
| * if several exceptions are mapped to the same signal, this returns |
| * the pointer to first such entry in the exception action table. it |
| * is assumed that the other entries immediately follow this one. |
| */ |
| if ( (pxcptact = siglookup(sig)) == NULL ) |
| goto sigreterror; |
| |
| /* |
| * SIGSEGV, SIGILL and SIGFPE all have more than one exception mapped |
| * to them. the code below depends on the exceptions corresponding to |
| * the same signal being grouped together in the exception-action |
| * table. |
| */ |
| |
| /* |
| * store old signal action code for return value |
| */ |
| oldsigact = pxcptact->XcptAction; |
| |
| /* |
| * loop through all entries corresponding to the |
| * given signal and update the SigAction and XcptAction |
| * fields as appropriate |
| */ |
| while ( pxcptact->SignalNumber == sig ) { |
| /* |
| * take care of the SIG_IGN and SIG_DFL action |
| * codes |
| */ |
| pxcptact->XcptAction = act; |
| |
| /* |
| * make sure we don't run off the end of the table |
| */ |
| if ( ++pxcptact >= (_XcptActTab + _XcptActTabCount) ) |
| break; |
| } |
| |
| sigretok: |
| return(oldsigact); |
| |
| sigreterror: |
| return(SIG_ERR); |
| } |
| |
| int raise(int sig) { |
| __p_sig_fn_t sigact; |
| __p_sig_fn_t *psigact; |
| PEXCEPTION_POINTERS oldpxcptinfoptrs; |
| |
| |
| switch (sig) { |
| |
| case SIGINT: |
| sigact = *(psigact = &ctrlc_action); |
| break; |
| |
| case SIGBREAK: |
| sigact = *(psigact = &ctrlbreak_action); |
| break; |
| |
| case SIGABRT: |
| sigact = *(psigact = &abort_action); |
| break; |
| |
| case SIGTERM: |
| sigact = *(psigact = &term_action); |
| break; |
| |
| case SIGFPE: |
| case SIGILL: |
| case SIGSEGV: |
| sigact = *(psigact = &(siglookup( sig )-> |
| XcptAction)); |
| break; |
| |
| default: |
| /* |
| * unsupported signal, return an error |
| */ |
| return (-1); |
| } |
| |
| |
| /* |
| * If the current action is SIG_IGN, just return |
| */ |
| if ( sigact == SIG_IGN ) { |
| return(0); |
| } |
| |
| /* |
| * If the current action is SIG_DFL, take the default action |
| */ |
| if ( sigact == SIG_DFL ) { |
| |
| /* |
| * The current default action for all of the supported |
| * signals is to terminate with an exit code of 3. |
| * |
| */ |
| _exit(3); |
| } |
| |
| /* |
| * From here on, sigact is assumed to be a pointer to a user-supplied |
| * handler. |
| */ |
| |
| /* |
| * For signals which correspond to exceptions, set the pointer |
| * to the EXCEPTION_POINTERS structure to NULL |
| */ |
| if ( (sig == SIGFPE) || (sig == SIGSEGV) || |
| (sig == SIGILL) ) { |
| oldpxcptinfoptrs = _pxcptinfoptrs; |
| _pxcptinfoptrs = NULL; |
| } |
| |
| /* |
| * Reset the action to SIG_DFL and call the user specified handler |
| * routine. |
| */ |
| (*sigact)(sig); |
| |
| /* |
| * For signals which correspond to exceptions, restore the pointer |
| * to the EXCEPTION_POINTERS structure. |
| */ |
| if ( (sig == SIGFPE) || (sig == SIGSEGV) || |
| (sig == SIGILL) ) { |
| _pxcptinfoptrs = oldpxcptinfoptrs; |
| /* |
| * If sig is SIGFPE, also restore _fpecode |
| */ |
| } |
| return(0); |
| } |