/*
 * @DEC_COPYRIGHT@
 */
/*
 * HISTORY
 * $Log:	excepthdr.h,v $
 * Revision 4.2.2.2  91/12/05  15:00:45  Jim_McHale
 * 	"Integrate with AG pool"
 * 
 * Revision 4.2.1.2  91/11/22  17:57:26  Jim_McHale
 * 	Merge with mips 3.0
 * 
 * Revision 4.2  91/09/20  05:07:50  devbld
 * 	Adding ODE Headers
 * 
 * $EndLog$
 */
/*
 *       @(#)$RCSfile: excepthdr.h,v $ $Revision: 4.2.2.2 $ (DEC) $Date: 91/12/05 15:00:45 $
 */
/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1991, 1990 MIPS Computer Systems, Inc.      |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
/* $Header: /usr/sde/osf1/rcs/src/./usr/include/PMAX/excepthdr.h,v 4.2.2.2 91/12/05 15:00:45 Jim_McHale Exp $ */
#ifndef _EXCEPTION_H
#define _EXCEPTION_H

#ifdef __lint
#include <sys/signal.h>	/* struct sigcontext defined so lint wont complain */
#endif
/*

This file contains information, data structures and constants for
the Mips exception handling facility

First, let's examine the requirements:
	- minimize cost at runtime until an exception is encountered.
	- handle exception from ada, pl1, iee and unix signals.

These requirements led us to providing a facility in the loader to
collect per-procedure exception information and frame information so
that we could easily unwind the stack at the point of exception.
Details follow.

The data structures involved are the runtime procedure table (runtime_pdr)
and the exception info structure (exception_info). A runtime_pdr table is
generated by the loader if the user accesses a variable called 
"_procedure_table" (akin to accessing _stext). "_procedure_table_size"
will contain the number of "_procedure_table" entries if it is used.
The loader will sort the runtime_pdr by the adr field.

See sym.h for a definition of the runtime_pdr.

The "exception_info" field is filled in by the loader for external procedures
with address of a global data variable with the same name as the procedure
and a suffix "_exception_info" (e.g. foo() and foo_exception_info). By
convention this address will contain an array of "exception_info" structures.

*/

#ifdef __LANGUAGE_C__
typedef struct exception_info {
	long exception;		/* exception identifier */
	void (*handler) ();	/* handler for exception */
	long data;		/* compile time data to pass to handler */
} EXIR, *pEXIR;
#endif

/*

The "exception" field will contain either a signal number or one of the
following constants (to be added to):

*/

#define EXC_END		0
#define EXC_BASE	1000000
#define EXC_ALL		(EXC_BASE+0)
#define EXC_ADA_USER	(EXC_BASE+1)
#define EXC_PL1_USER	(EXC_BASE+2)


/*

The array is terminated with an entry where the "exception field is either
EXI_END or EXI_ALL. EXI_ALL will say that "handler" will handle all
exceptions.

The data field will depend on the procedure. For example, in ADA the data
field will point at the frame table which the ADA handler will use to
further subdivide a procedure into exception scopes.

At runtime the following procedures will be provided in libexc.a:

*/

#ifdef __LANGUAGE_C__
void
set_unhandled_exception();

struct runtime_pdr *
find_rpd(long pc);

void
unwind(struct sigcontext *scp, struct runtime_pdr *prpd);

void
exception_dispatcher(long exception, long code, struct sigcontext *scp);

int
exc_resume(struct sigcontext *scp);

void
exc_setjmp(struct sigcontext *scp);

/*

Exception_default allows the user to set up a default handler in case
no one handles an excpetion sent to the exception_dispatcher. By
default this will be set up to be a routine that unsets the signal
(where applicable) and returns to initial spot of the exception. If
it is a signal, then the process should die with unhandled excption.

Find_rpd will do a binary search on the tabe pointed to by "_procedure_table"
and return a pointer to entry which it's pc argument falls into.

Unwind will take the sigcontext scp argument and virtually unwind by
changing the fields to reflect the next frame on the stack. A sigreturn
call can be called with this scp upon return and you'll return to
the frame unwind set up. The prpd argument is used as the the
procedure table entry, if it is null unwind will call find_rpd on
scp->sc_pc to get it.

Exception_dispatcher will be a generic exception handler which will
get the runtime_pdr and check through it's exception_info array for an
entry which matches it's exception argument. If an entry is found which
matches or contains EXI_ALL, then the entry's handler is called as
follows:
		handler(exception, code, ocp, scp, prpd, data)
		long	exception;
		long	code;
		struct	sigcontext *oscp;-- original sigcontext
		struct	sigcontext *scp; -- current sigcontext for this frame
		pRPDR	prpd;
		long	data;		 -- from exception record

[NOTE: If exception is SIGFPE, the scp argument has IEEE exception bits masked 
out of it sc_fpc_scr so that a handler that uses the scp to sigreturn won't 
get an immediate SIGFPE-- of course oscp has the correct sc_fpc_csr]

If no match is found or the handler returns, exception_dispatch will
unwind the frame and try the previous frame's exception array. If the
bottom of the stack is reached (pc == 0), then the default handler is called.

The handler can either return to exception_dispatcher (who'll treat that action
as the handler not really handling the error and try to find someone else
to handle it up the stack) or it can sigreturn (longjump) to wherever it
deems appropriate.

If a language support user exceptions, it can use the exception dispatcher
as well (assume ADA code):

user_code:
	...
	if whatever
		raise(my_exception)
	...

raise(exception)
{
	struct sigcontext sc;

	setjmp(&sc);		-- currently 4.3's setjmp
	unwind(&sc, 0);		-- get back to user_code's frame
	sc.sc_pc -= 8;		-- make it point at the call
	exception_dispatcher(EXI_ADA_USER, exception, &sc);
}

*/

/* the following are the declarations to access the procedure table and
 *	its size generated by the loader.
 */
extern char _procedure_table_size[];
extern char _procedure_string_table[];
#define PSIZE ((int) _procedure_table_size)
extern struct runtime_pdr _procedure_table[];

#define EXCEPTION_SUFFIX "_exception_info"
#endif

/* $Log:	excepthdr.h,v $
 * Revision 4.2.2.2  91/12/05  15:00:45  Jim_McHale
 * 	"Integrate with AG pool"
 * 
 * Revision 4.2.1.2  91/11/22  17:57:26  Jim_McHale
 * 	Merge with mips 3.0
 * 
 * Revision 3000.5.1.1  91/05/31  18:24:48  bettina
 * fix DFARS in copyright
 * 
 * Revision 3000.5  91/04/08  17:39:48  bettina
 * fix copyright
 * 
 * Revision 3000.4  91/04/08  13:52:38  bettina
 * update copyright
 * 
 * Revision 3000.3  91/03/13  18:50:07  karen
 * changed #ifdef __EXCEPTION_H to #ifdef _EXCEPTION_H
 * 
 * Revision 3000.2  90/12/10  13:52:13  zaineb
 * Ansi Changes
 * 
 * Revision 2020.2  90/03/12  17:03:13  bettina
 * 2.20 - add legend
 * 
 * Revision 2010.4  89/10/05  10:45:04  lai
 * added lint wrapper
 * 
 * Revision 2010.3  89/09/26  23:58:10  lai
 * added #include sys/signal.h
 * 
 * Revision 2010.2  89/09/26  23:37:48  lai
 * added wrapper
 * 
*/
#endif
