aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/init.c')
-rw-r--r--gcc/ada/init.c2027
1 files changed, 2027 insertions, 0 deletions
diff --git a/gcc/ada/init.c b/gcc/ada/init.c
new file mode 100644
index 00000000000..77d0d6f967e
--- /dev/null
+++ b/gcc/ada/init.c
@@ -0,0 +1,2027 @@
+/****************************************************************************
+ * *
+ * GNAT COMPILER COMPONENTS *
+ * *
+ * I N I T *
+ * *
+ * $Revision: 1.1 $
+ * *
+ * C Implementation File *
+ * *
+ * Copyright (C) 1992-2001 Free Software Foundation, Inc. *
+ * *
+ * GNAT is free software; you can redistribute it and/or modify it under *
+ * terms of the GNU General Public License as published by the Free Soft- *
+ * ware Foundation; either version 2, or (at your option) any later ver- *
+ * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
+ * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
+ * for more details. You should have received a copy of the GNU General *
+ * Public License distributed with GNAT; see file COPYING. If not, write *
+ * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, *
+ * MA 02111-1307, USA. *
+ * *
+ * As a special exception, if you link this file with other files to *
+ * produce an executable, this file does not by itself cause the resulting *
+ * executable to be covered by the GNU General Public License. This except- *
+ * ion does not however invalidate any other reasons why the executable *
+ * file might be covered by the GNU Public License. *
+ * *
+ * GNAT was originally developed by the GNAT team at New York University. *
+ * It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). *
+ * *
+ ****************************************************************************/
+
+/* This unit contains initialization circuits that are system dependent. A
+ major part of the functionality involved involves stack overflow checking.
+ The GCC backend generates probe instructions to test for stack overflow.
+ For details on the exact approach used to generate these probes, see the
+ "Using and Porting GCC" manual, in particular the "Stack Checking" section
+ and the subsection "Specifying How Stack Checking is Done". The handlers
+ installed by this file are used to handle resulting signals that come
+ from these probes failing (i.e. touching protected pages) */
+
+/* The following include is here to meet the published VxWorks requirement
+ that the __vxworks header appear before any other include. */
+#ifdef __vxworks
+#include "vxWorks.h"
+#endif
+
+#ifdef IN_RTS
+#include "tconfig.h"
+#include "tsystem.h"
+#include <sys/stat.h>
+#else
+#include "config.h"
+#include "system.h"
+#endif
+
+#include "adaint.h"
+#include "raise.h"
+
+extern void __gnat_raise_program_error (const char *, int);
+
+/* Addresses of exception data blocks for predefined exceptions. */
+extern struct Exception_Data constraint_error;
+extern struct Exception_Data numeric_error;
+extern struct Exception_Data program_error;
+extern struct Exception_Data storage_error;
+extern struct Exception_Data tasking_error;
+extern struct Exception_Data _abort_signal;
+
+#define Lock_Task system__soft_links__lock_task
+extern void (*Lock_Task) PARAMS ((void));
+
+#define Unlock_Task system__soft_links__unlock_task
+extern void (*Unlock_Task) PARAMS ((void));
+
+#define Get_Machine_State_Addr \
+ system__soft_links__get_machine_state_addr
+extern struct Machine_State *(*Get_Machine_State_Addr) PARAMS ((void));
+
+#define Check_Abort_Status \
+ system__soft_links__check_abort_status
+extern int (*Check_Abort_Status) PARAMS ((void));
+
+#define Raise_From_Signal_Handler \
+ ada__exceptions__raise_from_signal_handler
+extern void Raise_From_Signal_Handler PARAMS ((struct Exception_Data *,
+ char *));
+
+#define Propagate_Signal_Exception \
+ __gnat_propagate_sig_exc
+extern void Propagate_Signal_Exception
+ PARAMS ((struct Machine_State *, struct Exception_Data *, char *));
+
+
+/* Copies of global values computed by the binder */
+int __gl_main_priority = -1;
+int __gl_time_slice_val = -1;
+char __gl_wc_encoding = 'n';
+char __gl_locking_policy = ' ';
+char __gl_queuing_policy = ' ';
+char __gl_task_dispatching_policy = ' ';
+int __gl_unreserve_all_interrupts = 0;
+int __gl_exception_tracebacks = 0;
+
+/* Indication of whether synchronous signal handler has already been
+ installed by a previous call to adainit */
+int __gnat_handler_installed = 0;
+
+/* HAVE_GNAT_INIT_FLOAT must be set on every targets where a __gnat_init_float
+ is defined. If this is not set them a void implementation will be defined
+ at the end of this unit. */
+#undef HAVE_GNAT_INIT_FLOAT
+
+/**********************/
+/* __gnat_set_globals */
+/**********************/
+
+/* This routine is called from the binder generated main program. It copies
+ the values for global quantities computed by the binder into the following
+ global locations. The reason that we go through this copy, rather than just
+ define the global locations in the binder generated file, is that they are
+ referenced from the runtime, which may be in a shared library, and the
+ binder file is not in the shared library. Global references across library
+ boundaries like this are not handled correctly in all systems. */
+
+void
+__gnat_set_globals (main_priority, time_slice_val, wc_encoding, locking_policy,
+ queuing_policy, task_dispatching_policy, adafinal_ptr,
+ unreserve_all_interrupts, exception_tracebacks)
+ int main_priority;
+ int time_slice_val;
+ int wc_encoding;
+ int locking_policy, queuing_policy, task_dispatching_policy;
+ void (*adafinal_ptr) PARAMS ((void)) ATTRIBUTE_UNUSED;
+ int unreserve_all_interrupts, exception_tracebacks;
+{
+ static int already_called = 0;
+
+ /* If this procedure has been already called once, check that the
+ arguments in this call are consistent with the ones in the previous
+ calls. Otherwise, raise a Program_Error exception.
+
+ We do not check for consistency of the wide character encoding
+ method. This default affects only Wide_Text_IO where no explicit
+ coding method is given, and there is no particular reason to let
+ this default be affected by the source representation of a library
+ in any case.
+
+ The value of main_priority is meaningful only when we are invoked
+ from the main program elaboration routine of an Ada application.
+ Checking the consistency of this parameter should therefore not be
+ done. Since it is assured that the main program elaboration will
+ always invoke this procedure before any library elaboration
+ routine, only the value of main_priority during the first call
+ should be taken into account and all the subsequent ones should be
+ ignored. Note that the case where the main program is not written
+ in Ada is also properly handled, since the default value will then
+ be used for this parameter.
+
+ For identical reasons, the consistency of time_slice_val should not
+ be checked. */
+
+ if (already_called)
+ {
+ if (__gl_locking_policy != locking_policy ||
+ __gl_queuing_policy != queuing_policy ||
+ __gl_task_dispatching_policy != task_dispatching_policy ||
+ __gl_unreserve_all_interrupts != unreserve_all_interrupts ||
+ __gl_exception_tracebacks != exception_tracebacks)
+ {
+ __gnat_raise_program_error (__FILE__, __LINE__);
+ }
+ return;
+ }
+ already_called = 1;
+
+ __gl_main_priority = main_priority;
+ __gl_time_slice_val = time_slice_val;
+ __gl_wc_encoding = wc_encoding;
+ __gl_locking_policy = locking_policy;
+ __gl_queuing_policy = queuing_policy;
+ __gl_task_dispatching_policy = task_dispatching_policy;
+ __gl_unreserve_all_interrupts = unreserve_all_interrupts;
+ __gl_exception_tracebacks = exception_tracebacks;
+}
+
+/*********************/
+/* __gnat_initialize */
+/*********************/
+
+/* __gnat_initialize is called at the start of execution of an Ada program
+ (the call is generated by the binder). The standard routine does nothing
+ at all; the intention is that this be replaced by system specific
+ code where initialization is required. */
+
+/***********************************/
+/* __gnat_initialize (AIX version) */
+/***********************************/
+
+#if defined (_AIX)
+
+/* AiX doesn't have SA_NODEFER */
+
+#define SA_NODEFER 0
+
+#include <sys/time.h>
+
+/* AiX doesn't have nanosleep, but provides nsleep instead */
+
+extern int nanosleep PARAMS ((struct timestruc_t *, struct timestruc_t *));
+static void __gnat_error_handler PARAMS ((int));
+
+int
+nanosleep (Rqtp, Rmtp)
+ struct timestruc_t *Rqtp, *Rmtp;
+{
+ return nsleep (Rqtp, Rmtp);
+}
+
+#include <signal.h>
+
+static void
+__gnat_error_handler (sig)
+ int sig;
+{
+ struct Exception_Data *exception;
+ char *msg;
+
+ switch (sig)
+ {
+ case SIGSEGV:
+ /* FIXME: we need to detect the case of a *real* SIGSEGV */
+ exception = &storage_error;
+ msg = "stack overflow or erroneous memory access";
+ break;
+
+ case SIGBUS:
+ exception = &constraint_error;
+ msg = "SIGBUS";
+ break;
+
+ case SIGFPE:
+ exception = &constraint_error;
+ msg = "SIGFPE";
+ break;
+
+ default:
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ Raise_From_Signal_Handler (exception, msg);
+}
+
+void
+__gnat_install_handler ()
+{
+ struct sigaction act;
+
+ /* Set up signal handler to map synchronous signals to appropriate
+ exceptions. Make sure that the handler isn't interrupted by another
+ signal that might cause a scheduling event! */
+
+ act.sa_handler = __gnat_error_handler;
+ act.sa_flags = SA_NODEFER | SA_RESTART;
+ (void) sigemptyset (&act.sa_mask);
+
+ (void) sigaction (SIGABRT, &act, NULL);
+ (void) sigaction (SIGFPE, &act, NULL);
+
+ if (__gl_unreserve_all_interrupts == 0)
+ {
+ (void) sigaction (SIGILL, &act, NULL);
+ (void) sigaction (SIGSEGV, &act, NULL);
+ (void) sigaction (SIGBUS, &act, NULL);
+ }
+ __gnat_handler_installed = 1;
+}
+
+void
+__gnat_initialize ()
+{
+}
+
+/****************************************/
+/* __gnat_initialize (Dec Unix version) */
+/****************************************/
+
+#elif defined(__alpha__) && defined(__osf__) && ! defined(__alpha_vxworks)
+
+/* Note: it seems that __osf__ is defined for the Alpha VXWorks case. Not
+ clear that this is reasonable, but in any case we have to be sure to
+ exclude this case in the above test. */
+
+#include <signal.h>
+#include <sys/siginfo.h>
+
+static void __gnat_error_handler PARAMS ((int, siginfo_t *,
+ struct sigcontext *));
+extern char *__gnat_get_code_loc PARAMS ((struct sigcontext *));
+extern void __gnat_enter_handler PARAMS ((struct sigcontext *, char *));
+extern size_t __gnat_machine_state_length PARAMS ((void));
+
+extern long exc_lookup_gp PARAMS ((char *));
+extern void exc_resume PARAMS ((struct sigcontext *));
+
+static void
+__gnat_error_handler (sig, sip, context)
+ int sig;
+ siginfo_t *sip;
+ struct sigcontext *context;
+{
+ struct Exception_Data *exception;
+ static int recurse = 0;
+ struct sigcontext *mstate;
+ const char *msg;
+
+ /* If this was an explicit signal from a "kill", just resignal it. */
+ if (SI_FROMUSER (sip))
+ {
+ signal (sig, SIG_DFL);
+ kill (getpid(), sig);
+ }
+
+ /* Otherwise, treat it as something we handle. */
+ switch (sig)
+ {
+ case SIGSEGV:
+ /* If the problem was permissions, this is a constraint error.
+ Likewise if the failing address isn't maximally aligned or if
+ we've recursed.
+
+ ??? Using a static variable here isn't task-safe, but it's
+ much too hard to do anything else and we're just determining
+ which exception to raise. */
+ if (sip->si_code == SEGV_ACCERR
+ || (((long) sip->si_addr) & 3) != 0
+ || recurse)
+ {
+ exception = &constraint_error;
+ msg = "SIGSEGV";
+ }
+ else
+ {
+ /* See if the page before the faulting page is accessable. Do that
+ by trying to access it. We'd like to simply try to access
+ 4096 + the faulting address, but it's not guaranteed to be
+ the actual address, just to be on the same page. */
+ recurse++;
+ ((volatile char *)
+ ((long) sip->si_addr & - getpagesize ()))[getpagesize ()];
+ msg = "stack overflow (or erroneous memory access)";
+ exception = &storage_error;
+ }
+ break;
+
+ case SIGBUS:
+ exception = &program_error;
+ msg = "SIGBUS";
+ break;
+
+ case SIGFPE:
+ exception = &constraint_error;
+ msg = "SIGFPE";
+ break;
+
+ default:
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ recurse = 0;
+ mstate = (struct sigcontext *) (*Get_Machine_State_Addr) ();
+ if (mstate != 0)
+ *mstate = *context;
+
+ Raise_From_Signal_Handler (exception, (char *) msg);
+}
+
+void
+__gnat_install_handler ()
+{
+ struct sigaction act;
+
+ /* Setup signal handler to map synchronous signals to appropriate
+ exceptions. Make sure that the handler isn't interrupted by another
+ signal that might cause a scheduling event! */
+
+ act.sa_handler = (void (*) PARAMS ((int))) __gnat_error_handler;
+ act.sa_flags = SA_ONSTACK | SA_RESTART | SA_NODEFER | SA_SIGINFO;
+ (void) sigemptyset (&act.sa_mask);
+
+ (void) sigaction (SIGABRT, &act, NULL);
+ (void) sigaction (SIGFPE, &act, NULL);
+
+ if (__gl_unreserve_all_interrupts == 0)
+ {
+ (void) sigaction (SIGILL, &act, NULL);
+ (void) sigaction (SIGSEGV, &act, NULL);
+ (void) sigaction (SIGBUS, &act, NULL);
+ }
+
+ __gnat_handler_installed = 1;
+}
+
+void
+__gnat_initialize ()
+{
+}
+
+/* Routines called by 5amastop.adb. */
+
+#define SC_GP 29
+
+char *
+__gnat_get_code_loc (context)
+ struct sigcontext *context;
+{
+ return (char *) context->sc_pc;
+}
+
+void
+__gnat_enter_handler (context, pc)
+ struct sigcontext *context;
+ char *pc;
+{
+ context->sc_pc = (long) pc;
+ context->sc_regs[SC_GP] = exc_lookup_gp (pc);
+ exc_resume (context);
+}
+
+size_t
+__gnat_machine_state_length ()
+{
+ return sizeof (struct sigcontext);
+}
+
+/***********************************/
+/* __gnat_initialize (HPUX version) */
+/***********************************/
+
+#elif defined (hpux)
+
+#include <signal.h>
+
+static void __gnat_error_handler PARAMS ((int));
+
+static void
+__gnat_error_handler (sig)
+ int sig;
+{
+ struct Exception_Data *exception;
+ char *msg;
+
+ switch (sig)
+ {
+ case SIGSEGV:
+ /* FIXME: we need to detect the case of a *real* SIGSEGV */
+ exception = &storage_error;
+ msg = "stack overflow or erroneous memory access";
+ break;
+
+ case SIGBUS:
+ exception = &constraint_error;
+ msg = "SIGBUS";
+ break;
+
+ case SIGFPE:
+ exception = &constraint_error;
+ msg = "SIGFPE";
+ break;
+
+ default:
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ Raise_From_Signal_Handler (exception, msg);
+}
+
+void
+__gnat_install_handler ()
+{
+ struct sigaction act;
+
+ /* Set up signal handler to map synchronous signals to appropriate
+ exceptions. Make sure that the handler isn't interrupted by another
+ signal that might cause a scheduling event! Also setup an alternate
+ stack region for the handler execution so that stack overflows can be
+ handled properly, avoiding a SEGV generation from stack usage by the
+ handler itself. */
+
+ static char handler_stack [SIGSTKSZ];
+
+ stack_t stack;
+
+ stack.ss_sp = handler_stack;
+ stack.ss_size = SIGSTKSZ;
+ stack.ss_flags = 0;
+
+ (void) sigaltstack (&stack, NULL);
+
+ act.sa_handler = __gnat_error_handler;
+ act.sa_flags = SA_NODEFER | SA_RESTART | SA_ONSTACK;
+ (void) sigemptyset (&act.sa_mask);
+
+ (void) sigaction (SIGABRT, &act, NULL);
+ (void) sigaction (SIGFPE, &act, NULL);
+
+ if (__gl_unreserve_all_interrupts == 0)
+ {
+ (void) sigaction (SIGILL, &act, NULL);
+ (void) sigaction (SIGSEGV, &act, NULL);
+ (void) sigaction (SIGBUS, &act, NULL);
+ }
+ __gnat_handler_installed = 1;
+}
+
+void
+__gnat_initialize ()
+{
+}
+
+
+/*************************************/
+/* __gnat_initialize (Linux version) */
+/*************************************/
+
+#elif defined (linux) && defined (i386) && !defined (__RT__)
+
+#include <signal.h>
+#include <asm/sigcontext.h>
+
+/* Linux with GNU libc does not define NULL in included header files */
+
+#if !defined (NULL)
+#define NULL ((void *) 0)
+#endif
+
+struct Machine_State
+{
+ unsigned long eip;
+ unsigned long ebx;
+ unsigned long esp;
+ unsigned long ebp;
+ unsigned long esi;
+ unsigned long edi;
+};
+
+static void __gnat_error_handler PARAMS ((int));
+
+static void
+__gnat_error_handler (sig)
+ int sig;
+{
+ struct Exception_Data *exception;
+ char *msg;
+ static int recurse = 0;
+
+ struct sigcontext *info
+ = (struct sigcontext *) (((char *) &sig) + sizeof (int));
+ /* Linux does not document how to get the machine state in a signal handler,
+ but in fact the necessary data is in a sigcontext_struct value that is
+ on the stack immediately above the signal number parameter, and the
+ above messing accesses this value on the stack. */
+
+ struct Machine_State *mstate;
+
+ switch (sig)
+ {
+ case SIGSEGV:
+ /* If the problem was permissions, this is a constraint error.
+ Likewise if the failing address isn't maximally aligned or if
+ we've recursed.
+
+ ??? Using a static variable here isn't task-safe, but it's
+ much too hard to do anything else and we're just determining
+ which exception to raise. */
+ if (recurse)
+ {
+ exception = &constraint_error;
+ msg = "SIGSEGV";
+ }
+ else
+ {
+ /* Here we would like a discrimination test to see whether the
+ page before the faulting address is accessible. Unfortunately
+ Linux seems to have no way of giving us the faulting address.
+
+ In versions of a-init.c before 1.95, we had a test of the page
+ before the stack pointer using:
+
+ recurse++;
+ ((volatile char *)
+ ((long) info->esp_at_signal & - getpagesize ()))[getpagesize ()];
+
+ but that's wrong, since it tests the stack pointer location, and
+ the current stack probe code does not move the stack pointer
+ until all probes succeed.
+
+ For now we simply do not attempt any discrimination at all. Note
+ that this is quite acceptable, since a "real" SIGSEGV can only
+ occur as the result of an erroneous program */
+
+ msg = "stack overflow (or erroneous memory access)";
+ exception = &storage_error;
+ }
+ break;
+
+ case SIGBUS:
+ exception = &constraint_error;
+ msg = "SIGBUS";
+ break;
+
+ case SIGFPE:
+ exception = &constraint_error;
+ msg = "SIGFPE";
+ break;
+
+ default:
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ mstate = (*Get_Machine_State_Addr)();
+ if (mstate)
+ {
+ mstate->eip = info->eip;
+ mstate->ebx = info->ebx;
+ mstate->esp = info->esp_at_signal;
+ mstate->ebp = info->ebp;
+ mstate->esi = info->esi;
+ mstate->edi = info->edi;
+ }
+
+ recurse = 0;
+ Raise_From_Signal_Handler (exception, msg);
+}
+
+void
+__gnat_install_handler ()
+{
+ struct sigaction act;
+
+ /* Set up signal handler to map synchronous signals to appropriate
+ exceptions. Make sure that the handler isn't interrupted by another
+ signal that might cause a scheduling event! */
+
+ act.sa_handler = __gnat_error_handler;
+ act.sa_flags = SA_NODEFER | SA_RESTART;
+ (void) sigemptyset (&act.sa_mask);
+
+ (void) sigaction (SIGABRT, &act, NULL);
+ (void) sigaction (SIGFPE, &act, NULL);
+
+ if (__gl_unreserve_all_interrupts == 0)
+ {
+ (void) sigaction (SIGILL, &act, NULL);
+ (void) sigaction (SIGSEGV, &act, NULL);
+ (void) sigaction (SIGBUS, &act, NULL);
+ }
+ __gnat_handler_installed = 1;
+}
+
+void
+__gnat_initialize ()
+{
+}
+
+/******************************************/
+/* __gnat_initialize (NT-mingw32 version) */
+/******************************************/
+
+#elif defined (__MINGW32__)
+#include <windows.h>
+
+static LONG __gnat_error_handler PARAMS ((PEXCEPTION_POINTERS));
+
+/* __gnat_initialize (mingw32). */
+
+static LONG
+__gnat_error_handler (info)
+ PEXCEPTION_POINTERS info;
+{
+ static int recurse;
+ struct Exception_Data *exception;
+ char *msg;
+
+ switch (info->ExceptionRecord->ExceptionCode)
+ {
+ case EXCEPTION_ACCESS_VIOLATION:
+ /* If the failing address isn't maximally-aligned or if we've
+ recursed, this is a program error. */
+ if ((info->ExceptionRecord->ExceptionInformation[1] & 3) != 0
+ || recurse)
+ {
+ exception = &program_error;
+ msg = "EXCEPTION_ACCESS_VIOLATION";
+ }
+ else
+ {
+ /* See if the page before the faulting page is accessable. Do that
+ by trying to access it. */
+ recurse++;
+ * ((volatile char *) (info->ExceptionRecord->ExceptionInformation[1]
+ + 4096));
+ exception = &storage_error;
+ msg = "stack overflow (or erroneous memory access)";
+ }
+ break;
+
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ exception = &constraint_error;
+ msg = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
+ break;
+
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ exception = &constraint_error;
+ msg = "EXCEPTION_DATATYPE_MISALIGNMENT";
+ break;
+
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ exception = &constraint_error;
+ msg = "EXCEPTION_FLT_DENORMAL_OPERAND";
+ break;
+
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ exception = &constraint_error;
+ msg = "EXCEPTION_FLT_DENORMAL_OPERAND";
+ break;
+
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ exception = &constraint_error;
+ msg = "EXCEPTION_FLT_INVALID_OPERATION";
+ break;
+
+ case EXCEPTION_FLT_OVERFLOW:
+ exception = &constraint_error;
+ msg = "EXCEPTION_FLT_OVERFLOW";
+ break;
+
+ case EXCEPTION_FLT_STACK_CHECK:
+ exception = &program_error;
+ msg = "EXCEPTION_FLT_STACK_CHECK";
+ break;
+
+ case EXCEPTION_FLT_UNDERFLOW:
+ exception = &constraint_error;
+ msg = "EXCEPTION_FLT_UNDERFLOW";
+ break;
+
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ exception = &constraint_error;
+ msg = "EXCEPTION_INT_DIVIDE_BY_ZERO";
+ break;
+
+ case EXCEPTION_INT_OVERFLOW:
+ exception = &constraint_error;
+ msg = "EXCEPTION_INT_OVERFLOW";
+ break;
+
+ case EXCEPTION_INVALID_DISPOSITION:
+ exception = &program_error;
+ msg = "EXCEPTION_INVALID_DISPOSITION";
+ break;
+
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ exception = &program_error;
+ msg = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
+ break;
+
+ case EXCEPTION_PRIV_INSTRUCTION:
+ exception = &program_error;
+ msg = "EXCEPTION_PRIV_INSTRUCTION";
+ break;
+
+ case EXCEPTION_SINGLE_STEP:
+ exception = &program_error;
+ msg = "EXCEPTION_SINGLE_STEP";
+ break;
+
+ case EXCEPTION_STACK_OVERFLOW:
+ exception = &storage_error;
+ msg = "EXCEPTION_STACK_OVERFLOW";
+ break;
+
+ default:
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ recurse = 0;
+ Raise_From_Signal_Handler (exception, msg);
+}
+
+void
+__gnat_install_handler ()
+{
+ SetUnhandledExceptionFilter (__gnat_error_handler);
+ __gnat_handler_installed = 1;
+}
+
+void
+__gnat_initialize ()
+{
+
+ /* Initialize floating-point coprocessor. This call is needed because
+ the MS libraries default to 64-bit precision instead of 80-bit
+ precision, and we require the full precision for proper operation,
+ given that we have set Max_Digits etc with this in mind */
+
+ __gnat_init_float ();
+
+ /* initialize a lock for a process handle list - see a-adaint.c for the
+ implementation of __gnat_portable_no_block_spawn, __gnat_portable_wait */
+ __gnat_plist_init();
+}
+
+/**************************************/
+/* __gnat_initialize (Interix version) */
+/**************************************/
+
+#elif defined (__INTERIX)
+
+#include <signal.h>
+
+static void __gnat_error_handler PARAMS ((int));
+
+static void
+__gnat_error_handler (sig)
+ int sig;
+{
+ struct Exception_Data *exception;
+ char *msg;
+
+ switch (sig)
+ {
+ case SIGSEGV:
+ exception = &storage_error;
+ msg = "stack overflow or erroneous memory access";
+ break;
+
+ case SIGBUS:
+ exception = &constraint_error;
+ msg = "SIGBUS";
+ break;
+
+ case SIGFPE:
+ exception = &constraint_error;
+ msg = "SIGFPE";
+ break;
+
+ default:
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ Raise_From_Signal_Handler (exception, msg);
+}
+
+void
+__gnat_install_handler ()
+{
+ struct sigaction act;
+
+ /* Set up signal handler to map synchronous signals to appropriate
+ exceptions. Make sure that the handler isn't interrupted by another
+ signal that might cause a scheduling event! */
+
+ act.sa_handler = __gnat_error_handler;
+ act.sa_flags = 0;
+ (void) sigemptyset (&act.sa_mask);
+
+ /* Handlers for signals besides SIGSEGV cause c974013 to hang */
+/* (void) sigaction (SIGILL, &act, NULL); */
+/* (void) sigaction (SIGABRT, &act, NULL); */
+/* (void) sigaction (SIGFPE, &act, NULL); */
+/* (void) sigaction (SIGBUS, &act, NULL); */
+ if (__gl_unreserve_all_interrupts == 0)
+ {
+ (void) sigaction (SIGSEGV, &act, NULL);
+ }
+ __gnat_handler_installed = 1;
+}
+
+void
+__gnat_initialize ()
+{
+ __gnat_init_float ();
+}
+
+/**************************************/
+/* __gnat_initialize (LynxOS version) */
+/**************************************/
+
+#elif defined (__Lynx__)
+
+void
+__gnat_initialize ()
+{
+ __gnat_init_float ();
+}
+
+/*********************************/
+/* __gnat_install_handler (Lynx) */
+/*********************************/
+
+void
+__gnat_install_handler ()
+{
+ __gnat_handler_installed = 1;
+}
+
+/****************************/
+/* __gnat_initialize (OS/2) */
+/****************************/
+
+#elif defined (__EMX__) /* OS/2 dependent initialization */
+
+void
+__gnat_initialize ()
+{
+}
+
+/*********************************/
+/* __gnat_install_handler (OS/2) */
+/*********************************/
+
+void
+__gnat_install_handler ()
+{
+ __gnat_handler_installed = 1;
+}
+
+/***********************************/
+/* __gnat_initialize (SGI version) */
+/***********************************/
+
+#elif defined (sgi)
+
+#include <signal.h>
+#include <siginfo.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define SIGADAABORT 48
+#define SIGNAL_STACK_SIZE 4096
+#define SIGNAL_STACK_ALIGNMENT 64
+
+struct Machine_State
+{
+ sigcontext_t context;
+};
+
+static void __gnat_error_handler PARAMS ((int, int, sigcontext_t *));
+
+static void
+__gnat_error_handler (sig, code, sc)
+ int sig;
+ int code;
+ sigcontext_t *sc;
+{
+ struct Machine_State *mstate;
+ struct Exception_Data *exception;
+ char *msg;
+
+ int i;
+
+ switch (sig)
+ {
+ case SIGSEGV:
+ if (code == EFAULT)
+ {
+ exception = &program_error;
+ msg = "SIGSEGV: (Invalid virtual address)";
+ }
+ else if (code == ENXIO)
+ {
+ exception = &program_error;
+ msg = "SIGSEGV: (Read beyond mapped object)";
+ }
+ else if (code == ENOSPC)
+ {
+ exception = &program_error; /* ??? storage_error ??? */
+ msg = "SIGSEGV: (Autogrow for file failed)";
+ }
+ else if (code == EACCES)
+ {
+ /* ??? Re-add smarts to further verify that we launched
+ the stack into a guard page, not an attempt to
+ write to .text or something */
+ exception = &storage_error;
+ msg = "SIGSEGV: (stack overflow or erroneous memory access)";
+ }
+ else
+ {
+ /* Just in case the OS guys did it to us again. Sometimes
+ they fail to document all of the valid codes that are
+ passed to signal handlers, just in case someone depends
+ on knowing all the codes */
+ exception = &program_error;
+ msg = "SIGSEGV: (Undocumented reason)";
+ }
+ break;
+
+ case SIGBUS:
+ /* Map all bus errors to Program_Error. */
+ exception = &program_error;
+ msg = "SIGBUS";
+ break;
+
+ case SIGFPE:
+ /* Map all fpe errors to Constraint_Error. */
+ exception = &constraint_error;
+ msg = "SIGFPE";
+ break;
+
+ case SIGADAABORT:
+ if ((*Check_Abort_Status) ())
+ {
+ exception = &_abort_signal;
+ msg = "";
+ }
+ else
+ return;
+
+ break;
+
+ default:
+ /* Everything else is a Program_Error. */
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ mstate = (*Get_Machine_State_Addr)();
+ if (mstate != 0)
+ memcpy ((void *) mstate, (const void *) sc, sizeof (sigcontext_t));
+
+ Raise_From_Signal_Handler (exception, msg);
+
+}
+
+void
+__gnat_install_handler ()
+{
+ stack_t ss;
+ struct sigaction act;
+
+ /* Setup signal handler to map synchronous signals to appropriate
+ exceptions. Make sure that the handler isn't interrupted by another
+ signal that might cause a scheduling event! */
+
+ act.sa_handler = __gnat_error_handler;
+ act.sa_flags = SA_NODEFER + SA_RESTART;
+ (void) sigfillset (&act.sa_mask);
+ (void) sigemptyset (&act.sa_mask);
+
+ (void) sigaction (SIGABRT, &act, NULL);
+ (void) sigaction (SIGFPE, &act, NULL);
+
+ if (__gl_unreserve_all_interrupts == 0)
+ {
+ (void) sigaction (SIGILL, &act, NULL);
+ (void) sigaction (SIGSEGV, &act, NULL);
+ (void) sigaction (SIGBUS, &act, NULL);
+ }
+ (void) sigaction (SIGADAABORT, &act, NULL);
+ __gnat_handler_installed = 1;
+}
+
+void
+__gnat_initialize ()
+{
+}
+
+/*************************************************/
+/* __gnat_initialize (Solaris and SunOS version) */
+/*************************************************/
+
+#elif defined (sun) && defined (__SVR4) && !defined (__vxworks)
+
+#include <signal.h>
+#include <siginfo.h>
+
+static void __gnat_error_handler PARAMS ((int, siginfo_t *));
+
+static void
+__gnat_error_handler (sig, sip)
+ int sig;
+ siginfo_t *sip;
+{
+ struct Exception_Data *exception;
+ static int recurse = 0;
+ char *msg;
+
+ /* If this was an explicit signal from a "kill", just resignal it. */
+ if (SI_FROMUSER (sip))
+ {
+ signal (sig, SIG_DFL);
+ kill (getpid(), sig);
+ }
+
+ /* Otherwise, treat it as something we handle. */
+ switch (sig)
+ {
+ case SIGSEGV:
+ /* If the problem was permissions, this is a constraint error.
+ Likewise if the failing address isn't maximally aligned or if
+ we've recursed.
+
+ ??? Using a static variable here isn't task-safe, but it's
+ much too hard to do anything else and we're just determining
+ which exception to raise. */
+ if (sip->si_code == SEGV_ACCERR
+ || (((long) sip->si_addr) & 3) != 0
+ || recurse)
+ {
+ exception = &constraint_error;
+ msg = "SIGSEGV";
+ }
+ else
+ {
+ /* See if the page before the faulting page is accessable. Do that
+ by trying to access it. We'd like to simply try to access
+ 4096 + the faulting address, but it's not guaranteed to be
+ the actual address, just to be on the same page. */
+ recurse++;
+ ((volatile char *)
+ ((long) sip->si_addr & - getpagesize ()))[getpagesize ()];
+ exception = &storage_error;
+ msg = "stack overflow (or erroneous memory access)";
+ }
+ break;
+
+ case SIGBUS:
+ exception = &program_error;
+ msg = "SIGBUS";
+ break;
+
+ case SIGFPE:
+ exception = &constraint_error;
+ msg = "SIGFPE";
+ break;
+
+ default:
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ recurse = 0;
+
+ Raise_From_Signal_Handler (exception, msg);
+}
+
+void
+__gnat_install_handler ()
+{
+ struct sigaction act;
+
+ /* Set up signal handler to map synchronous signals to appropriate
+ exceptions. Make sure that the handler isn't interrupted by another
+ signal that might cause a scheduling event! */
+
+ act.sa_handler = __gnat_error_handler;
+ act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
+ (void) sigemptyset (&act.sa_mask);
+
+ (void) sigaction (SIGABRT, &act, NULL);
+
+ if (__gl_unreserve_all_interrupts == 0)
+ {
+ (void) sigaction (SIGFPE, &act, NULL);
+ (void) sigaction (SIGSEGV, &act, NULL);
+ (void) sigaction (SIGBUS, &act, NULL);
+ }
+ __gnat_handler_installed = 1;
+}
+
+void
+__gnat_initialize ()
+{
+}
+
+/***********************************/
+/* __gnat_initialize (SNI version) */
+/***********************************/
+
+#elif defined (__sni__)
+
+/* SNI needs special defines and includes */
+
+#define _XOPEN_SOURCE
+#define _POSIX_SOURCE
+#include <signal.h>
+
+extern size_t __gnat_getpagesize PARAMS ((void));
+static void __gnat_error_handler PARAMS ((int));
+
+/* The run time needs this function which is a #define in SNI */
+
+size_t
+__gnat_getpagesize ()
+{
+ return getpagesize ();
+}
+
+static void
+__gnat_error_handler (sig)
+ int sig;
+{
+ struct Exception_Data *exception;
+ char *msg;
+
+ switch (sig)
+ {
+ case SIGSEGV:
+ /* FIXME: we need to detect the case of a *real* SIGSEGV */
+ exception = &storage_error;
+ msg = "stack overflow or erroneous memory access";
+ break;
+
+ case SIGBUS:
+ exception = &constraint_error;
+ msg = "SIGBUS";
+ break;
+
+ case SIGFPE:
+ exception = &constraint_error;
+ msg = "SIGFPE";
+ break;
+
+ default:
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ Raise_From_Signal_Handler (exception, msg);
+}
+
+void
+__gnat_install_handler ()
+{
+ struct sigaction act;
+
+ /* Set up signal handler to map synchronous signals to appropriate
+ exceptions. Make sure that the handler isn't interrupted by another
+ signal that might cause a scheduling event! */
+
+ act.sa_handler = __gnat_error_handler;
+ act.sa_flags = SA_NODEFER | SA_RESTART;
+ (void) sigemptyset (&act.sa_mask);
+
+ (void) sigaction (SIGABRT, &act, NULL);
+ (void) sigaction (SIGFPE, &act, NULL);
+
+ if (__gl_unreserve_all_interrupts == 0)
+ {
+ (void) sigaction (SIGILL, &act, NULL);
+ (void) sigaction (SIGSEGV, &act, NULL);
+ (void) sigaction (SIGBUS, &act, NULL);
+ }
+ __gnat_handler_installed = 1;
+}
+
+void
+__gnat_initialize ()
+{
+}
+
+/***********************************/
+/* __gnat_initialize (VMS version) */
+/***********************************/
+
+#elif defined (VMS)
+
+/* The prehandler actually gets control first on a condition. It swaps the
+ stack pointer and calls the handler (__gnat_error_handler). */
+extern long __gnat_error_prehandler ();
+
+extern char *__gnat_error_prehandler_stack; /* Alternate signal stack */
+
+/* Conditions that don't have an Ada exception counterpart must raise
+ Non_Ada_Error. Since this is defined in s-auxdec, it should only be
+ referenced by user programs, not the compiler or tools. Hence the
+ #ifdef IN_RTS. */
+
+#ifdef IN_RTS
+#define Non_Ada_Error system__aux_dec__non_ada_error
+extern struct Exception_Data Non_Ada_Error;
+
+#define Coded_Exception system__vms_exception_table__coded_exception
+extern struct Exception_Data *Coded_Exception (int);
+#endif
+
+/* Define macro symbols for the VMS conditions that become Ada exceptions.
+ Most of these are also defined in the header file ssdef.h which has not
+ yet been converted to be recoginized by Gnu C. Some, which couldn't be
+ located, are assigned names based on the DEC test suite tests which
+ raise them. */
+
+#define SS$_ACCVIO 12
+#define SS$_DEBUG 1132
+#define SS$_INTDIV 1156
+#define SS$_HPARITH 1284
+#define SS$_STKOVF 1364
+#define SS$_RESIGNAL 2328
+#define MTH$_FLOOVEMAT 1475268 /* Some ACVC_21 CXA tests */
+#define SS$_CE24VRU 3253636 /* Write to unopened file */
+#define SS$_C980VTE 3246436 /* AST requests time slice */
+#define CMA$_EXIT_THREAD 4227492
+#define CMA$_EXCCOPLOS 4228108
+#define CMA$_ALERTED 4227460
+
+struct descriptor_s {unsigned short len, mbz; char *adr; };
+
+static long __gnat_error_handler PARAMS ((int *, void *));
+
+static long
+__gnat_error_handler (sigargs, mechargs)
+ int *sigargs;
+ void *mechargs;
+{
+ struct Exception_Data *exception = 0;
+ char *msg = "";
+ char message [256];
+ long prvhnd;
+ struct descriptor_s msgdesc;
+ int msg_flag = 0x000f; /* 1 bit for each of the four message parts */
+ unsigned short outlen;
+ char curr_icb [544];
+ long curr_invo_handle;
+ long *mstate;
+
+ /* Resignaled condtions aren't effected by by pragma Import_Exception */
+
+ switch (sigargs[1])
+ {
+
+ case CMA$_EXIT_THREAD:
+ return SS$_RESIGNAL;
+
+ case SS$_DEBUG: /* Gdb attach, resignal to merge activate gdbstub. */
+ return SS$_RESIGNAL;
+
+ case 1409786: /* Nickerson bug #33 ??? */
+ return SS$_RESIGNAL;
+
+ case 1381050: /* Nickerson bug #33 ??? */
+ return SS$_RESIGNAL;
+
+ case 11829410: /* Resignalled as Use_Error for CE10VRC */
+ return SS$_RESIGNAL;
+
+ }
+
+#ifdef IN_RTS
+ /* See if it's an imported exception. Mask off severity bits. */
+ exception = Coded_Exception (sigargs [1] & 0xfffffff8);
+ if (exception)
+ {
+ msgdesc.len = 256;
+ msgdesc.mbz = 0;
+ msgdesc.adr = message;
+ SYS$GETMSG (sigargs[1], &outlen, &msgdesc, msg_flag, 0);
+ message [outlen] = 0;
+ msg = message;
+
+ exception->Name_Length = 19;
+ /* The full name really should be get sys$getmsg returns. ??? */
+ exception->Full_Name = "IMPORTED_EXCEPTION";
+ exception->Import_Code = sigargs [1] & 0xfffffff8;
+ }
+#endif
+
+ if (exception == 0)
+ switch (sigargs[1])
+ {
+ case SS$_ACCVIO:
+ if (sigargs[3] == 0)
+ {
+ exception = &constraint_error;
+ msg = "access zero";
+ }
+ else
+ {
+ exception = &storage_error;
+ msg = "stack overflow (or erroneous memory access)";
+ }
+ break;
+
+ case SS$_STKOVF:
+ exception = &storage_error;
+ msg = "stack overflow";
+ break;
+
+ case SS$_INTDIV:
+ exception = &constraint_error;
+ msg = "division by zero";
+ break;
+
+ case SS$_HPARITH:
+#ifndef IN_RTS
+ return SS$_RESIGNAL; /* toplev.c handles for compiler */
+#else
+ {
+ exception = &constraint_error;
+ msg = "arithmetic error";
+ }
+#endif
+ break;
+
+ case MTH$_FLOOVEMAT:
+ exception = &constraint_error;
+ msg = "floating overflow in math library";
+ break;
+
+ case SS$_CE24VRU:
+ exception = &constraint_error;
+ msg = "";
+ break;
+
+ case SS$_C980VTE:
+ exception = &program_error;
+ msg = "";
+ break;
+
+ default:
+#ifndef IN_RTS
+ exception = &program_error;
+#else
+ /* User programs expect Non_Ada_Error to be raised, reference
+ DEC Ada test CXCONDHAN. */
+ exception = &Non_Ada_Error;
+#endif
+ msgdesc.len = 256;
+ msgdesc.mbz = 0;
+ msgdesc.adr = message;
+ SYS$GETMSG (sigargs[1], &outlen, &msgdesc, msg_flag, 0);
+ message [outlen] = 0;
+ msg = message;
+ break;
+ }
+
+ mstate = (long *) (*Get_Machine_State_Addr) ();
+ if (mstate != 0)
+ {
+ LIB$GET_CURR_INVO_CONTEXT (&curr_icb);
+ LIB$GET_PREV_INVO_CONTEXT (&curr_icb);
+ LIB$GET_PREV_INVO_CONTEXT (&curr_icb);
+ curr_invo_handle = LIB$GET_INVO_HANDLE (&curr_icb);
+ *mstate = curr_invo_handle;
+ }
+ Raise_From_Signal_Handler (exception, msg);
+}
+
+void
+__gnat_install_handler ()
+{
+ long prvhnd;
+ char *c;
+
+ c = (char *) malloc (1025);
+
+ __gnat_error_prehandler_stack = &c[1024];
+
+ /* __gnat_error_prehandler is an assembly function. */
+ SYS$SETEXV (1, __gnat_error_prehandler, 3, &prvhnd);
+ __gnat_handler_installed = 1;
+}
+
+void
+__gnat_initialize()
+{
+}
+
+/***************************************/
+/* __gnat_initialize (VXWorks version) */
+/***************************************/
+
+#elif defined(__vxworks)
+
+#include <signal.h>
+#include <taskLib.h>
+#include <intLib.h>
+#include <iv.h>
+
+static void __gnat_init_handler PARAMS ((int));
+extern int __gnat_inum_to_ivec PARAMS ((int));
+static void __gnat_error_handler PARAMS ((int, int, struct sigcontext *));
+
+static void
+__gnat_int_handler (interr)
+ int interr;
+{
+ /* Note that we should use something like Raise_From_Int_Handler here, but
+ for now Raise_From_Signal_Handler will do the job. ??? */
+
+ Raise_From_Signal_Handler (&storage_error, "stack overflow");
+}
+
+/* Used for stack-checking on VxWorks. Must be task-local in
+ tasking programs */
+
+void *__gnat_stack_limit = NULL;
+
+#ifndef __alpha_vxworks
+
+/* getpid is used by s-parint.adb, but is not defined by VxWorks, except
+ on Alpha VxWorks */
+
+extern long getpid PARAMS ((void));
+
+long
+getpid ()
+{
+ return taskIdSelf ();
+}
+#endif
+
+/* This is needed by the GNAT run time to handle Vxworks interrupts */
+int
+__gnat_inum_to_ivec (num)
+ int num;
+{
+ return INUM_TO_IVEC (num);
+}
+
+static void
+__gnat_error_handler (sig, code, sc)
+ int sig;
+ int code;
+ struct sigcontext *sc;
+{
+ struct Exception_Data *exception;
+ sigset_t mask;
+ int result;
+ char *msg;
+
+ /* VxWorks will always mask out the signal during the signal handler and
+ will reenable it on a longjmp. GNAT does not generate a longjmp to
+ return from a signal handler so the signal will still be masked unless
+ we unmask it. */
+ (void) sigprocmask (SIG_SETMASK, NULL, &mask);
+ sigdelset (&mask, sig);
+ (void) sigprocmask (SIG_SETMASK, &mask, NULL);
+
+ /* VxWorks will suspend the task when it gets a hardware exception. We
+ take the liberty of resuming the task for the application. */
+ if (taskIsSuspended (taskIdSelf ()) != 0)
+ (void) taskResume (taskIdSelf ());
+
+ switch (sig)
+ {
+ case SIGFPE:
+ exception = &constraint_error;
+ msg = "SIGFPE";
+ break;
+ case SIGILL:
+ exception = &constraint_error;
+ msg = "SIGILL";
+ break;
+ case SIGSEGV:
+ exception = &program_error;
+ msg = "SIGSEGV";
+ break;
+ case SIGBUS:
+ exception = &program_error;
+ msg = "SIGBUS";
+ break;
+ default:
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ Raise_From_Signal_Handler (exception, msg);
+}
+
+void
+__gnat_install_handler ()
+{
+ struct sigaction act;
+
+ /* Setup signal handler to map synchronous signals to appropriate
+ exceptions. Make sure that the handler isn't interrupted by another
+ signal that might cause a scheduling event! */
+
+ act.sa_handler = __gnat_error_handler;
+ act.sa_flags = SA_SIGINFO | SA_ONSTACK;
+ (void) sigemptyset (&act.sa_mask);
+
+ (void) sigaction (SIGFPE, &act, NULL);
+
+ if (__gl_unreserve_all_interrupts == 0)
+ {
+ (void) sigaction (SIGILL, &act, NULL);
+ (void) sigaction (SIGSEGV, &act, NULL);
+ (void) sigaction (SIGBUS, &act, NULL);
+ }
+ __gnat_handler_installed = 1;
+}
+
+#define HAVE_GNAT_INIT_FLOAT
+
+void
+__gnat_init_float ()
+{
+#if defined (_ARCH_PPC) && !defined (_SOFT_FLOAT)
+ /* Disable overflow/underflow exceptions on the PPC processor, this is needed
+ to get correct Ada semantic */
+ asm ("mtfsb0 25");
+ asm ("mtfsb0 26");
+#endif
+}
+
+void
+__gnat_initialize ()
+{
+ TASK_DESC pTaskDesc;
+
+ if (taskInfoGet (taskIdSelf (), &pTaskDesc) != OK)
+ printErr ("Cannot get task info");
+
+ __gnat_stack_limit = (void *) pTaskDesc.td_pStackLimit;
+
+ __gnat_init_float ();
+
+#ifdef __mips_vxworks
+#if 0
+ /* For now remove this handler, since it is causing interferences with gdb */
+
+ /* Connect the overflow trap directly to the __gnat_int_handler routine
+ as it is not converted to a signal by VxWorks. */
+
+ intConnect (INUM_TO_IVEC (IV_TRAP_VEC), &__gnat_int_handler, IV_TRAP_VEC);
+#endif
+#endif
+}
+
+
+/***************************************/
+/* __gnat_initialize (default version) */
+/***************************************/
+
+/* Get the stack unwinding mechanism when available and when compiling
+ a-init.c for the run time. Except in the case of a restricted run-time,
+ such as RT-Linux modules (__RT__ is defined). */
+
+#elif defined (IN_RTS) && !defined (__RT__)
+
+/* If we have a definition of INCOMING_RETURN_ADDR_RTX, assume that
+ the rest of the DWARF 2 frame unwind support is also provided. */
+#if !defined (DWARF2_UNWIND_INFO) && defined (INCOMING_RETURN_ADDR_RTX)
+#define DWARF2_UNWIND_INFO 1
+#endif
+
+#ifdef DWARF2_UNWIND_INFO
+#include "frame.h"
+
+struct machine_state
+{
+ frame_state f1, f2, f3;
+ frame_state *udata, *udata_start, *sub_udata;
+ void *pc, *pc_start, *new_pc;
+};
+
+typedef int word_type __attribute__ ((mode (__word__)));
+
+/* This type is used in get_reg and put_reg to deal with ABIs where a void*
+ is smaller than a word, such as the Irix 6 n32 ABI. We cast twice to
+ avoid a warning about casting between int and pointer of different
+ sizes. */
+
+typedef int ptr_type __attribute__ ((mode (pointer)));
+
+static void get_reg PARAMS ((unsigned int, frame_state *,
+ frame_state *));
+static void put_reg PARAMS ((unsigned int, void *,
+ frame_state *));
+static void copy_reg PARAMS ((unsigned int, frame_state *,
+ frame_state *));
+static inline void put_return_addr PARAMS ((void *, frame_state *));
+static inline void *get_return_addr PARAMS ((frame_state *,
+ frame_state *));
+static frame_state *__frame_state_for_r PARAMS ((void *, frame_state *));
+
+#ifdef INCOMING_REGNO
+static int in_reg_window PARAMS ((unsigned int, frame_state *));
+#endif
+
+extern void __gnat_pop_frame PARAMS ((struct machine_state *));
+extern void __gnat_set_machine_state PARAMS ((struct machine_state *));
+extern void __gnat_enter_handler PARAMS ((struct machine_state *,
+ void *));
+extern __SIZE_TYPE__ __gnat_machine_state_length PARAMS ((void));
+extern void *__gnat_get_code_loc PARAMS ((struct machine_state *));
+
+/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+ frame called by UDATA or 0. */
+
+static void *
+get_reg (reg, udata, sub_udata)
+ unsigned int reg;
+ frame_state *udata, *sub_udata;
+{
+ if (udata->saved[reg] == REG_SAVED_OFFSET)
+ return
+ (void *) (ptr_type) *(word_type *) (udata->cfa
+ + udata->reg_or_offset[reg]);
+ else if (udata->saved[reg] == REG_SAVED_REG && sub_udata)
+ return get_reg (udata->reg_or_offset[reg], sub_udata, 0);
+ else
+ abort ();
+}
+
+/* Overwrite the saved value for register REG in frame UDATA with VAL. */
+
+static void
+put_reg (reg, val, udata)
+ unsigned int reg;
+ void *val;
+ frame_state *udate;
+{
+ if (udata->saved[reg] == REG_SAVED_OFFSET)
+ *(word_type *) (udata->cfa + udata->reg_or_offset[reg])
+ = (word_type) (ptr_type) val;
+ else
+ abort ();
+}
+
+/* Copy the saved value for register REG from frame UDATA to frame
+ TARGET_UDATA. Unlike the previous two functions, this can handle
+ registers that are not one word large. */
+
+static void
+copy_reg (reg, udata, target_udata)
+ unsigned int reg;
+ frame_state *udate, *target_udata;
+{
+ if (udata->saved[reg] == REG_SAVED_OFFSET
+ && target_udata->saved[reg] == REG_SAVED_OFFSET)
+ memcpy (target_udata->cfa + target_udata->reg_or_offset[reg],
+ udata->cfa + udata->reg_or_offset[reg],
+ __builtin_dwarf_reg_size (reg));
+ else
+ abort ();
+}
+
+/* Overwrite the return address for frame UDATA with VAL. */
+
+static inline void
+put_return_addr (val, udata)
+ void *val;
+ frame_state *udata;
+{
+ val = __builtin_frob_return_addr (val);
+ put_reg (udata->retaddr_column, val, udata);
+}
+
+#ifdef INCOMING_REGNO
+
+/* Is the saved value for register REG in frame UDATA stored in a register
+ window in the previous frame? */
+
+static int
+in_reg_window (reg, udata)
+ unsigned int reg;
+ frame_state *udata;
+{
+ if (udata->saved[reg] != REG_SAVED_OFFSET)
+ return 0;
+
+#ifdef STACK_GROWS_DOWNWARD
+ return udata->reg_or_offset[reg] > 0;
+#else
+ return udata->reg_or_offset[reg] < 0;
+#endif
+}
+#endif /* INCOMING_REGNO */
+
+/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
+ frame called by UDATA or 0. */
+
+static inline void *
+get_return_addr (udata, sub_udata)
+ frame_state *udate, *sub_udata;
+{
+ return __builtin_extract_return_addr (get_reg (udata->retaddr_column,
+ udata, sub_udata));
+}
+
+/* Thread-safe version of __frame_state_for */
+
+static frame_state *
+__frame_state_for_r (void *pc_target, frame_state *state_in)
+ void *pc_target;
+ frame_state *state_in;
+{
+ frame_state *f;
+
+ (*Lock_Task) ();
+ f = __frame_state_for (pc_target, state_in);
+ (*Unlock_Task) ();
+ return f;
+}
+
+/* Given the current frame UDATA and its return address PC, return the
+ information about the calling frame in CALLER_UDATA. */
+
+void
+__gnat_pop_frame (m)
+ struct machine_state *m;
+{
+ frame_state *p;
+
+ int i;
+
+ m->pc = m->new_pc;
+ p = m->udata;
+ if (! __frame_state_for_r (m->pc, m->sub_udata))
+ {
+ m->new_pc = 0;
+ return;
+ }
+
+ /* Now go back to our caller's stack frame. If our caller's CFA register
+ was saved in our stack frame, restore it; otherwise, assume the CFA
+ register is SP and restore it to our CFA value. */
+ if (m->udata->saved[m->sub_udata->cfa_reg])
+ m->sub_udata->cfa = get_reg (m->sub_udata->cfa_reg, m->udata, 0);
+ else
+ m->sub_udata->cfa = m->udata->cfa;
+ m->sub_udata->cfa += m->sub_udata->cfa_offset;
+
+ m->udata = m->sub_udata;
+ m->sub_udata = p;
+ m->new_pc = get_return_addr (m->udata, m->sub_udata) - 1;
+
+ return;
+
+/* ??? disable this code for now since it doesn't work properly */
+#if 0
+ if (m->pc == m->pc_start)
+ return;
+
+ /* Copy the frame's saved register values into our register save slots. */
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+ if (i != m->udata->retaddr_column && m->udata->saved[i])
+ {
+#ifdef INCOMING_REGNO
+ /* If you modify the saved value of the return address
+ register on the SPARC, you modify the return address for
+ your caller's frame. Don't do that here, as it will
+ confuse get_return_addr. */
+ if (in_reg_window (i, m->udata)
+ && m->udata->saved[m->udata->retaddr_column] == REG_SAVED_REG
+ && m->udata->reg_or_offset[m->udata->retaddr_column] == i)
+ continue;
+#endif
+ copy_reg (i, m->udata, m->udata_start);
+ }
+#endif
+}
+
+void
+__gnat_set_machine_state (machine_state)
+ struct machine_state *machine_state;
+{
+ frame_state sub_udata;
+
+ /* Start at our stack frame. */
+label:
+ machine_state->udata = &machine_state->f1;
+ machine_state->sub_udata = &machine_state->f2;
+ machine_state->udata_start = &machine_state->f3;
+
+ if (! __frame_state_for_r (&&label, machine_state->udata))
+ return;
+
+ /* We need to get the value from the CFA register. At this point in
+ compiling libgnat.a we don't know whether or not we will use the frame
+ pointer register for the CFA, so we check our unwind info. */
+ if (machine_state->udata->cfa_reg == __builtin_dwarf_fp_regnum ())
+ machine_state->udata->cfa = __builtin_fp ();
+ else
+ machine_state->udata->cfa = __builtin_sp ();
+ machine_state->udata->cfa += machine_state->udata->cfa_offset;
+
+ memcpy (machine_state->udata_start, machine_state->udata,
+ sizeof (frame_state));
+ machine_state->new_pc =
+ machine_state->pc_start =
+ machine_state->pc = &&label;
+
+ /* Do any necessary initialization to access arbitrary stack frames.
+ On the SPARC, this means flushing the register windows. */
+ __builtin_unwind_init ();
+
+ /* go up one frame */
+ __gnat_pop_frame (machine_state);
+}
+
+void
+__gnat_enter_handler (m, handler)
+ struct machine_state *m;
+ void *handler;
+{
+ void *retaddr;
+
+#ifdef INCOMING_REGNO
+ /* we need to update the saved return address register from
+ the last frame we unwind, or the handler frame will have the wrong
+ return address. */
+ if (m->udata->saved[m->udata->retaddr_column] == REG_SAVED_REG)
+ {
+ int i = m->udata->reg_or_offset[m->udata->retaddr_column];
+ if (in_reg_window (i, m->udata))
+ copy_reg (i, m->udata, m->udata_start);
+ }
+#endif
+
+ /* Emit the stub to adjust sp and jump to the handler. */
+ retaddr = __builtin_eh_stub ();
+
+ /* And then set our return address to point to the stub. */
+ if (m->udata_start->saved[m->udata_start->retaddr_column] ==
+ REG_SAVED_OFFSET)
+ put_return_addr (retaddr, m->udata_start);
+ else
+ __builtin_set_return_addr_reg (retaddr);
+
+ /* Set up the registers we use to communicate with the stub.
+ We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack. */
+ __builtin_set_eh_regs
+ (handler,
+#ifdef STACK_GROWS_DOWNWARD
+ m->udata->cfa - m->udata_start->cfa
+#else
+ m->udata_start->cfa - m->udata->cfa
+#endif
+ + m->udata->args_size);
+
+ /* Epilogue: restore the handler frame's register values and return
+ to the stub. */
+}
+
+__SIZE_TYPE__
+__gnat_machine_state_length ()
+{
+ return sizeof (struct machine_state);
+}
+
+void *
+__gnat_get_code_loc (m)
+ struct machine_state *m;
+{
+ return m->pc;
+}
+#endif /* DWARF2_UNWIND_INFO */
+
+#else
+
+/* For all other versions of GNAT, the initialize routine and handler
+ installation do nothing */
+
+/***************************************/
+/* __gnat_initialize (default version) */
+/***************************************/
+
+void
+__gnat_initialize ()
+{
+}
+
+/********************************************/
+/* __gnat_install_handler (default version) */
+/********************************************/
+
+void
+__gnat_install_handler ()
+{
+ __gnat_handler_installed = 1;
+}
+
+#endif
+
+
+/*********************/
+/* __gnat_init_float */
+/*********************/
+
+/* This routine is called as each process thread is created, for possible
+ initialization of the FP processor. This version is used under INTERIX,
+ WIN32 and could be used under OS/2 */
+
+#if defined (_WIN32) || defined (__INTERIX) || defined (__EMX__) \
+ || defined (__Lynx__)
+
+#define HAVE_GNAT_INIT_FLOAT
+
+void
+__gnat_init_float ()
+{
+#if defined (__i386__) || defined (i386)
+
+ /* This is used to properly initialize the FPU on an x86 for each
+ process thread. */
+
+ asm ("finit");
+
+#endif /* Defined __i386__ */
+}
+#endif
+
+
+#ifndef HAVE_GNAT_INIT_FLOAT
+
+/* All targets without a specific __gnat_init_float will use an empty one */
+void
+__gnat_init_float ()
+{
+}
+#endif