/* --- Copyright University of Sussex 1994. All rights reserved. ----------
 * File:			C.win32/extern/src/exception.c
 * Purpose:			Exceptions (error signals)
 * Author:			Robert John Duncan, Jun 14 1994
 * Documentation:
 * Related Files:
 */

#include "popcore.h"


POP_SIGNAL_CONTEXT __pop_sigcontext;
	/* signal context communicated to "signal.p" */

DWORD __pop_fpe_handler;
	/* may be used in "afloat.s" for trapping FP exceptions */

#ifdef _X86_
#define SET_CONTEXT_IP(context, address) \
	(context)->Eip = (DWORD)address
#endif
	/* set the instruction pointer in a machine-specific PCONTEXT */

LONG pop_exception_filter(LPEXCEPTION_POINTERS exp)
	/*	Filters exceptions raised while Poplog is running: anything
		continuable is treated as a ``system error'' and passed to
		__pop_errsig. For compatibility with Unix & VMS systems, the
		various exception codes are mapped onto ``signal'' numbers which
		correspond to the events which Poplog expects; the signal names
		and numbers are based on the Unix ones, purely because of their
		familiarity.
	*/
{
	EXCEPTION_RECORD *exr = exp->ExceptionRecord;
	POP_SIGNAL_CONTEXT *psc = &__pop_sigcontext;

	if (exr->ExceptionFlags != 0)
		/*	non-continuable --- means something dreadful has happened:
			continuing the search will take us out to the post-mortem
			debugger */
		return EXCEPTION_CONTINUE_SEARCH;

	/* convert exception info to something Poplog will recognise */
	psc->ExceptionCode = exr->ExceptionCode;
	psc->ExceptionAddress = exr->ExceptionAddress;
	switch (exr->ExceptionCode)
	{
		case EXCEPTION_ACCESS_VIOLATION:
			psc->SignalNumber = POP_SIG_SEGV;
			if (exr->NumberParameters >= 2)
			{
				/* parameters are: read/write flag and bad address */
				psc->ReadWriteFlag = exr->ExceptionInformation[0];
				psc->FaultAddress = (PVOID)exr->ExceptionInformation[1];
			}
			break;

		case EXCEPTION_DATATYPE_MISALIGNMENT:
			psc->SignalNumber = POP_SIG_BUS;
			break;

		case EXCEPTION_ILLEGAL_INSTRUCTION:
		case EXCEPTION_PRIV_INSTRUCTION:
			psc->SignalNumber = POP_SIG_ILL;
			break;

		case EXCEPTION_FLT_DENORMAL_OPERAND:
		case EXCEPTION_FLT_DIVIDE_BY_ZERO:
		case EXCEPTION_FLT_INEXACT_RESULT:
		case EXCEPTION_FLT_INVALID_OPERATION:
		case EXCEPTION_FLT_OVERFLOW:
		case EXCEPTION_FLT_STACK_CHECK:
		case EXCEPTION_FLT_UNDERFLOW:
			if (__pop_fpe_handler != 0)
			{
				/*	as a special case we allow FP code to install an
					exception handler, although by default all exceptions
					should be disabled */
				SET_CONTEXT_IP(exp->ContextRecord, __pop_fpe_handler);
				__pop_fpe_handler = 0;
				return EXCEPTION_CONTINUE_EXECUTION;
			}
			psc->SignalNumber = POP_SIG_FPE;
			break;

		default:
			/* debugger trap, bounds check, etc. -- nothing interesting */
			psc->SignalNumber = POP_SIG_EXN;
			break;
	}

	/* return into _pop_errsig */
	SET_CONTEXT_IP(exp->ContextRecord, __pop_errsig);
	return EXCEPTION_CONTINUE_EXECUTION;
}
