/*
	Trap handling
*/

/* $Header$ */

#include	<setjmp.h>

#include	<em_abs.h>
#include	"logging.h"
#include	"global.h"
#include	"log.h"
#include	"trap.h"
#include	"warn.h"
#include	"mem.h"
#include	"shadow.h"
#include	"linfil.h"
#include	"rsb.h"
#include	"fra.h"

extern char *sprintf();

extern jmp_buf trapbuf;			/* from main.c */

int must_test;				/* TEST-bit on in EM header word 2 */
int signalled;

PRIVATE int nonreturnable();

PRIVATE char *trap_msg[] = {
#include	"trap_msg"		/* generated from $(EM)/etc/traps */
	""
};

char *trap2text(nr)			/* transient */
	int nr;
{
	if (	/* trap number in predefined range */
		nr < sizeof (trap_msg) / sizeof (trap_msg[0])
	&&	/* trap message not the empty string */
		trap_msg[nr][0]
	) {
		return trap_msg[nr];
	}
	else {
		static char buf[50];

		sprintf(buf, "TRAP %d", nr);
		return buf;
	}
}

/*ARGSUSED*/
do_trap(nr, L, F)
	int nr;
	int L;
	char *F;
{
	/*
	1.	The trap has not been masked.
	2.	This routine does not return; it either ends in a call of
		fatal() or in a longjmp().
	*/
	static int rec_nr;		/* Recursive trap number */
	static int rec_trap = 0;	/* To detect traps inside do_trap() */
	
	register long tpi;		/* Trap Procedure Identifier */

	LOG(("@t1 trap(%d) [%s: %d]", nr, F, L));
	warning(WMSG + nr);

	switch (OnTrap) {
	case TR_ABORT:
		fatal("trap \"%s\" before program started", trap2text(nr));
		/*NOTREACHED*/

	case TR_HALT:
		fatal("trap \"%s\" not caught at %s",
				trap2text(nr), position());
		/*NOTREACHED*/

	case TR_TRAP:
		/* execute the trap */
		if (rec_trap) {
			fatal("recursive trap; first trap number was \"%s\"",
					trap2text(rec_nr));
		}
		rec_trap = 1;
		rec_nr = nr;

		/* save the Function Return Area */
		pushFRA(FRASize);
		npush((long)FRASize, wsize);
		npush((long)FRA_def, wsize);

		/* set up the trap number as the only parameter */
		npush((long) nr, wsize);

		tpi = TrapPI;		/* allowed since OnTrap == TR_TRAP */
		TrapPI = 0;
		OnTrap = TR_HALT;
		call(tpi, (nonreturnable(nr) ? RSB_NRT : RSB_RTT));
		rec_trap = 0;
		longjmp(trapbuf, 1);
		/*NOTREACHED*/
	}
}

PRIVATE int nonreturnable(nr)
	int nr;
{
	switch (nr) {
	case ESTACK:
	case EILLINS:
	case EODDZ:
	case ECASE:
	case EMEMFLT:
	case EBADPTR:
	case EBADPC:
	case EBADLAE:
	case EBADGTO:
		return 1;
	default:
		return 0;
	}
	/*NOTREACHED*/
}