blob: db7c6cd683674177ef6d5d111bc6d5d6cbd4e854 [file] [log] [blame] [raw]
#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);
else
/*
* 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);
}