(root)/
gcc-13.2.0/
gcc/
ada/
init.c
       1  /****************************************************************************
       2   *                                                                          *
       3   *                         GNAT COMPILER COMPONENTS                         *
       4   *                                                                          *
       5   *                                 I N I T                                  *
       6   *                                                                          *
       7   *                          C Implementation File                           *
       8   *                                                                          *
       9   *          Copyright (C) 1992-2023, Free Software Foundation, Inc.         *
      10   *                                                                          *
      11   * GNAT is free software;  you can  redistribute it  and/or modify it under *
      12   * terms of the  GNU General Public License as published  by the Free Soft- *
      13   * ware  Foundation;  either version 3,  or (at your option) any later ver- *
      14   * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
      15   * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
      16   * or FITNESS FOR A PARTICULAR PURPOSE.                                     *
      17   *                                                                          *
      18   * As a special exception under Section 7 of GPL version 3, you are granted *
      19   * additional permissions described in the GCC Runtime Library Exception,   *
      20   * version 3.1, as published by the Free Software Foundation.               *
      21   *                                                                          *
      22   * You should have received a copy of the GNU General Public License and    *
      23   * a copy of the GCC Runtime Library Exception along with this program;     *
      24   * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    *
      25   * <http://www.gnu.org/licenses/>.                                          *
      26   *                                                                          *
      27   * GNAT was originally developed  by the GNAT team at  New York University. *
      28   * Extensive contributions were provided by Ada Core Technologies Inc.      *
      29   *                                                                          *
      30   ****************************************************************************/
      31  
      32  /*  This unit contains initialization circuits that are system dependent.
      33      A major part of the functionality involves stack overflow checking.
      34      The GCC backend generates probe instructions to test for stack overflow.
      35      For details on the exact approach used to generate these probes, see the
      36      "Using and Porting GCC" manual, in particular the "Stack Checking" section
      37      and the subsection "Specifying How Stack Checking is Done".  The handlers
      38      installed by this file are used to catch the resulting signals that come
      39      from these probes failing (i.e. touching protected pages).  */
      40  
      41  /* This file should be kept synchronized with s-init.ads, s-init.adb and the
      42     s-init-*.adb variants. All these files implement the required functionality
      43     for different targets.  */
      44  
      45  /* The following include is here to meet the published VxWorks requirement
      46     that the __vxworks header appear before any other include.  */
      47  #ifdef __vxworks
      48  #include "vxWorks.h"
      49  #include "version.h" /* for _WRS_VXWORKS_MAJOR */
      50  #endif
      51  
      52  #ifdef __ANDROID__
      53  #undef __linux__
      54  #endif
      55  
      56  #ifdef IN_RTS
      57  
      58  #ifdef STANDALONE
      59  #include "runtime.h"
      60  #else
      61  #include "tconfig.h"
      62  #include "tsystem.h"
      63  #endif
      64  
      65  #include <sys/stat.h>
      66  
      67  /* We don't have libiberty, so use malloc.  */
      68  #define xmalloc(S) malloc (S)
      69  #else
      70  #include "config.h"
      71  #include "system.h"
      72  #endif
      73  
      74  #include "adaint.h"
      75  #include "raise.h"
      76  
      77  #ifdef __cplusplus
      78  extern "C" {
      79  #endif
      80  
      81  extern void __gnat_raise_program_error (const void *, int);
      82  
      83  /* Addresses of exception data blocks for predefined exceptions.  Tasking_Error
      84     is not used in this unit, and the abort signal is only used on IRIX.
      85     ??? Revisit this part since IRIX is no longer supported.  */
      86  extern struct Exception_Data constraint_error;
      87  extern struct Exception_Data numeric_error;
      88  extern struct Exception_Data program_error;
      89  extern struct Exception_Data storage_error;
      90  
      91  /* For the Cert run time we use the regular raise exception routine because
      92     __gnat_raise_from_signal_handler is not available.  */
      93  #ifdef CERT
      94  #define Raise_From_Signal_Handler __gnat_raise_exception
      95  #else
      96  #define Raise_From_Signal_Handler __gnat_raise_from_signal_handler
      97  #endif
      98  
      99  extern void Raise_From_Signal_Handler (struct Exception_Data *, const void *)
     100    ATTRIBUTE_NORETURN;
     101  
     102  /* Global values computed by the binder.  Note that these variables are
     103     declared here, not in the binder file, to avoid having unresolved
     104     references in the shared libgnat.  */
     105  int   __gl_main_priority                 = -1;
     106  int   __gl_main_cpu                      = -1;
     107  int   __gl_time_slice_val                = -1;
     108  char  __gl_wc_encoding                   = 'n';
     109  char  __gl_locking_policy                = ' ';
     110  char  __gl_queuing_policy                = ' ';
     111  char  __gl_task_dispatching_policy       = ' ';
     112  char *__gl_priority_specific_dispatching = 0;
     113  int   __gl_num_specific_dispatching      = 0;
     114  char *__gl_interrupt_states              = 0;
     115  int   __gl_num_interrupt_states          = 0;
     116  int   __gl_unreserve_all_interrupts      = 0;
     117  int   __gl_exception_tracebacks          = 0;
     118  int   __gl_exception_tracebacks_symbolic = 0;
     119  int   __gl_detect_blocking               = 0;
     120  int   __gl_default_stack_size            = -1;
     121  int   __gl_leap_seconds_support          = 0;
     122  int   __gl_canonical_streams             = 0;
     123  char *__gl_bind_env_addr                 = NULL;
     124  int   __gl_xdr_stream                    = 0;
     125  
     126  /* This value is not used anymore, but kept for bootstrapping purpose.  */
     127  int   __gl_zero_cost_exceptions          = 0;
     128  
     129  /* Indication of whether synchronous signal handler has already been
     130     installed by a previous call to adainit.  */
     131  int  __gnat_handler_installed      = 0;
     132  
     133  #ifndef IN_RTS
     134  int __gnat_inside_elab_final_code = 0;
     135  /* ??? This variable is obsolete since 2001-08-29 but is kept to allow
     136     bootstrap from old GNAT versions (< 3.15).  */
     137  #endif
     138  
     139  /* HAVE_GNAT_INIT_FLOAT must be set on every targets where a __gnat_init_float
     140     is defined.  If this is not set then a void implementation will be defined
     141     at the end of this unit.  */
     142  #undef HAVE_GNAT_INIT_FLOAT
     143  
     144  /******************************/
     145  /* __gnat_get_interrupt_state */
     146  /******************************/
     147  
     148  char __gnat_get_interrupt_state (int);
     149  
     150  /* This routine is called from the runtime as needed to determine the state
     151     of an interrupt, as set by an Interrupt_State pragma appearing anywhere
     152     in the current partition.  The input argument is the interrupt number,
     153     and the result is one of the following:
     154  
     155         'n'   this interrupt not set by any Interrupt_State pragma
     156         'u'   Interrupt_State pragma set state to User
     157         'r'   Interrupt_State pragma set state to Runtime
     158         's'   Interrupt_State pragma set state to System  */
     159  
     160  char
     161  __gnat_get_interrupt_state (int intrup)
     162  {
     163    if (intrup >= __gl_num_interrupt_states)
     164      return 'n';
     165    else
     166      return __gl_interrupt_states [intrup];
     167  }
     168  
     169  /***********************************/
     170  /* __gnat_get_specific_dispatching */
     171  /***********************************/
     172  
     173  char __gnat_get_specific_dispatching (int);
     174  
     175  /* This routine is called from the runtime as needed to determine the
     176     priority specific dispatching policy, as set by a
     177     Priority_Specific_Dispatching pragma appearing anywhere in the current
     178     partition.  The input argument is the priority number, and the result
     179     is the upper case first character of the policy name, e.g. 'F' for
     180     FIFO_Within_Priorities. A space ' ' is returned if no
     181     Priority_Specific_Dispatching pragma is used in the partition.  */
     182  
     183  char
     184  __gnat_get_specific_dispatching (int priority)
     185  {
     186    if (__gl_num_specific_dispatching == 0)
     187      return ' ';
     188    else if (priority >= __gl_num_specific_dispatching)
     189      return 'F';
     190    else
     191      return __gl_priority_specific_dispatching [priority];
     192  }
     193  
     194  #ifndef IN_RTS
     195  
     196  /**********************/
     197  /* __gnat_set_globals */
     198  /**********************/
     199  
     200  /* This routine is kept for bootstrapping purposes, since the binder generated
     201     file now sets the __gl_* variables directly.  */
     202  
     203  void
     204  __gnat_set_globals (void)
     205  {
     206  }
     207  
     208  #endif
     209  
     210  /***************/
     211  /* AIX Section */
     212  /***************/
     213  
     214  #if defined (_AIX)
     215  
     216  #include <signal.h>
     217  #include <sys/time.h>
     218  
     219  /* Some versions of AIX don't define SA_NODEFER.  */
     220  
     221  #ifndef SA_NODEFER
     222  #define SA_NODEFER 0
     223  #endif /* SA_NODEFER */
     224  
     225  /* Versions of AIX before 4.3 don't have nanosleep but provide
     226     nsleep instead.  */
     227  
     228  #ifndef _AIXVERSION_430
     229  
     230  extern int nanosleep (struct timestruc_t *, struct timestruc_t *);
     231  
     232  int
     233  nanosleep (struct timestruc_t *Rqtp, struct timestruc_t *Rmtp)
     234  {
     235    return nsleep (Rqtp, Rmtp);
     236  }
     237  
     238  #endif /* _AIXVERSION_430 */
     239  
     240  static void
     241  __gnat_error_handler (int sig,
     242  		      siginfo_t *si ATTRIBUTE_UNUSED,
     243  		      void *ucontext ATTRIBUTE_UNUSED)
     244  {
     245    struct Exception_Data *exception;
     246    const char *msg;
     247  
     248    switch (sig)
     249      {
     250      case SIGSEGV:
     251        /* FIXME: we need to detect the case of a *real* SIGSEGV.  */
     252        exception = &storage_error;
     253        msg = "stack overflow or erroneous memory access";
     254        break;
     255  
     256      case SIGBUS:
     257        exception = &constraint_error;
     258        msg = "SIGBUS";
     259        break;
     260  
     261      case SIGFPE:
     262        exception = &constraint_error;
     263        msg = "SIGFPE";
     264        break;
     265  
     266      default:
     267        exception = &program_error;
     268        msg = "unhandled signal";
     269      }
     270  
     271    Raise_From_Signal_Handler (exception, msg);
     272  }
     273  
     274  void
     275  __gnat_install_handler (void)
     276  {
     277    struct sigaction act;
     278  
     279    /* Set up signal handler to map synchronous signals to appropriate
     280       exceptions.  Make sure that the handler isn't interrupted by another
     281       signal that might cause a scheduling event!  */
     282  
     283    act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
     284    act.sa_sigaction = __gnat_error_handler;
     285    sigemptyset (&act.sa_mask);
     286  
     287    /* Do not install handlers if interrupt state is "System".  */
     288    if (__gnat_get_interrupt_state (SIGABRT) != 's')
     289      sigaction (SIGABRT, &act, NULL);
     290    if (__gnat_get_interrupt_state (SIGFPE) != 's')
     291      sigaction (SIGFPE,  &act, NULL);
     292    if (__gnat_get_interrupt_state (SIGILL) != 's')
     293      sigaction (SIGILL,  &act, NULL);
     294    if (__gnat_get_interrupt_state (SIGSEGV) != 's')
     295      sigaction (SIGSEGV, &act, NULL);
     296    if (__gnat_get_interrupt_state (SIGBUS) != 's')
     297      sigaction (SIGBUS,  &act, NULL);
     298  
     299    __gnat_handler_installed = 1;
     300  }
     301  
     302  /*****************/
     303  /* HP-UX section */
     304  /*****************/
     305  
     306  #elif defined (__hpux__)
     307  
     308  #include <signal.h>
     309  #include <sys/ucontext.h>
     310  
     311  #if defined (IN_RTS) && defined (__ia64__)
     312  
     313  #include <sys/uc_access.h>
     314  
     315  #define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
     316  
     317  void
     318  __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
     319  {
     320    ucontext_t *uc = (ucontext_t *) ucontext;
     321    uint64_t ip;
     322  
     323    /* Adjust on itanium, as GetIPInfo is not supported.  */
     324    __uc_get_ip (uc, &ip);
     325    __uc_set_ip (uc, ip + 1);
     326  }
     327  #endif /* IN_RTS && __ia64__ */
     328  
     329  /* Tasking and Non-tasking signal handler.  Map SIGnal to Ada exception
     330     propagation after the required low level adjustments.  */
     331  
     332  static void
     333  __gnat_error_handler (int sig, siginfo_t *si ATTRIBUTE_UNUSED, void *ucontext)
     334  {
     335    struct Exception_Data *exception;
     336    const char *msg;
     337  
     338    __gnat_adjust_context_for_raise (sig, ucontext);
     339  
     340    switch (sig)
     341      {
     342      case SIGSEGV:
     343        /* FIXME: we need to detect the case of a *real* SIGSEGV.  */
     344        exception = &storage_error;
     345        msg = "stack overflow or erroneous memory access";
     346        break;
     347  
     348      case SIGBUS:
     349        exception = &constraint_error;
     350        msg = "SIGBUS";
     351        break;
     352  
     353      case SIGFPE:
     354        exception = &constraint_error;
     355        msg = "SIGFPE";
     356        break;
     357  
     358      default:
     359        exception = &program_error;
     360        msg = "unhandled signal";
     361      }
     362  
     363    Raise_From_Signal_Handler (exception, msg);
     364  }
     365  
     366  /* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.  */
     367  #if defined (__hppa__)
     368  char __gnat_alternate_stack[16 * 1024]; /* 2 * SIGSTKSZ */
     369  #else
     370  char __gnat_alternate_stack[128 * 1024]; /* MINSIGSTKSZ */
     371  #endif
     372  
     373  void
     374  __gnat_install_handler (void)
     375  {
     376    struct sigaction act;
     377  
     378    /* Set up signal handler to map synchronous signals to appropriate
     379       exceptions.  Make sure that the handler isn't interrupted by another
     380       signal that might cause a scheduling event!  Also setup an alternate
     381       stack region for the handler execution so that stack overflows can be
     382       handled properly, avoiding a SEGV generation from stack usage by the
     383       handler itself.  */
     384  
     385    stack_t stack;
     386    stack.ss_sp = __gnat_alternate_stack;
     387    stack.ss_size = sizeof (__gnat_alternate_stack);
     388    stack.ss_flags = 0;
     389    sigaltstack (&stack, NULL);
     390  
     391    act.sa_sigaction = __gnat_error_handler;
     392    act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
     393    sigemptyset (&act.sa_mask);
     394  
     395    /* Do not install handlers if interrupt state is "System".  */
     396    if (__gnat_get_interrupt_state (SIGABRT) != 's')
     397      sigaction (SIGABRT, &act, NULL);
     398    if (__gnat_get_interrupt_state (SIGFPE) != 's')
     399      sigaction (SIGFPE,  &act, NULL);
     400    if (__gnat_get_interrupt_state (SIGILL) != 's')
     401      sigaction (SIGILL,  &act, NULL);
     402    if (__gnat_get_interrupt_state (SIGBUS) != 's')
     403      sigaction (SIGBUS,  &act, NULL);
     404    act.sa_flags |= SA_ONSTACK;
     405    if (__gnat_get_interrupt_state (SIGSEGV) != 's')
     406      sigaction (SIGSEGV, &act, NULL);
     407  
     408    __gnat_handler_installed = 1;
     409  }
     410  
     411  /*********************/
     412  /* GNU/Linux Section */
     413  /*********************/
     414  
     415  #elif defined (__linux__)
     416  
     417  #include <signal.h>
     418  
     419  #define __USE_GNU 1 /* required to get REG_EIP/RIP from glibc's ucontext.h */
     420  #include <sys/ucontext.h>
     421  
     422  /* GNU/Linux, which uses glibc, does not define NULL in included
     423     header files.  */
     424  
     425  #if !defined (NULL)
     426  #define NULL ((void *) 0)
     427  #endif
     428  
     429  #if defined (MaRTE)
     430  
     431  /* MaRTE OS provides its own version of sigaction, sigfillset, and
     432     sigemptyset (overriding these symbol names).  We want to make sure that
     433     the versions provided by the underlying C library are used here (these
     434     versions are renamed by MaRTE to linux_sigaction, fake_linux_sigfillset,
     435     and fake_linux_sigemptyset, respectively).  The MaRTE library will not
     436     always be present (it will not be linked if no tasking constructs are
     437     used), so we use the weak symbol mechanism to point always to the symbols
     438     defined within the C library.  */
     439  
     440  #pragma weak linux_sigaction
     441  int linux_sigaction (int signum, const struct sigaction *act,
     442  		     struct sigaction *oldact)
     443  {
     444    return sigaction (signum, act, oldact);
     445  }
     446  #define sigaction(signum, act, oldact) linux_sigaction (signum, act, oldact)
     447  
     448  #pragma weak fake_linux_sigfillset
     449  void fake_linux_sigfillset (sigset_t *set)
     450  {
     451    sigfillset (set);
     452  }
     453  #define sigfillset(set) fake_linux_sigfillset (set)
     454  
     455  #pragma weak fake_linux_sigemptyset
     456  void fake_linux_sigemptyset (sigset_t *set)
     457  {
     458    sigemptyset (set);
     459  }
     460  #define sigemptyset(set) fake_linux_sigemptyset (set)
     461  
     462  #endif
     463  
     464  #if defined (__i386__) || defined (__x86_64__) || defined (__ia64__) \
     465      || defined (__ARMEL__)
     466  
     467  #define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
     468  
     469  void
     470  __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
     471  {
     472  #ifndef STANDALONE
     473    mcontext_t *mcontext = &((ucontext_t *) ucontext)->uc_mcontext;
     474  
     475    /* On the i386 and x86-64 architectures, stack checking is performed by
     476       means of probes with moving stack pointer, that is to say the probed
     477       address is always the value of the stack pointer.  Upon hitting the
     478       guard page, the stack pointer therefore points to an inaccessible
     479       address and an alternate signal stack is needed to run the handler.
     480       But there is an additional twist: on these architectures, the EH
     481       return code writes the address of the handler at the target CFA's
     482       value on the stack before doing the jump.  As a consequence, if
     483       there is an active handler in the frame whose stack has overflowed,
     484       the stack pointer must nevertheless point to an accessible address
     485       by the time the EH return is executed.
     486  
     487       We therefore adjust the saved value of the stack pointer by the size
     488       of one page + a small dope of 4 words, in order to make sure that it
     489       points to an accessible address in case it's used as the target CFA.
     490       The stack checking code guarantees that this address is unused by the
     491       time this happens.  */
     492  
     493  #if defined (__i386__)
     494    unsigned long *pc = (unsigned long *)mcontext->gregs[REG_EIP];
     495    /* The pattern is "orl $0x0,(%esp)" for a probe in 32-bit mode.  */
     496    if (signo == SIGSEGV && pc && *pc == 0x00240c83)
     497      mcontext->gregs[REG_ESP] += 4096 + 4 * sizeof (unsigned long);
     498  #elif defined (__x86_64__)
     499    unsigned long long *pc = (unsigned long long *)mcontext->gregs[REG_RIP];
     500    if (signo == SIGSEGV && pc
     501        /* The pattern is "orq $0x0,(%rsp)" for a probe in 64-bit mode.  */
     502        && ((*pc & 0xffffffffffLL) == 0x00240c8348LL
     503  	  /* The pattern may also be "orl $0x0,(%esp)" for a probe in
     504  	     x32 mode.  */
     505  	  || (*pc & 0xffffffffLL) == 0x00240c83LL))
     506      mcontext->gregs[REG_RSP] += 4096 + 4 * sizeof (unsigned long);
     507  #elif defined (__ia64__)
     508    /* ??? The IA-64 unwinder doesn't compensate for signals.  */
     509    mcontext->sc_ip++;
     510  #elif defined (__ARMEL__)
     511    /* ARM Bump has to be an even number because of odd/even architecture.  */
     512    mcontext->arm_pc+=2;
     513  #ifdef __thumb2__
     514  #define CPSR_THUMB_BIT 5
     515    /* For thumb, the return address much have the low order bit set, otherwise
     516       the unwinder will reset to "arm" mode upon return.  As long as the
     517       compilation unit containing the landing pad is compiled with the same
     518       mode (arm vs thumb) as the signaling compilation unit, this works.  */
     519    if (mcontext->arm_cpsr & (1<<CPSR_THUMB_BIT))
     520      mcontext->arm_pc+=1;
     521  #endif
     522  #endif
     523  #endif
     524  }
     525  
     526  #endif
     527  
     528  static void
     529  __gnat_error_handler (int sig, siginfo_t *si ATTRIBUTE_UNUSED, void *ucontext)
     530  {
     531    struct Exception_Data *exception;
     532    const char *msg;
     533  
     534    /* Adjusting is required for every fault context, so adjust for this one
     535       now, before we possibly trigger a recursive fault below.  */
     536    __gnat_adjust_context_for_raise (sig, ucontext);
     537  
     538    switch (sig)
     539      {
     540      case SIGSEGV:
     541        /* Here we would like a discrimination test to see whether the page
     542  	 before the faulting address is accessible.  Unfortunately, Linux
     543  	 seems to have no way of giving us the faulting address.
     544  
     545  	 In old versions of init.c, we had a test of the page before the
     546  	 stack pointer:
     547  
     548  	   ((volatile char *)
     549  	    ((long) si->esp_at_signal & - getpagesize ()))[getpagesize ()];
     550  
     551  	 but that's wrong since it tests the stack pointer location and the
     552  	 stack probing code may not move it until all probes succeed.
     553  
     554  	 For now we simply do not attempt any discrimination at all. Note
     555  	 that this is quite acceptable, since a "real" SIGSEGV can only
     556  	 occur as the result of an erroneous program.  */
     557        exception = &storage_error;
     558        msg = "stack overflow or erroneous memory access";
     559        break;
     560  
     561      case SIGBUS:
     562        exception = &storage_error;
     563        msg = "SIGBUS: possible stack overflow";
     564        break;
     565  
     566      case SIGFPE:
     567        exception = &constraint_error;
     568        msg = "SIGFPE";
     569        break;
     570  
     571      default:
     572        exception = &program_error;
     573        msg = "unhandled signal";
     574      }
     575  
     576    Raise_From_Signal_Handler (exception, msg);
     577  }
     578  
     579  #ifndef __ia64__
     580  #define HAVE_GNAT_ALTERNATE_STACK 1
     581  /* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.  */
     582  char __gnat_alternate_stack[32 * 1024];
     583  #endif
     584  
     585  #ifdef __XENO__
     586  #include <sys/mman.h>
     587  #include <native/task.h>
     588  
     589  RT_TASK main_task;
     590  #endif
     591  
     592  void
     593  __gnat_install_handler (void)
     594  {
     595    struct sigaction act;
     596  
     597  #ifdef __XENO__
     598    int prio;
     599  
     600    if (__gl_main_priority == -1)
     601      prio = 49;
     602    else
     603      prio = __gl_main_priority;
     604  
     605    /* Avoid memory swapping for this program */
     606  
     607    mlockall (MCL_CURRENT|MCL_FUTURE);
     608  
     609    /* Turn the current Linux task into a native Xenomai task */
     610  
     611    rt_task_shadow (&main_task, "environment_task", prio, T_FPU);
     612  #endif
     613  
     614    /* Set up signal handler to map synchronous signals to appropriate
     615       exceptions.  Make sure that the handler isn't interrupted by another
     616       signal that might cause a scheduling event!  Also setup an alternate
     617       stack region for the handler execution so that stack overflows can be
     618       handled properly, avoiding a SEGV generation from stack usage by the
     619       handler itself.  */
     620  
     621    act.sa_sigaction = __gnat_error_handler;
     622    act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
     623    sigemptyset (&act.sa_mask);
     624  
     625    /* Do not install handlers if interrupt state is "System".  */
     626    if (__gnat_get_interrupt_state (SIGABRT) != 's')
     627      sigaction (SIGABRT, &act, NULL);
     628    if (__gnat_get_interrupt_state (SIGFPE) != 's')
     629      sigaction (SIGFPE,  &act, NULL);
     630    if (__gnat_get_interrupt_state (SIGILL) != 's')
     631      sigaction (SIGILL,  &act, NULL);
     632    if (__gnat_get_interrupt_state (SIGBUS) != 's')
     633      sigaction (SIGBUS,  &act, NULL);
     634    if (__gnat_get_interrupt_state (SIGSEGV) != 's')
     635      {
     636  #ifdef HAVE_GNAT_ALTERNATE_STACK
     637        /* Setup an alternate stack region for the handler execution so that
     638  	 stack overflows can be handled properly, avoiding a SEGV generation
     639  	 from stack usage by the handler itself.  */
     640        stack_t stack;
     641  
     642        stack.ss_sp = __gnat_alternate_stack;
     643        stack.ss_size = sizeof (__gnat_alternate_stack);
     644        stack.ss_flags = 0;
     645        sigaltstack (&stack, NULL);
     646  
     647        act.sa_flags |= SA_ONSTACK;
     648  #endif
     649        sigaction (SIGSEGV, &act, NULL);
     650      }
     651  
     652    __gnat_handler_installed = 1;
     653  }
     654  
     655  /*******************/
     656  /* LynxOS Section */
     657  /*******************/
     658  
     659  #elif defined (__Lynx__)
     660  
     661  #include <signal.h>
     662  #include <unistd.h>
     663  
     664  /* SA_SIGINFO is not supported by default on LynxOS, so all we have
     665     available here is the "sig" argument. On newer LynxOS versions it's
     666     possible to support SA_SIGINFO by setting a kernel configuration macro.
     667  
     668     To wit:
     669  
     670     #define NONPOSIX_SA_HANDLER_PROTO (0)
     671  
     672     This macro must be set to 1 in either sys/bsp.<bspname>/uparam.h
     673     or in the associated uparam.h customization file sys/bsp.<bspname>/xparam.h
     674     (uparam.h includes xparam.h for customization)
     675  
     676     The NONPOSIX_SA_HANDLER_PROTO macro makes it possible to provide
     677     signal-catching function with 'info' and 'context' input parameters
     678     even if SA_SIGINFO flag is not set or it is set for a non-realtime signal.
     679  
     680     It also allows signal-catching function to update thread context even
     681     if SA_UPDATECTX flag is not set.
     682  
     683     This would be useful, but relying on that would transmit the requirement
     684     to users to configure that feature as well, which is undesirable.  */
     685  
     686  static void
     687  __gnat_error_handler (int sig)
     688  {
     689    struct Exception_Data *exception;
     690    const char *msg;
     691  
     692    switch(sig)
     693    {
     694      case SIGFPE:
     695        exception = &constraint_error;
     696        msg = "SIGFPE";
     697        break;
     698      case SIGILL:
     699        exception = &constraint_error;
     700        msg = "SIGILL";
     701        break;
     702      case SIGSEGV:
     703        exception = &storage_error;
     704        msg = "stack overflow or erroneous memory access";
     705        break;
     706      case SIGBUS:
     707        exception = &constraint_error;
     708        msg = "SIGBUS";
     709        break;
     710      default:
     711        exception = &program_error;
     712        msg = "unhandled signal";
     713      }
     714  
     715      Raise_From_Signal_Handler (exception, msg);
     716  }
     717  
     718  void
     719  __gnat_install_handler (void)
     720  {
     721    struct sigaction act;
     722  
     723    act.sa_handler = __gnat_error_handler;
     724    act.sa_flags = 0x0;
     725    sigemptyset (&act.sa_mask);
     726  
     727    /* Do not install handlers if interrupt state is "System".  */
     728    if (__gnat_get_interrupt_state (SIGFPE) != 's')
     729      sigaction (SIGFPE,  &act, NULL);
     730    if (__gnat_get_interrupt_state (SIGILL) != 's')
     731      sigaction (SIGILL,  &act, NULL);
     732    if (__gnat_get_interrupt_state (SIGSEGV) != 's')
     733      sigaction (SIGSEGV, &act, NULL);
     734    if (__gnat_get_interrupt_state (SIGBUS) != 's')
     735      sigaction (SIGBUS,  &act, NULL);
     736  
     737    __gnat_handler_installed = 1;
     738  }
     739  
     740  /*******************/
     741  /* Solaris Section */
     742  /*******************/
     743  
     744  #elif defined (__sun__) && !defined (__vxworks)
     745  
     746  #include <signal.h>
     747  #include <siginfo.h>
     748  #include <sys/ucontext.h>
     749  #include <sys/regset.h>
     750  
     751  static void
     752  __gnat_error_handler (int sig, siginfo_t *si, void *ucontext ATTRIBUTE_UNUSED)
     753  {
     754    struct Exception_Data *exception;
     755    static int recurse = 0;
     756    const char *msg;
     757  
     758    switch (sig)
     759      {
     760      case SIGSEGV:
     761        /* If the problem was permissions, this is a constraint error.
     762  	 Likewise if the failing address isn't maximally aligned or if
     763  	 we've recursed.
     764  
     765  	 ??? Using a static variable here isn't task-safe, but it's
     766  	 much too hard to do anything else and we're just determining
     767  	 which exception to raise.  */
     768        if (si->si_code == SEGV_ACCERR
     769  	  || (long) si->si_addr == 0
     770  	  || (((long) si->si_addr) & 3) != 0
     771  	  || recurse)
     772  	{
     773  	  exception = &constraint_error;
     774  	  msg = "SIGSEGV";
     775  	}
     776        else
     777  	{
     778  	  /* See if the page before the faulting page is accessible.  Do that
     779  	     by trying to access it.  We'd like to simply try to access
     780  	     4096 + the faulting address, but it's not guaranteed to be
     781  	     the actual address, just to be on the same page.  */
     782  	  recurse++;
     783  	  ((volatile char *)
     784  	   ((long) si->si_addr & - getpagesize ()))[getpagesize ()];
     785  	  exception = &storage_error;
     786  	  msg = "stack overflow or erroneous memory access";
     787  	}
     788        break;
     789  
     790      case SIGBUS:
     791        exception = &program_error;
     792        msg = "SIGBUS";
     793        break;
     794  
     795      case SIGFPE:
     796        exception = &constraint_error;
     797        msg = "SIGFPE";
     798        break;
     799  
     800      default:
     801        exception = &program_error;
     802        msg = "unhandled signal";
     803      }
     804  
     805    recurse = 0;
     806    Raise_From_Signal_Handler (exception, msg);
     807  }
     808  
     809  void
     810  __gnat_install_handler (void)
     811  {
     812    struct sigaction act;
     813  
     814    /* Set up signal handler to map synchronous signals to appropriate
     815       exceptions.  Make sure that the handler isn't interrupted by another
     816       signal that might cause a scheduling event!  */
     817  
     818    act.sa_sigaction = __gnat_error_handler;
     819    act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
     820    sigemptyset (&act.sa_mask);
     821  
     822    /* Do not install handlers if interrupt state is "System".  */
     823    if (__gnat_get_interrupt_state (SIGABRT) != 's')
     824      sigaction (SIGABRT, &act, NULL);
     825    if (__gnat_get_interrupt_state (SIGFPE) != 's')
     826      sigaction (SIGFPE,  &act, NULL);
     827    if (__gnat_get_interrupt_state (SIGSEGV) != 's')
     828      sigaction (SIGSEGV, &act, NULL);
     829    if (__gnat_get_interrupt_state (SIGBUS) != 's')
     830      sigaction (SIGBUS,  &act, NULL);
     831  
     832    __gnat_handler_installed = 1;
     833  }
     834  
     835  /***************/
     836  /* VMS Section */
     837  /***************/
     838  
     839  #elif defined (VMS)
     840  
     841  /* Routine called from binder to override default feature values. */
     842  void __gnat_set_features (void);
     843  int __gnat_features_set = 0;
     844  void (*__gnat_ctrl_c_handler) (void) = 0;
     845  
     846  #ifdef __IA64
     847  #define lib_get_curr_invo_context LIB$I64_GET_CURR_INVO_CONTEXT
     848  #define lib_get_prev_invo_context LIB$I64_GET_PREV_INVO_CONTEXT
     849  #define lib_get_invo_handle LIB$I64_GET_INVO_HANDLE
     850  #else
     851  #define lib_get_curr_invo_context LIB$GET_CURR_INVO_CONTEXT
     852  #define lib_get_prev_invo_context LIB$GET_PREV_INVO_CONTEXT
     853  #define lib_get_invo_handle LIB$GET_INVO_HANDLE
     854  #endif
     855  
     856  /* Masks for facility identification. */
     857  #define FAC_MASK  		0x0fff0000
     858  #define DECADA_M_FACILITY	0x00310000
     859  
     860  /* Define macro symbols for the VMS conditions that become Ada exceptions.
     861     It would be better to just include <ssdef.h> */
     862  
     863  #define SS$_CONTINUE           1
     864  #define SS$_ACCVIO            12
     865  #define SS$_HPARITH         1284
     866  #define SS$_INTDIV          1156
     867  #define SS$_STKOVF          1364
     868  #define SS$_CONTROLC        1617
     869  #define SS$_RESIGNAL        2328
     870  
     871  #define MTH$_FLOOVEMAT   1475268       /* Some ACVC_21 CXA tests */
     872  
     873  /* The following codes must be resignalled, and not handled here. */
     874  
     875  /* These codes are in standard message libraries.  */
     876  extern int C$_SIGKILL;
     877  extern int C$_SIGINT;
     878  extern int SS$_DEBUG;
     879  extern int LIB$_KEYNOTFOU;
     880  extern int LIB$_ACTIMAGE;
     881  
     882  /* These codes are non standard, which is to say the author is
     883     not sure if they are defined in the standard message libraries
     884     so keep them as macros for now.  */
     885  #define RDB$_STREAM_EOF 20480426
     886  #define FDL$_UNPRIKW 11829410
     887  #define CMA$_EXIT_THREAD 4227492
     888  
     889  struct cond_sigargs
     890  {
     891    unsigned int sigarg;
     892    unsigned int sigargval;
     893  };
     894  
     895  struct cond_subtests
     896  {
     897    unsigned int num;
     898    const struct cond_sigargs sigargs[];
     899  };
     900  
     901  struct cond_except
     902  {
     903    unsigned int cond;
     904    const struct Exception_Data *except;
     905    unsigned int needs_adjust;  /* 1 = adjust PC,  0 = no adjust */
     906    const struct cond_subtests *subtests;
     907  };
     908  
     909  struct descriptor_s
     910  {
     911    unsigned short len, mbz;
     912    __char_ptr32 adr;
     913  };
     914  
     915  /* Conditions that don't have an Ada exception counterpart must raise
     916     Non_Ada_Error.  Since this is defined in s-auxdec, it should only be
     917     referenced by user programs, not the compiler or tools.  Hence the
     918     #ifdef IN_RTS.  */
     919  
     920  #ifdef IN_RTS
     921  
     922  #define Status_Error ada__io_exceptions__status_error
     923  extern struct Exception_Data Status_Error;
     924  
     925  #define Mode_Error ada__io_exceptions__mode_error
     926  extern struct Exception_Data Mode_Error;
     927  
     928  #define Name_Error ada__io_exceptions__name_error
     929  extern struct Exception_Data Name_Error;
     930  
     931  #define Use_Error ada__io_exceptions__use_error
     932  extern struct Exception_Data Use_Error;
     933  
     934  #define Device_Error ada__io_exceptions__device_error
     935  extern struct Exception_Data Device_Error;
     936  
     937  #define End_Error ada__io_exceptions__end_error
     938  extern struct Exception_Data End_Error;
     939  
     940  #define Data_Error ada__io_exceptions__data_error
     941  extern struct Exception_Data Data_Error;
     942  
     943  #define Layout_Error ada__io_exceptions__layout_error
     944  extern struct Exception_Data Layout_Error;
     945  
     946  #define Non_Ada_Error system__aux_dec__non_ada_error
     947  extern struct Exception_Data Non_Ada_Error;
     948  
     949  #define Coded_Exception system__vms_exception_table__coded_exception
     950  extern struct Exception_Data *Coded_Exception (void *);
     951  
     952  #define Base_Code_In system__vms_exception_table__base_code_in
     953  extern void *Base_Code_In (void *);
     954  
     955  /* DEC Ada exceptions are not defined in a header file, so they
     956     must be declared.  */
     957  
     958  #define ADA$_ALREADY_OPEN	0x0031a594
     959  #define ADA$_CONSTRAINT_ERRO	0x00318324
     960  #define ADA$_DATA_ERROR		0x003192c4
     961  #define ADA$_DEVICE_ERROR	0x003195e4
     962  #define ADA$_END_ERROR		0x00319904
     963  #define ADA$_FAC_MODE_MISMAT	0x0031a8b3
     964  #define ADA$_IOSYSFAILED	0x0031af04
     965  #define ADA$_KEYSIZERR		0x0031aa3c
     966  #define ADA$_KEY_MISMATCH	0x0031a8e3
     967  #define ADA$_LAYOUT_ERROR	0x00319c24
     968  #define ADA$_LINEXCMRS		0x0031a8f3
     969  #define ADA$_MAXLINEXC		0x0031a8eb
     970  #define ADA$_MODE_ERROR		0x00319f44
     971  #define ADA$_MRN_MISMATCH	0x0031a8db
     972  #define ADA$_MRS_MISMATCH	0x0031a8d3
     973  #define ADA$_NAME_ERROR		0x0031a264
     974  #define ADA$_NOT_OPEN		0x0031a58c
     975  #define ADA$_ORG_MISMATCH	0x0031a8bb
     976  #define ADA$_PROGRAM_ERROR	0x00318964
     977  #define ADA$_RAT_MISMATCH	0x0031a8cb
     978  #define ADA$_RFM_MISMATCH	0x0031a8c3
     979  #define ADA$_STAOVF		0x00318cac
     980  #define ADA$_STATUS_ERROR	0x0031a584
     981  #define ADA$_STORAGE_ERROR	0x00318c84
     982  #define ADA$_UNSUPPORTED	0x0031a8ab
     983  #define ADA$_USE_ERROR		0x0031a8a4
     984  
     985  /* DEC Ada specific conditions.  */
     986  static const struct cond_except dec_ada_cond_except_table [] =
     987  {
     988    {ADA$_PROGRAM_ERROR,   &program_error, 0, 0},
     989    {ADA$_USE_ERROR,       &Use_Error, 0, 0},
     990    {ADA$_KEYSIZERR,       &program_error, 0, 0},
     991    {ADA$_STAOVF,          &storage_error, 0, 0},
     992    {ADA$_CONSTRAINT_ERRO, &constraint_error, 0, 0},
     993    {ADA$_IOSYSFAILED,     &Device_Error, 0, 0},
     994    {ADA$_LAYOUT_ERROR,    &Layout_Error, 0, 0},
     995    {ADA$_STORAGE_ERROR,   &storage_error, 0, 0},
     996    {ADA$_DATA_ERROR,      &Data_Error, 0, 0},
     997    {ADA$_DEVICE_ERROR,    &Device_Error, 0, 0},
     998    {ADA$_END_ERROR,       &End_Error, 0, 0},
     999    {ADA$_MODE_ERROR,      &Mode_Error, 0, 0},
    1000    {ADA$_NAME_ERROR,      &Name_Error, 0, 0},
    1001    {ADA$_STATUS_ERROR,    &Status_Error, 0, 0},
    1002    {ADA$_NOT_OPEN,        &Use_Error, 0, 0},
    1003    {ADA$_ALREADY_OPEN,    &Use_Error, 0, 0},
    1004    {ADA$_USE_ERROR,       &Use_Error, 0, 0},
    1005    {ADA$_UNSUPPORTED,     &Use_Error, 0, 0},
    1006    {ADA$_FAC_MODE_MISMAT, &Use_Error, 0, 0},
    1007    {ADA$_ORG_MISMATCH,    &Use_Error, 0, 0},
    1008    {ADA$_RFM_MISMATCH,    &Use_Error, 0, 0},
    1009    {ADA$_RAT_MISMATCH,    &Use_Error, 0, 0},
    1010    {ADA$_MRS_MISMATCH,    &Use_Error, 0, 0},
    1011    {ADA$_MRN_MISMATCH,    &Use_Error, 0, 0},
    1012    {ADA$_KEY_MISMATCH,    &Use_Error, 0, 0},
    1013    {ADA$_MAXLINEXC,       &constraint_error, 0, 0},
    1014    {ADA$_LINEXCMRS,       &constraint_error, 0, 0},
    1015  
    1016  #if 0
    1017     /* Already handled by a pragma Import_Exception
    1018        in Aux_IO_Exceptions */
    1019    {ADA$_LOCK_ERROR,      &Lock_Error, 0, 0},
    1020    {ADA$_EXISTENCE_ERROR, &Existence_Error, 0, 0},
    1021    {ADA$_KEY_ERROR,       &Key_Error, 0, 0},
    1022  #endif
    1023  
    1024    {0,                    0, 0, 0}
    1025  };
    1026  
    1027  #endif /* IN_RTS */
    1028  
    1029  /* Non-DEC Ada specific conditions that map to Ada exceptions.  */
    1030  
    1031  /* Subtest for ACCVIO Constraint_Error, kept for compatibility,
    1032     in hindsight should have just made ACCVIO == Storage_Error.  */
    1033  #define ACCVIO_VIRTUAL_ADDR 3
    1034  static const struct cond_subtests accvio_c_e =
    1035  {1,  /* number of subtests below */
    1036    {
    1037       { ACCVIO_VIRTUAL_ADDR, 0 }
    1038     }
    1039  };
    1040  
    1041  /* Macro flag to adjust PC which gets off by one for some conditions,
    1042     not sure if this is reliably true, PC could be off by more for
    1043     HPARITH for example, unless a trapb is inserted. */
    1044  #define NEEDS_ADJUST 1
    1045  
    1046  static const struct cond_except system_cond_except_table [] =
    1047  {
    1048    {MTH$_FLOOVEMAT, &constraint_error, 0, 0},
    1049    {SS$_INTDIV,     &constraint_error, 0, 0},
    1050    {SS$_HPARITH,    &constraint_error, NEEDS_ADJUST, 0},
    1051    {SS$_ACCVIO,     &constraint_error, NEEDS_ADJUST, &accvio_c_e},
    1052    {SS$_ACCVIO,     &storage_error,    NEEDS_ADJUST, 0},
    1053    {SS$_STKOVF,     &storage_error,    NEEDS_ADJUST, 0},
    1054    {0,               0, 0, 0}
    1055  };
    1056  
    1057  /* To deal with VMS conditions and their mapping to Ada exceptions,
    1058     the __gnat_error_handler routine below is installed as an exception
    1059     vector having precedence over DEC frame handlers.  Some conditions
    1060     still need to be handled by such handlers, however, in which case
    1061     __gnat_error_handler needs to return SS$_RESIGNAL.  Consider for
    1062     instance the use of a third party library compiled with DECAda and
    1063     performing its own exception handling internally.
    1064  
    1065     To allow some user-level flexibility, which conditions should be
    1066     resignaled is controlled by a predicate function, provided with the
    1067     condition value and returning a boolean indication stating whether
    1068     this condition should be resignaled or not.
    1069  
    1070     That predicate function is called indirectly, via a function pointer,
    1071     by __gnat_error_handler, and changing that pointer is allowed to the
    1072     user code by way of the __gnat_set_resignal_predicate interface.
    1073  
    1074     The user level function may then implement what it likes, including
    1075     for instance the maintenance of a dynamic data structure if the set
    1076     of to be resignalled conditions has to change over the program's
    1077     lifetime.
    1078  
    1079     ??? This is not a perfect solution to deal with the possible
    1080     interactions between the GNAT and the DECAda exception handling
    1081     models and better (more general) schemes are studied.  This is so
    1082     just provided as a convenient workaround in the meantime, and
    1083     should be use with caution since the implementation has been kept
    1084     very simple.  */
    1085  
    1086  typedef int resignal_predicate (int code);
    1087  
    1088  static const int * const cond_resignal_table [] =
    1089  {
    1090    &C$_SIGKILL,
    1091    (int *)CMA$_EXIT_THREAD,
    1092    &SS$_DEBUG,
    1093    &LIB$_KEYNOTFOU,
    1094    &LIB$_ACTIMAGE,
    1095    (int *) RDB$_STREAM_EOF,
    1096    (int *) FDL$_UNPRIKW,
    1097    0
    1098  };
    1099  
    1100  static const int facility_resignal_table [] =
    1101  {
    1102    0x1380000, /* RDB */
    1103    0x2220000, /* SQL */
    1104    0
    1105  };
    1106  
    1107  /* Default GNAT predicate for resignaling conditions.  */
    1108  
    1109  static int
    1110  __gnat_default_resignal_p (int code)
    1111  {
    1112    int i, iexcept;
    1113  
    1114    for (i = 0; facility_resignal_table [i]; i++)
    1115      if ((code & FAC_MASK) == facility_resignal_table [i])
    1116        return 1;
    1117  
    1118    for (i = 0, iexcept = 0;
    1119         cond_resignal_table [i]
    1120  	&& !(iexcept = LIB$MATCH_COND (&code, &cond_resignal_table [i]));
    1121         i++);
    1122  
    1123    return iexcept;
    1124  }
    1125  
    1126  /* Static pointer to predicate that the __gnat_error_handler exception
    1127     vector invokes to determine if it should resignal a condition.  */
    1128  
    1129  static resignal_predicate *__gnat_resignal_p = __gnat_default_resignal_p;
    1130  
    1131  /* User interface to change the predicate pointer to PREDICATE. Reset to
    1132     the default if PREDICATE is null.  */
    1133  
    1134  void
    1135  __gnat_set_resignal_predicate (resignal_predicate *predicate)
    1136  {
    1137    if (predicate == NULL)
    1138      __gnat_resignal_p = __gnat_default_resignal_p;
    1139    else
    1140      __gnat_resignal_p = predicate;
    1141  }
    1142  
    1143  /* Should match System.Parameters.Default_Exception_Msg_Max_Length.  */
    1144  #define Default_Exception_Msg_Max_Length 512
    1145  
    1146  /* Action routine for SYS$PUTMSG. There may be multiple
    1147     conditions, each with text to be appended to MESSAGE
    1148     and separated by line termination.  */
    1149  static int
    1150  copy_msg (struct descriptor_s *msgdesc, char *message)
    1151  {
    1152    int len = strlen (message);
    1153    int copy_len;
    1154  
    1155    /* Check for buffer overflow and skip.  */
    1156    if (len > 0 && len <= Default_Exception_Msg_Max_Length - 3)
    1157      {
    1158        strcat (message, "\r\n");
    1159        len += 2;
    1160      }
    1161  
    1162    /* Check for buffer overflow and truncate if necessary.  */
    1163    copy_len = (len + msgdesc->len <= Default_Exception_Msg_Max_Length - 1 ?
    1164  	      msgdesc->len :
    1165  	      Default_Exception_Msg_Max_Length - 1 - len);
    1166    strncpy (&message [len], msgdesc->adr, copy_len);
    1167    message [len + copy_len] = 0;
    1168  
    1169    return 0;
    1170  }
    1171  
    1172  /* Scan TABLE for a match for the condition contained in SIGARGS,
    1173     and return the entry, or the empty entry if no match found.  */
    1174  static const struct cond_except *
    1175  scan_conditions ( int *sigargs, const struct cond_except *table [])
    1176  {
    1177    int i;
    1178    struct cond_except entry;
    1179  
    1180    /* Scan the exception condition table for a match and fetch
    1181       the associated GNAT exception pointer.  */
    1182    for (i = 0; (*table) [i].cond; i++)
    1183      {
    1184        unsigned int match = LIB$MATCH_COND (&sigargs [1], &(*table) [i].cond);
    1185        const struct cond_subtests *subtests  = (*table) [i].subtests;
    1186  
    1187        if (match)
    1188  	{
    1189  	  if (!subtests)
    1190  	    {
    1191  	      return &(*table) [i];
    1192  	    }
    1193  	  else
    1194  	    {
    1195  	      unsigned int ii;
    1196  	      int num = (*subtests).num;
    1197  
    1198  	      /* Perform subtests to differentiate exception.  */
    1199  	      for (ii = 0; ii < num; ii++)
    1200  		{
    1201  		  unsigned int arg = (*subtests).sigargs [ii].sigarg;
    1202  		  unsigned int argval = (*subtests).sigargs [ii].sigargval;
    1203  
    1204  		  if (sigargs [arg] != argval)
    1205  		    {
    1206  		      num = 0;
    1207  		      break;
    1208  		    }
    1209  		}
    1210  
    1211  	      /* All subtests passed.  */
    1212  	      if (num == (*subtests).num)
    1213  	        return &(*table) [i];
    1214  	    }
    1215  	}
    1216      }
    1217  
    1218      /* No match, return the null terminating entry.  */
    1219      return &(*table) [i];
    1220  }
    1221  
    1222  /* __gnat_handle_vms_condtition is both a frame based handler
    1223     for the runtime, and an exception vector for the compiler.  */
    1224  long
    1225  __gnat_handle_vms_condition (int *sigargs, void *mechargs)
    1226  {
    1227    struct Exception_Data *exception = 0;
    1228    unsigned int needs_adjust = 0;
    1229    void *base_code;
    1230    struct descriptor_s gnat_facility = {4, 0, "GNAT"};
    1231    char message [Default_Exception_Msg_Max_Length];
    1232  
    1233    const char *msg = "";
    1234  
    1235    /* Check for conditions to resignal which aren't effected by pragma
    1236       Import_Exception.  */
    1237    if (__gnat_resignal_p (sigargs [1]))
    1238      return SS$_RESIGNAL;
    1239  #ifndef IN_RTS
    1240    /* toplev.cc handles this for compiler.  */
    1241    if (sigargs [1] == SS$_HPARITH)
    1242      return SS$_RESIGNAL;
    1243  #endif
    1244  
    1245  #ifdef IN_RTS
    1246    /* See if it's an imported exception.  Beware that registered exceptions
    1247       are bound to their base code, with the severity bits masked off.  */
    1248    base_code = Base_Code_In ((void *) sigargs[1]);
    1249    exception = Coded_Exception (base_code);
    1250  #endif
    1251  
    1252    if (exception == 0)
    1253  #ifdef IN_RTS
    1254      {
    1255        int i;
    1256        struct cond_except cond;
    1257        const struct cond_except *cond_table;
    1258        const struct cond_except *cond_tables [] = {dec_ada_cond_except_table,
    1259  					          system_cond_except_table,
    1260  					          0};
    1261        unsigned int ctrlc = SS$_CONTROLC;
    1262        unsigned int *sigint = &C$_SIGINT;
    1263        int ctrlc_match = LIB$MATCH_COND (&sigargs [1], &ctrlc);
    1264        int sigint_match = LIB$MATCH_COND (&sigargs [1], &sigint);
    1265  
    1266        extern int SYS$DCLAST (void (*astadr)(), unsigned long long astprm,
    1267  	                     unsigned int acmode);
    1268  
    1269        /* If SS$_CONTROLC has been imported as an exception, it will take
    1270  	 priority over a Ctrl/C handler.  See above.  SIGINT has a
    1271  	 different condition value due to it's DECCCRTL roots and it's
    1272  	 the condition that gets raised for a "kill -INT".  */
    1273        if ((ctrlc_match || sigint_match) && __gnat_ctrl_c_handler)
    1274  	{
    1275  	  SYS$DCLAST (__gnat_ctrl_c_handler, 0, 0);
    1276  	  return SS$_CONTINUE;
    1277  	}
    1278  
    1279        i = 0;
    1280        while ((cond_table = cond_tables[i++]) && !exception)
    1281  	{
    1282  	  cond = *scan_conditions (sigargs, &cond_table);
    1283  	  exception = (struct Exception_Data *) cond.except;
    1284  	}
    1285  
    1286        if (exception)
    1287  	needs_adjust = cond.needs_adjust;
    1288        else
    1289  	/* User programs expect Non_Ada_Error to be raised if no match,
    1290  	   reference DEC Ada test CXCONDHAN.  */
    1291  	exception = &Non_Ada_Error;
    1292        }
    1293  #else
    1294      {
    1295        /* Pretty much everything is just a program error in the compiler */
    1296        exception = &program_error;
    1297      }
    1298  #endif
    1299  
    1300    message[0] = 0;
    1301    /* Subtract PC & PSL fields as per ABI for SYS$PUTMSG.  */
    1302    sigargs[0] -= 2;
    1303  
    1304    extern int SYS$PUTMSG (void *, int (*)(), void *, unsigned long long);
    1305  
    1306    /* If it was a DEC Ada specific condtiion, make it GNAT otherwise
    1307       keep the old facility.  */
    1308    if ((sigargs [1] & FAC_MASK) == DECADA_M_FACILITY)
    1309      SYS$PUTMSG (sigargs, copy_msg, &gnat_facility,
    1310  	        (unsigned long long ) message);
    1311    else
    1312      SYS$PUTMSG (sigargs, copy_msg, 0,
    1313  	        (unsigned long long ) message);
    1314  
    1315    /* Add back PC & PSL fields as per ABI for SYS$PUTMSG.  */
    1316    sigargs[0] += 2;
    1317    msg = message;
    1318  
    1319    if (needs_adjust)
    1320      __gnat_adjust_context_for_raise (sigargs [1], (void *)mechargs);
    1321  
    1322    Raise_From_Signal_Handler (exception, msg);
    1323  }
    1324  
    1325  #if defined (IN_RTS) && defined (__IA64)
    1326  /* Called only from adasigio.b32.  This is a band aid to avoid going
    1327     through the VMS signal handling code which results in a 0x8000 per
    1328     handled exception memory leak in P2 space (see VMS source listing
    1329     sys/lis/exception.lis) due to the allocation of working space that
    1330     is expected to be deallocated upon return from the condition handler,
    1331     which doesn't return in GNAT compiled code.  */
    1332  void
    1333  GNAT$STOP (int *sigargs)
    1334  {
    1335     /* Note that there are no mechargs. We rely on the fact that condtions
    1336        raised from DEClib I/O do not require an "adjust".  Also the count
    1337        will be off by 2, since LIB$STOP didn't get a chance to add the
    1338        PC and PSL fields, so we bump it so PUTMSG comes out right.  */
    1339     sigargs [0] += 2;
    1340     __gnat_handle_vms_condition (sigargs, 0);
    1341  }
    1342  #endif
    1343  
    1344  void
    1345  __gnat_install_handler (void)
    1346  {
    1347    long prvhnd ATTRIBUTE_UNUSED;
    1348  
    1349  #if !defined (IN_RTS)
    1350    extern int SYS$SETEXV (unsigned int vector, int (*addres)(),
    1351  	                 unsigned int accmode, void *(*(prvhnd)));
    1352    SYS$SETEXV (1, __gnat_handle_vms_condition, 3, &prvhnd);
    1353  #endif
    1354  
    1355    __gnat_handler_installed = 1;
    1356  }
    1357  
    1358  /* __gnat_adjust_context_for_raise for Alpha - see comments along with the
    1359     default version later in this file.  */
    1360  
    1361  #if defined (IN_RTS) && defined (__alpha__)
    1362  
    1363  #include <vms/chfctxdef.h>
    1364  #include <vms/chfdef.h>
    1365  
    1366  #define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
    1367  
    1368  void
    1369  __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
    1370  {
    1371    if (signo == SS$_HPARITH)
    1372      {
    1373        /* Sub one to the address of the instruction signaling the condition,
    1374  	 located in the sigargs array.  */
    1375  
    1376        CHF$MECH_ARRAY * mechargs = (CHF$MECH_ARRAY *) ucontext;
    1377        CHF$SIGNAL_ARRAY * sigargs
    1378  	= (CHF$SIGNAL_ARRAY *) mechargs->chf$q_mch_sig_addr;
    1379  
    1380        int vcount = sigargs->chf$is_sig_args;
    1381        int * pc_slot = & (&sigargs->chf$l_sig_name)[vcount-2];
    1382  
    1383        (*pc_slot)--;
    1384      }
    1385  }
    1386  
    1387  #endif
    1388  
    1389  /* __gnat_adjust_context_for_raise for ia64.  */
    1390  
    1391  #if defined (IN_RTS) && defined (__IA64)
    1392  
    1393  #include <vms/chfctxdef.h>
    1394  #include <vms/chfdef.h>
    1395  
    1396  #define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
    1397  
    1398  typedef unsigned long long u64;
    1399  
    1400  void
    1401  __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
    1402  {
    1403    /* Add one to the address of the instruction signaling the condition,
    1404       located in the 64bits sigargs array.  */
    1405  
    1406    CHF$MECH_ARRAY * mechargs = (CHF$MECH_ARRAY *) ucontext;
    1407  
    1408    CHF64$SIGNAL_ARRAY *chfsig64
    1409      = (CHF64$SIGNAL_ARRAY *) mechargs->chf$ph_mch_sig64_addr;
    1410  
    1411    u64 * post_sigarray
    1412      = (u64 *)chfsig64 + 1 + chfsig64->chf64$l_sig_args;
    1413  
    1414    u64 * ih_pc_loc = post_sigarray - 2;
    1415  
    1416    (*ih_pc_loc) ++;
    1417  }
    1418  
    1419  #endif
    1420  
    1421  /* Easier interface for LIB$GET_LOGICAL: put the equivalence of NAME into BUF,
    1422     always NUL terminated.  In case of error or if the result is longer than
    1423     LEN (length of BUF) an empty string is written info BUF.  */
    1424  
    1425  static void
    1426  __gnat_vms_get_logical (const char *name, char *buf, int len)
    1427  {
    1428    struct descriptor_s name_desc, result_desc;
    1429    int status;
    1430    unsigned short rlen;
    1431  
    1432    /* Build the descriptor for NAME.  */
    1433    name_desc.len = strlen (name);
    1434    name_desc.mbz = 0;
    1435    name_desc.adr = (char *)name;
    1436  
    1437    /* Build the descriptor for the result.  */
    1438    result_desc.len = len;
    1439    result_desc.mbz = 0;
    1440    result_desc.adr = buf;
    1441  
    1442    status = LIB$GET_LOGICAL (&name_desc, &result_desc, &rlen);
    1443  
    1444    if ((status & 1) == 1 && rlen < len)
    1445      buf[rlen] = 0;
    1446    else
    1447      buf[0] = 0;
    1448  }
    1449  
    1450  /* Size of a page on ia64 and alpha VMS.  */
    1451  #define VMS_PAGESIZE 8192
    1452  
    1453  /* User mode.  */
    1454  #define PSL__C_USER 3
    1455  
    1456  /* No access.  */
    1457  #define PRT__C_NA 0
    1458  
    1459  /* Descending region.  */
    1460  #define VA__M_DESCEND 1
    1461  
    1462  /* Get by virtual address.  */
    1463  #define VA___REGSUM_BY_VA 1
    1464  
    1465  /* Memory region summary.  */
    1466  struct regsum
    1467  {
    1468    unsigned long long q_region_id;
    1469    unsigned int l_flags;
    1470    unsigned int l_region_protection;
    1471    void *pq_start_va;
    1472    unsigned long long q_region_size;
    1473    void *pq_first_free_va;
    1474  };
    1475  
    1476  extern int SYS$GET_REGION_INFO (unsigned int, unsigned long long *,
    1477  	                        void *, void *, unsigned int,
    1478  	                        void *, unsigned int *);
    1479  extern int SYS$EXPREG_64 (unsigned long long *, unsigned long long,
    1480  	                  unsigned int, unsigned int, void **,
    1481  	                  unsigned long long *);
    1482  extern int SYS$SETPRT_64 (void *, unsigned long long, unsigned int,
    1483  	                  unsigned int, void **, unsigned long long *,
    1484  	                  unsigned int *);
    1485  
    1486  /* Add a guard page in the memory region containing ADDR at ADDR +/- SIZE.
    1487     (The sign depends on the kind of the memory region).  */
    1488  
    1489  static int
    1490  __gnat_set_stack_guard_page (void *addr, unsigned long size)
    1491  {
    1492    int status;
    1493    void *ret_va;
    1494    unsigned long long ret_len;
    1495    unsigned int ret_prot;
    1496    void *start_va;
    1497    unsigned long long length;
    1498    unsigned int retlen;
    1499    struct regsum buffer;
    1500  
    1501    /* Get the region for ADDR.  */
    1502    status = SYS$GET_REGION_INFO
    1503      (VA___REGSUM_BY_VA, NULL, addr, NULL, sizeof (buffer), &buffer, &retlen);
    1504  
    1505    if ((status & 1) != 1)
    1506      return -1;
    1507  
    1508    /* Extend the region.  */
    1509    status = SYS$EXPREG_64 (&buffer.q_region_id,
    1510  	                  size, 0, 0, &start_va, &length);
    1511  
    1512    if ((status & 1) != 1)
    1513      return -1;
    1514  
    1515    /* Create a guard page.  */
    1516    if (!(buffer.l_flags & VA__M_DESCEND))
    1517      start_va = (void *)((unsigned long long)start_va + length - VMS_PAGESIZE);
    1518  
    1519    status = SYS$SETPRT_64 (start_va, VMS_PAGESIZE, PSL__C_USER, PRT__C_NA,
    1520  	                  &ret_va, &ret_len, &ret_prot);
    1521  
    1522    if ((status & 1) != 1)
    1523      return -1;
    1524    return 0;
    1525  }
    1526  
    1527  /* Read logicals to limit the stack(s) size.  */
    1528  
    1529  static void
    1530  __gnat_set_stack_limit (void)
    1531  {
    1532  #ifdef __ia64__
    1533    void *sp;
    1534    unsigned long size;
    1535    char value[16];
    1536    char *e;
    1537  
    1538    /* The main stack.  */
    1539    __gnat_vms_get_logical ("GNAT_STACK_SIZE", value, sizeof (value));
    1540    size = strtoul (value, &e, 0);
    1541    if (e > value && *e == 0)
    1542      {
    1543        asm ("mov %0=sp" : "=r" (sp));
    1544        __gnat_set_stack_guard_page (sp, size * 1024);
    1545      }
    1546  
    1547    /* The register stack.  */
    1548    __gnat_vms_get_logical ("GNAT_RBS_SIZE", value, sizeof (value));
    1549    size = strtoul (value, &e, 0);
    1550    if (e > value && *e == 0)
    1551      {
    1552        asm ("mov %0=ar.bsp" : "=r" (sp));
    1553        __gnat_set_stack_guard_page (sp, size * 1024);
    1554      }
    1555  #endif
    1556  }
    1557  
    1558  #ifdef IN_RTS
    1559  extern int SYS$IEEE_SET_FP_CONTROL (void *, void *, void *);
    1560  #define K_TRUE 1
    1561  #define __int64 long long
    1562  #define __NEW_STARLET
    1563  #include <vms/ieeedef.h>
    1564  #endif
    1565  
    1566  /* Feature logical name and global variable address pair.
    1567     If we ever add another feature logical to this list, the
    1568     feature struct will need to be enhanced to take into account
    1569     possible values for *gl_addr.  */
    1570  struct feature {
    1571    const char *name;
    1572    int *gl_addr;
    1573  };
    1574  
    1575  /* Default values for GNAT features set by environment or binder.  */
    1576  int __gl_heap_size = 64;
    1577  
    1578  /* Default float format is 'I' meaning IEEE.  If gnatbind detetcts that a
    1579     VAX Float format is specified, it will set this global variable to 'V'.
    1580     Subsequently __gnat_set_features will test the variable and if set for
    1581     VAX Float will call a Starlet function to enable trapping for invalid
    1582     operation, drivide by zero, and overflow. This will prevent the VMS runtime
    1583     (specifically OTS$CHECK_FP_MODE) from complaining about inconsistent
    1584     floating point settings in a mixed language program. Ideally the setting
    1585     would be determined at link time based on settings in the object files,
    1586     however the VMS linker seems to take the setting from the first object
    1587     in the link, e.g. pcrt0.o which is float representation neutral.  */
    1588  char __gl_float_format = 'I';
    1589  
    1590  /* Array feature logical names and global variable addresses.  */
    1591  static const struct feature features[] =
    1592  {
    1593    {"GNAT$NO_MALLOC_64", &__gl_heap_size},
    1594    {0, 0}
    1595  };
    1596  
    1597  void
    1598  __gnat_set_features (void)
    1599  {
    1600    int i;
    1601    char buff[16];
    1602  #ifdef IN_RTS
    1603    IEEE clrmsk, setmsk, prvmsk;
    1604  
    1605    clrmsk.ieee$q_flags = 0LL;
    1606    setmsk.ieee$q_flags = 0LL;
    1607  #endif
    1608  
    1609    /* Loop through features array and test name for enable/disable.  */
    1610    for (i = 0; features[i].name; i++)
    1611      {
    1612        __gnat_vms_get_logical (features[i].name, buff, sizeof (buff));
    1613  
    1614        if (strcmp (buff, "ENABLE") == 0
    1615  	  || strcmp (buff, "TRUE") == 0
    1616  	  || strcmp (buff, "1") == 0)
    1617  	*features[i].gl_addr = 32;
    1618        else if (strcmp (buff, "DISABLE") == 0
    1619  	       || strcmp (buff, "FALSE") == 0
    1620  	       || strcmp (buff, "0") == 0)
    1621  	*features[i].gl_addr = 64;
    1622      }
    1623  
    1624    /* Features to artificially limit the stack size.  */
    1625    __gnat_set_stack_limit ();
    1626  
    1627  #ifdef IN_RTS
    1628    if (__gl_float_format == 'V')
    1629      {
    1630        setmsk.ieee$v_trap_enable_inv = K_TRUE;
    1631        setmsk.ieee$v_trap_enable_dze = K_TRUE;
    1632        setmsk.ieee$v_trap_enable_ovf = K_TRUE;
    1633        SYS$IEEE_SET_FP_CONTROL (&clrmsk, &setmsk, &prvmsk);
    1634      }
    1635  #endif
    1636  
    1637    __gnat_features_set = 1;
    1638  }
    1639  
    1640  /* Return true if the VMS version is 7.x.  */
    1641  
    1642  extern unsigned int LIB$GETSYI (int *, ...);
    1643  
    1644  #define SYI$_VERSION 0x1000
    1645  
    1646  int
    1647  __gnat_is_vms_v7 (void)
    1648  {
    1649    struct descriptor_s desc;
    1650    char version[8];
    1651    int status;
    1652    int code = SYI$_VERSION;
    1653  
    1654    desc.len = sizeof (version);
    1655    desc.mbz = 0;
    1656    desc.adr = version;
    1657  
    1658    status = LIB$GETSYI (&code, 0, &desc);
    1659    if ((status & 1) == 1 && version[1] == '7' && version[2] == '.')
    1660      return 1;
    1661    else
    1662      return 0;
    1663  }
    1664  
    1665  /*******************/
    1666  /* FreeBSD Section */
    1667  /*******************/
    1668  
    1669  #elif defined (__FreeBSD__) || defined (__DragonFly__)
    1670  
    1671  #include <signal.h>
    1672  #include <sys/ucontext.h>
    1673  #include <unistd.h>
    1674  
    1675  static void
    1676  __gnat_error_handler (int sig,
    1677  		      siginfo_t *si ATTRIBUTE_UNUSED,
    1678  		      void *ucontext ATTRIBUTE_UNUSED)
    1679  {
    1680    struct Exception_Data *exception;
    1681    const char *msg;
    1682  
    1683    switch (sig)
    1684      {
    1685      case SIGFPE:
    1686        exception = &constraint_error;
    1687        msg = "SIGFPE";
    1688        break;
    1689  
    1690      case SIGILL:
    1691        exception = &constraint_error;
    1692        msg = "SIGILL";
    1693        break;
    1694  
    1695      case SIGSEGV:
    1696        exception = &storage_error;
    1697        msg = "stack overflow or erroneous memory access";
    1698        break;
    1699  
    1700      case SIGBUS:
    1701        exception = &storage_error;
    1702        msg = "SIGBUS: possible stack overflow";
    1703        break;
    1704  
    1705      default:
    1706        exception = &program_error;
    1707        msg = "unhandled signal";
    1708      }
    1709  
    1710    Raise_From_Signal_Handler (exception, msg);
    1711  }
    1712  
    1713  void
    1714  __gnat_install_handler (void)
    1715  {
    1716    struct sigaction act;
    1717  
    1718    /* Set up signal handler to map synchronous signals to appropriate
    1719       exceptions.  Make sure that the handler isn't interrupted by another
    1720       signal that might cause a scheduling event!  */
    1721  
    1722    act.sa_sigaction
    1723      = (void (*)(int, struct __siginfo *, void*)) __gnat_error_handler;
    1724    act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
    1725    (void) sigemptyset (&act.sa_mask);
    1726  
    1727    (void) sigaction (SIGILL,  &act, NULL);
    1728    (void) sigaction (SIGFPE,  &act, NULL);
    1729    (void) sigaction (SIGSEGV, &act, NULL);
    1730    (void) sigaction (SIGBUS,  &act, NULL);
    1731  
    1732    __gnat_handler_installed = 1;
    1733  }
    1734  
    1735  /*************************************/
    1736  /* VxWorks Section (including Vx653) */
    1737  /*************************************/
    1738  
    1739  #elif defined(__vxworks)
    1740  
    1741  #include <signal.h>
    1742  #include <taskLib.h>
    1743  #if (defined (__i386__) || defined (__x86_64__)) && !defined (VTHREADS)
    1744  #include <sysLib.h>
    1745  #endif
    1746  
    1747  #include "sigtramp.h"
    1748  
    1749  #ifndef __RTP__
    1750  #include <intLib.h>
    1751  #include <iv.h>
    1752  #endif
    1753  
    1754  #if ((defined (ARMEL) && (_WRS_VXWORKS_MAJOR == 6))) && !defined(__RTP__)
    1755  #define VXWORKS_FORCE_GUARD_PAGE 1
    1756  #include <vmLib.h>
    1757  extern size_t vxIntStackOverflowSize;
    1758  #define INT_OVERFLOW_SIZE vxIntStackOverflowSize
    1759  #endif
    1760  
    1761  /* VxWorks 653 vThreads expects the field excCnt to be zeroed when a signal is.
    1762     handled.  The VxWorks version of longjmp does this; GCC's builtin_longjmp
    1763     doesn't.  A similar issue is present VxWorks 7.2 and affects ZCX as well
    1764     as builtin_longjmp.  This field only exists in Kernel mode, not RTP.  */
    1765  #if defined(VTHREADS) || (!defined(__RTP__) && (_WRS_VXWORKS_MAJOR >= 7))
    1766  # ifdef VTHREADS
    1767  #  include "private/vThreadsP.h"
    1768  #  define EXCCNT vThreads.excCnt
    1769  # else
    1770  #  include "private/taskLibP.h"
    1771  #  define EXCCNT excCnt
    1772  # endif
    1773  # define CLEAR_EXCEPTION_COUNT()			 \
    1774    do							 \
    1775      {							 \
    1776        WIND_TCB *currentTask = (WIND_TCB *) taskIdSelf(); \
    1777        currentTask->EXCCNT = 0;				 \
    1778      } while (0)
    1779  #else
    1780  # define CLEAR_EXCEPTION_COUNT()
    1781  #endif
    1782  
    1783  #ifndef __RTP__
    1784  
    1785  /* Directly vectored Interrupt routines are not supported when using RTPs.  */
    1786  
    1787  extern void * __gnat_inum_to_ivec (int);
    1788  
    1789  /* This is needed by the GNAT run time to handle Vxworks interrupts.  */
    1790  void *
    1791  __gnat_inum_to_ivec (int num)
    1792  {
    1793    return (void *) INUM_TO_IVEC (num);
    1794  }
    1795  #endif
    1796  
    1797  #if !defined(__alpha_vxworks) && ((_WRS_VXWORKS_MAJOR != 6) && (_WRS_VXWORKS_MAJOR != 7)) && !defined(__RTP__)
    1798  
    1799  /* getpid is used by s-parint.adb, but is not defined by VxWorks, except
    1800     on Alpha VxWorks and VxWorks 6.x (including RTPs).  */
    1801  
    1802  extern long getpid (void);
    1803  
    1804  long
    1805  getpid (void)
    1806  {
    1807    return taskIdSelf ();
    1808  }
    1809  #endif
    1810  
    1811  /* When stack checking is performed by probing a guard page on the stack,
    1812     sometimes this guard page is not properly reset on VxWorks. We need to
    1813     manually reset it in this case.
    1814     This function returns TRUE in case the guard page was hit by the
    1815     signal. */
    1816  static int
    1817  __gnat_reset_guard_page (int sig)
    1818  {
    1819    /* On ARM VxWorks 6.x and x86_64 VxWorks 7, the guard page is left un-armed
    1820       by the kernel after being violated, so subsequent violations aren't
    1821       detected.
    1822       So we retrieve the address of the guard page from the TCB and compare it
    1823       with the page that is violated and re-arm that page if there's a match. */
    1824  #if defined (VXWORKS_FORCE_GUARD_PAGE)
    1825  
    1826    /* Ignore signals that are not stack overflow signals */
    1827    if (sig != SIGSEGV && sig != SIGBUS && sig != SIGILL) return FALSE;
    1828  
    1829    /* If the target does not support guard pages, INT_OVERFLOW_SIZE will be 0 */
    1830    if (INT_OVERFLOW_SIZE == 0) return FALSE;
    1831  
    1832    TASK_ID tid           = taskIdSelf ();
    1833    WIND_TCB *pTcb        = taskTcb (tid);
    1834    VIRT_ADDR guardPage   = (VIRT_ADDR) pTcb->pStackEnd - INT_OVERFLOW_SIZE;
    1835    UINT stateMask        = VM_STATE_MASK_VALID;
    1836    UINT guardState       = VM_STATE_VALID_NOT;
    1837  
    1838  #if (_WRS_VXWORKS_MAJOR >= 7)
    1839    stateMask  |= MMU_ATTR_SPL_MSK;
    1840    guardState |= MMU_ATTR_NO_BLOCK;
    1841  #endif
    1842  
    1843    UINT nState;
    1844    vmStateGet (NULL, guardPage, &nState);
    1845    if ((nState & VM_STATE_MASK_VALID) != VM_STATE_VALID_NOT)
    1846      {
    1847        /* If the guard page has a valid state, we need to reset to
    1848           invalid state here */
    1849        vmStateSet (NULL, guardPage, INT_OVERFLOW_SIZE, stateMask, guardState);
    1850        return TRUE;
    1851      }
    1852  #endif /* VXWORKS_FORCE_GUARD_PAGE */
    1853    return FALSE;
    1854  }
    1855  
    1856  /* Handle different SIGnal to exception mappings in different VxWorks
    1857     versions.  */
    1858  void
    1859  __gnat_map_signal (int sig,
    1860                     siginfo_t *si ATTRIBUTE_UNUSED,
    1861                     void *sc ATTRIBUTE_UNUSED)
    1862  {
    1863    struct Exception_Data *exception;
    1864    const char *msg;
    1865  
    1866    switch (sig)
    1867      {
    1868      case SIGFPE:
    1869        exception = &constraint_error;
    1870        msg = "SIGFPE";
    1871        break;
    1872  #ifdef VTHREADS
    1873  #ifdef __VXWORKSMILS__
    1874      case SIGILL:
    1875        exception = &storage_error;
    1876        msg = "SIGILL: possible stack overflow";
    1877        break;
    1878      case SIGSEGV:
    1879        exception = &storage_error;
    1880        msg = "SIGSEGV";
    1881        break;
    1882      case SIGBUS:
    1883        exception = &program_error;
    1884        msg = "SIGBUS";
    1885        break;
    1886  #else
    1887      case SIGILL:
    1888        exception = &constraint_error;
    1889        msg = "Floating point exception or SIGILL";
    1890        break;
    1891      case SIGSEGV:
    1892        exception = &storage_error;
    1893        msg = "SIGSEGV";
    1894        break;
    1895      case SIGBUS:
    1896        exception = &storage_error;
    1897        msg = "SIGBUS: possible stack overflow";
    1898        break;
    1899  #endif
    1900  #elif (_WRS_VXWORKS_MAJOR >= 6)
    1901      case SIGILL:
    1902        exception = &constraint_error;
    1903        msg = "SIGILL";
    1904        break;
    1905  #ifdef __RTP__
    1906      /* In RTP mode a SIGSEGV is most likely due to a stack overflow,
    1907         since stack checking uses the probing mechanism.  */
    1908      case SIGSEGV:
    1909        exception = &storage_error;
    1910        msg = "SIGSEGV: possible stack overflow";
    1911        break;
    1912      case SIGBUS:
    1913        exception = &program_error;
    1914        msg = "SIGBUS";
    1915        break;
    1916  #else
    1917        /* VxWorks 6 kernel mode with probing. SIGBUS for guard page hit */
    1918      case SIGSEGV:
    1919        exception = &storage_error;
    1920        msg = "SIGSEGV";
    1921        break;
    1922      case SIGBUS:
    1923        exception = &storage_error;
    1924        msg = "SIGBUS: possible stack overflow";
    1925        break;
    1926  #endif
    1927  #else
    1928      /* VxWorks 5: a SIGILL is most likely due to a stack overflow,
    1929         since stack checking uses the stack limit mechanism.  */
    1930      case SIGILL:
    1931        exception = &storage_error;
    1932        msg = "SIGILL: possible stack overflow";
    1933        break;
    1934      case SIGSEGV:
    1935        exception = &storage_error;
    1936        msg = "SIGSEGV";
    1937        break;
    1938      case SIGBUS:
    1939        exception = &program_error;
    1940        msg = "SIGBUS";
    1941        break;
    1942  #endif
    1943      default:
    1944        exception = &program_error;
    1945        msg = "unhandled signal";
    1946      }
    1947  
    1948    if (__gnat_reset_guard_page (sig))
    1949      {
    1950        /* Set the exception message: we know for sure that we have a
    1951           stack overflow here */
    1952        exception = &storage_error;
    1953  
    1954        switch (sig)
    1955          {
    1956          case SIGSEGV:
    1957            msg = "SIGSEGV: stack overflow";
    1958            break;
    1959          case SIGBUS:
    1960            msg = "SIGBUS: stack overflow";
    1961            break;
    1962          case SIGILL:
    1963            msg = "SIGILL: stack overflow";
    1964            break;
    1965          }
    1966      }
    1967  
    1968    CLEAR_EXCEPTION_COUNT ();
    1969    Raise_From_Signal_Handler (exception, msg);
    1970  }
    1971  
    1972  #if defined (ARMEL) && (_WRS_VXWORKS_MAJOR >= 7) && !defined (__aarch64__)
    1973  
    1974  /* ARM-vx7 case with arm unwinding exceptions */
    1975  #define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
    1976  
    1977  #include <arch/../regs.h>
    1978  #ifndef __RTP__
    1979  #include <sigLib.h>
    1980  #else
    1981  #include <signal.h>
    1982  #include <regs.h>
    1983  #include <ucontext.h>
    1984  #endif /* __RTP__ */
    1985  
    1986  void
    1987  __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED,
    1988  				 void *sc ATTRIBUTE_UNUSED)
    1989  {
    1990    /* In case of ARM exceptions, the registers context have the PC pointing
    1991       to the instruction that raised the signal.  However the unwinder expects
    1992       the instruction to be in the range ]PC,PC+1].  */
    1993    uintptr_t *pc_addr;
    1994  #ifdef __RTP__
    1995    mcontext_t *mcontext = &((ucontext_t *) sc)->uc_mcontext;
    1996    pc_addr = (uintptr_t*)&mcontext->regs.pc;
    1997  #else
    1998    struct sigcontext * sctx = (struct sigcontext *) sc;
    1999    pc_addr = (uintptr_t*)&sctx->sc_pregs->pc;
    2000  #endif
    2001    /* ARM Bump has to be an even number because of odd/even architecture.  */
    2002    *pc_addr += 2;
    2003  }
    2004  #endif /* ARMEL && _WRS_VXWORKS_MAJOR >= 7 */
    2005  
    2006  /* Tasking and Non-tasking signal handler.  Map SIGnal to Ada exception
    2007     propagation after the required low level adjustments.  */
    2008  
    2009  static void
    2010  __gnat_error_handler (int sig, siginfo_t *si, void *sc)
    2011  {
    2012    sigset_t mask;
    2013  
    2014    /* VxWorks on e500v2 clears the SPE bit of the MSR when entering CPU
    2015       exception state. To allow the handler and exception to work properly
    2016       when they contain SPE instructions, we need to set it back before doing
    2017       anything else.
    2018       This mechanism is only need in kernel mode. */
    2019  #if !(defined (__RTP__) || defined (VTHREADS)) && ((CPU == PPCE500V2) || (CPU == PPC85XX))
    2020    unsigned msr;
    2021    /* Read the MSR value */
    2022    asm volatile ("mfmsr %0" : "=r" (msr));
    2023    /* Force the SPE bit if not set.  */
    2024    if ((msr & 0x02000000) == 0)
    2025      {
    2026        msr |= 0x02000000;
    2027        /* Store to MSR */
    2028        asm volatile ("mtmsr %0" : : "r" (msr));
    2029      }
    2030  #endif
    2031  
    2032    /* VxWorks will always mask out the signal during the signal handler and
    2033       will reenable it on a longjmp.  GNAT does not generate a longjmp to
    2034       return from a signal handler so the signal will still be masked unless
    2035       we unmask it.  */
    2036    sigprocmask (SIG_SETMASK, NULL, &mask);
    2037    sigdelset (&mask, sig);
    2038    sigprocmask (SIG_SETMASK, &mask, NULL);
    2039  
    2040  #if defined (__ARMEL__) || defined (__PPC__) || defined (__i386__) || defined (__x86_64__) || defined (__aarch64__)
    2041    /* On certain targets, kernel mode, we process signals through a Call Frame
    2042       Info trampoline, voiding the need for myriads of fallback_frame_state
    2043       variants in the ZCX runtime.  We have no simple way to distinguish ZCX
    2044       from SJLJ here, so we do this for SJLJ as well even though this is not
    2045       necessary.  This only incurs a few extra instructions and a tiny
    2046       amount of extra stack usage.  */
    2047  
    2048  #ifdef HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
    2049    /* We need to sometimes to adjust the PC in case of signals so that it
    2050       doesn't reference the exception that actually raised the signal but the
    2051       instruction before it.  */
    2052    __gnat_adjust_context_for_raise (sig, sc);
    2053  #endif
    2054  
    2055    __gnat_sigtramp (sig, (void *)si, (void *)sc,
    2056                     (__sigtramphandler_t *)&__gnat_map_signal);
    2057  
    2058  #else
    2059    __gnat_map_signal (sig, si, sc);
    2060  #endif
    2061  }
    2062  
    2063  #if defined(__leon__) && defined(_WRS_KERNEL)
    2064  /* For LEON VxWorks we need to install a trap handler for stack overflow */
    2065  
    2066  extern void excEnt (void);
    2067  /* VxWorks exception handler entry */
    2068  
    2069  struct trap_entry {
    2070     unsigned long inst_first;
    2071     unsigned long inst_second;
    2072     unsigned long inst_third;
    2073     unsigned long inst_fourth;
    2074  };
    2075  /* Four instructions representing entries in the trap table */
    2076  
    2077  struct trap_entry *trap_0_entry;
    2078  /* We will set the location of the entry for software trap 0 in the trap
    2079     table. */
    2080  #endif
    2081  
    2082  void
    2083  __gnat_install_handler (void)
    2084  {
    2085    struct sigaction act;
    2086  
    2087    /* Setup signal handler to map synchronous signals to appropriate
    2088       exceptions.  Make sure that the handler isn't interrupted by another
    2089       signal that might cause a scheduling event!  */
    2090  
    2091    act.sa_sigaction = __gnat_error_handler;
    2092    act.sa_flags = SA_SIGINFO | SA_ONSTACK;
    2093    sigemptyset (&act.sa_mask);
    2094  
    2095    /* For VxWorks, install all signal handlers, since pragma Interrupt_State
    2096       applies to vectored hardware interrupts, not signals.  */
    2097    sigaction (SIGFPE,  &act, NULL);
    2098    sigaction (SIGILL,  &act, NULL);
    2099    sigaction (SIGSEGV, &act, NULL);
    2100    sigaction (SIGBUS,  &act, NULL);
    2101  
    2102  #if defined(__leon__) && defined(_WRS_KERNEL)
    2103    /* Specific to the LEON VxWorks kernel run-time library */
    2104  
    2105    /* For stack checking the compiler triggers a software trap 0 (ta 0) in
    2106       case of overflow (we use the stack limit mechanism). We need to install
    2107       the trap handler here for this software trap (the OS does not handle
    2108       it) as if it were a data_access_exception (trap 9). We do the same as
    2109       if we put in the trap table a VXSPARC_BAD_TRAP(9). Software trap 0 is
    2110       located at vector 0x80, and each entry takes 4 words. */
    2111  
    2112    trap_0_entry = (struct trap_entry *)(intVecBaseGet () + 0x80 * 4);
    2113  
    2114    /* mov 0x9, %l7 */
    2115  
    2116    trap_0_entry->inst_first = 0xae102000 + 9;
    2117  
    2118    /* sethi %hi(excEnt), %l6 */
    2119  
    2120    /* The 22 most significant bits of excEnt are obtained shifting 10 times
    2121       to the right.  */
    2122  
    2123    trap_0_entry->inst_second = 0x2d000000 + ((unsigned long)excEnt >> 10);
    2124  
    2125    /* jmp %l6+%lo(excEnt) */
    2126  
    2127    /* The 10 least significant bits of excEnt are obtained by masking */
    2128  
    2129    trap_0_entry->inst_third = 0x81c5a000 + ((unsigned long)excEnt & 0x3ff);
    2130  
    2131    /* rd %psr, %l0 */
    2132  
    2133    trap_0_entry->inst_fourth = 0xa1480000;
    2134  #endif
    2135  
    2136  #ifdef __HANDLE_VXSIM_SC
    2137    /*  By experiment, found that sysModel () returns the following string
    2138        prefix for vxsim when running on Linux and Windows.  */
    2139    {
    2140      char *model = sysModel ();
    2141      if ((strncmp (model, "Linux", 5) == 0)
    2142          || (strncmp (model, "Windows", 7) == 0)
    2143          || (strncmp (model, "SIMLINUX", 8) == 0) /* vx7 */
    2144          || (strncmp (model, "SIMNT", 5) == 0)) /* ditto */
    2145        __gnat_set_is_vxsim (TRUE);
    2146    }
    2147  #endif
    2148  
    2149    __gnat_handler_installed = 1;
    2150  }
    2151  
    2152  #define HAVE_GNAT_INIT_FLOAT
    2153  
    2154  void
    2155  __gnat_init_float (void)
    2156  {
    2157    /* Disable overflow/underflow exceptions on the PPC processor, needed
    2158       to get correct Ada semantics.  Note that for AE653 vThreads, the HW
    2159       overflow settings are an OS configuration issue.  The instructions
    2160       below have no effect.  */
    2161  #if defined (_ARCH_PPC) && !defined (_SOFT_FLOAT) && (!defined (VTHREADS) || defined (__VXWORKSMILS__))
    2162  #if defined (__SPE__)
    2163    {
    2164      /* For e500v2, do nothing and leave the responsibility to install the
    2165         handler and enable the exceptions to the BSP.  */
    2166    }
    2167  #else
    2168    asm ("mtfsb0 25");
    2169    asm ("mtfsb0 26");
    2170  #endif
    2171  #endif
    2172  
    2173  #if (defined (__i386__) || defined (__x86_64__)) && !defined (VTHREADS)
    2174    /* This is used to properly initialize the FPU on an x86 for each
    2175       process thread. */
    2176    asm ("finit");
    2177  #endif
    2178  
    2179    /* Similarly for SPARC64.  Achieved by masking bits in the Trap Enable Mask
    2180       field of the Floating-point Status Register (see the SPARC Architecture
    2181       Manual Version 9, p 48).  */
    2182  #if defined (sparc64)
    2183  
    2184  #define FSR_TEM_NVM (1 << 27)  /* Invalid operand  */
    2185  #define FSR_TEM_OFM (1 << 26)  /* Overflow  */
    2186  #define FSR_TEM_UFM (1 << 25)  /* Underflow  */
    2187  #define FSR_TEM_DZM (1 << 24)  /* Division by Zero  */
    2188  #define FSR_TEM_NXM (1 << 23)  /* Inexact result  */
    2189    {
    2190      unsigned int fsr;
    2191  
    2192      __asm__("st %%fsr, %0" : "=m" (fsr));
    2193      fsr &= ~(FSR_TEM_OFM | FSR_TEM_UFM);
    2194      __asm__("ld %0, %%fsr" : : "m" (fsr));
    2195    }
    2196  #endif
    2197  }
    2198  
    2199  /* This subprogram is called by System.Task_Primitives.Operations.Enter_Task
    2200     (if not null) when a new task is created.  It is initialized by
    2201     System.Stack_Checking.Operations.Initialize_Stack_Limit.
    2202     The use of a hook avoids to drag stack checking subprograms if stack
    2203     checking is not used.  */
    2204  void (*__gnat_set_stack_limit_hook)(void) = (void (*)(void))0;
    2205  
    2206  /******************/
    2207  /* NetBSD Section */
    2208  /******************/
    2209  
    2210  #elif defined(__NetBSD__)
    2211  
    2212  #include <signal.h>
    2213  #include <unistd.h>
    2214  
    2215  static void
    2216  __gnat_error_handler (int sig)
    2217  {
    2218    struct Exception_Data *exception;
    2219    const char *msg;
    2220  
    2221    switch(sig)
    2222    {
    2223      case SIGFPE:
    2224        exception = &constraint_error;
    2225        msg = "SIGFPE";
    2226        break;
    2227      case SIGILL:
    2228        exception = &constraint_error;
    2229        msg = "SIGILL";
    2230        break;
    2231      case SIGSEGV:
    2232        exception = &storage_error;
    2233        msg = "stack overflow or erroneous memory access";
    2234        break;
    2235      case SIGBUS:
    2236        exception = &constraint_error;
    2237        msg = "SIGBUS";
    2238        break;
    2239      default:
    2240        exception = &program_error;
    2241        msg = "unhandled signal";
    2242      }
    2243  
    2244      Raise_From_Signal_Handler (exception, msg);
    2245  }
    2246  
    2247  void
    2248  __gnat_install_handler (void)
    2249  {
    2250    struct sigaction act;
    2251  
    2252    act.sa_handler = __gnat_error_handler;
    2253    act.sa_flags = SA_NODEFER | SA_RESTART;
    2254    sigemptyset (&act.sa_mask);
    2255  
    2256    /* Do not install handlers if interrupt state is "System".  */
    2257    if (__gnat_get_interrupt_state (SIGFPE) != 's')
    2258      sigaction (SIGFPE,  &act, NULL);
    2259    if (__gnat_get_interrupt_state (SIGILL) != 's')
    2260      sigaction (SIGILL,  &act, NULL);
    2261    if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    2262      sigaction (SIGSEGV, &act, NULL);
    2263    if (__gnat_get_interrupt_state (SIGBUS) != 's')
    2264      sigaction (SIGBUS,  &act, NULL);
    2265  
    2266    __gnat_handler_installed = 1;
    2267  }
    2268  
    2269  /*******************/
    2270  /* OpenBSD Section */
    2271  /*******************/
    2272  
    2273  #elif defined(__OpenBSD__)
    2274  
    2275  #include <signal.h>
    2276  #include <unistd.h>
    2277  
    2278  static void
    2279  __gnat_error_handler (int sig)
    2280  {
    2281    struct Exception_Data *exception;
    2282    const char *msg;
    2283  
    2284    switch(sig)
    2285    {
    2286      case SIGFPE:
    2287        exception = &constraint_error;
    2288        msg = "SIGFPE";
    2289        break;
    2290      case SIGILL:
    2291        exception = &constraint_error;
    2292        msg = "SIGILL";
    2293        break;
    2294      case SIGSEGV:
    2295        exception = &storage_error;
    2296        msg = "stack overflow or erroneous memory access";
    2297        break;
    2298      case SIGBUS:
    2299        exception = &constraint_error;
    2300        msg = "SIGBUS";
    2301        break;
    2302      default:
    2303        exception = &program_error;
    2304        msg = "unhandled signal";
    2305      }
    2306  
    2307      Raise_From_Signal_Handler (exception, msg);
    2308  }
    2309  
    2310  void
    2311  __gnat_install_handler (void)
    2312  {
    2313    struct sigaction act;
    2314  
    2315    act.sa_handler = __gnat_error_handler;
    2316    act.sa_flags = SA_NODEFER | SA_RESTART;
    2317    sigemptyset (&act.sa_mask);
    2318  
    2319    /* Do not install handlers if interrupt state is "System" */
    2320    if (__gnat_get_interrupt_state (SIGFPE) != 's')
    2321      sigaction (SIGFPE,  &act, NULL);
    2322    if (__gnat_get_interrupt_state (SIGILL) != 's')
    2323      sigaction (SIGILL,  &act, NULL);
    2324    if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    2325      sigaction (SIGSEGV, &act, NULL);
    2326    if (__gnat_get_interrupt_state (SIGBUS) != 's')
    2327      sigaction (SIGBUS,  &act, NULL);
    2328  
    2329    __gnat_handler_installed = 1;
    2330  }
    2331  
    2332  /******************/
    2333  /* Darwin Section */
    2334  /******************/
    2335  
    2336  #elif defined(__APPLE__)
    2337  
    2338  #include <TargetConditionals.h>
    2339  #include <signal.h>
    2340  #include <stdlib.h>
    2341  #include <sys/syscall.h>
    2342  #include <sys/sysctl.h>
    2343  
    2344  /* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.  */
    2345  char __gnat_alternate_stack[32 * 1024]; /* 1 * MINSIGSTKSZ */
    2346  
    2347  /* Defined in xnu unix_signal.c.
    2348     Tell the kernel to re-use alt stack when delivering a signal.  */
    2349  #define	UC_RESET_ALT_STACK	0x80000000
    2350  
    2351  #if !(defined (__arm__) || defined (__arm64__) || TARGET_IPHONE_SIMULATOR)
    2352  #include <mach/mach_vm.h>
    2353  #include <mach/mach_init.h>
    2354  #include <mach/vm_statistics.h>
    2355  #endif
    2356  
    2357  #ifdef __arm64__
    2358  #include <sys/ucontext.h>
    2359  #include "sigtramp.h"
    2360  #endif
    2361  
    2362  /* Return true if ADDR is within a stack guard area.  */
    2363  static int
    2364  __gnat_is_stack_guard (mach_vm_address_t addr)
    2365  {
    2366  #if !(defined (__arm__) || defined (__arm64__) || TARGET_IPHONE_SIMULATOR)
    2367    kern_return_t kret;
    2368    vm_region_submap_info_data_64_t info;
    2369    mach_vm_address_t start;
    2370    mach_vm_size_t size;
    2371    natural_t depth;
    2372    mach_msg_type_number_t count;
    2373  
    2374    count = VM_REGION_SUBMAP_INFO_COUNT_64;
    2375    start = addr;
    2376    size = -1;
    2377    depth = 9999;
    2378    kret = mach_vm_region_recurse (mach_task_self (), &start, &size, &depth,
    2379  				 (vm_region_recurse_info_t) &info, &count);
    2380    if (kret == KERN_SUCCESS
    2381        && addr >= start && addr < (start + size)
    2382        && info.protection == VM_PROT_NONE
    2383        && info.user_tag == VM_MEMORY_STACK)
    2384      return 1;
    2385    return 0;
    2386  #else
    2387    /* Pagezero for arm.  */
    2388    return addr >= 4096;
    2389  #endif
    2390  }
    2391  
    2392  #define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
    2393  
    2394  #if defined (__x86_64__)
    2395  static int
    2396  __darwin_major_version (void)
    2397  {
    2398    static int cache = -1;
    2399    if (cache < 0)
    2400      {
    2401        int mib[2] = {CTL_KERN, KERN_OSRELEASE};
    2402        size_t len;
    2403  
    2404        /* Find out how big the buffer needs to be (and set cache to 0
    2405           on failure).  */
    2406        if (sysctl (mib, 2, NULL, &len, NULL, 0) == 0)
    2407          {
    2408            char release[len];
    2409            sysctl (mib, 2, release, &len, NULL, 0);
    2410            /* Darwin releases are of the form L.M.N where L is the major
    2411               version, so strtol will return L.  */
    2412            cache = (int) strtol (release, NULL, 10);
    2413          }
    2414        else
    2415          {
    2416            cache = 0;
    2417          }
    2418      }
    2419    return cache;
    2420  }
    2421  #endif
    2422  
    2423  void
    2424  __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED,
    2425  				 void *ucontext ATTRIBUTE_UNUSED)
    2426  {
    2427  #if defined (__x86_64__)
    2428    if (__darwin_major_version () < 12)
    2429      {
    2430        /* Work around radar #10302855, where the unwinders (libunwind or
    2431  	 libgcc_s depending on the system revision) and the DWARF unwind
    2432  	 data for sigtramp have different ideas about register numbering,
    2433  	 causing rbx and rdx to be transposed.  */
    2434        ucontext_t *uc = (ucontext_t *)ucontext;
    2435        unsigned long t = uc->uc_mcontext->__ss.__rbx;
    2436  
    2437        uc->uc_mcontext->__ss.__rbx = uc->uc_mcontext->__ss.__rdx;
    2438        uc->uc_mcontext->__ss.__rdx = t;
    2439      }
    2440  #elif defined(__arm64__)
    2441    /* Even though the CFI is marked as a signal frame, we need this.  */
    2442    ucontext_t *uc = (ucontext_t *)ucontext;
    2443    uc->uc_mcontext->__ss.__pc++;
    2444  #endif
    2445  }
    2446  
    2447  static void
    2448  __gnat_map_signal (int sig, siginfo_t *si, void *mcontext ATTRIBUTE_UNUSED)
    2449  {
    2450    struct Exception_Data *exception;
    2451    const char *msg;
    2452  
    2453    switch (sig)
    2454      {
    2455      case SIGSEGV:
    2456      case SIGBUS:
    2457        if (__gnat_is_stack_guard ((unsigned long)si->si_addr))
    2458  	{
    2459  #ifdef __arm64__
    2460  	  /* ??? This is a kludge to make stack checking work.  The problem is
    2461  	     that the trampoline doesn't restore LR and, consequently, doesn't
    2462  	     make it possible to unwind past an interrupted frame which hasn"t
    2463  	     saved LR on the stack yet.  Therefore, for probes in the prologue
    2464  	     (32-bit probes as opposed to standard 64-bit probes), we make the
    2465  	     unwinder skip the not-yet-established frame altogether.  */
    2466  	  mcontext_t mc = (mcontext_t)mcontext;
    2467  	  if (!(*(unsigned int *)(mc->__ss.__pc-1) & ((unsigned int)1 << 30)))
    2468  	    mc->__ss.__pc = mc->__ss.__lr;
    2469  #endif
    2470  	  exception = &storage_error;
    2471  	  msg = "stack overflow";
    2472  	}
    2473        else
    2474  	{
    2475  	  exception = &constraint_error;
    2476  	  msg = "erroneous memory access";
    2477  	}
    2478  
    2479        /* Reset the use of alt stack, so that the alt stack will be used
    2480  	 for the next signal delivery.
    2481  	 The stack can't be used in case of stack checking.  */
    2482        syscall (SYS_sigreturn, NULL, UC_RESET_ALT_STACK);
    2483        break;
    2484  
    2485      case SIGFPE:
    2486        exception = &constraint_error;
    2487        msg = "SIGFPE";
    2488        break;
    2489  
    2490      default:
    2491        exception = &program_error;
    2492        msg = "unhandled signal";
    2493      }
    2494  
    2495    Raise_From_Signal_Handler (exception, msg);
    2496  }
    2497  
    2498  static void
    2499  __gnat_error_handler (int sig, siginfo_t *si, void *ucontext)
    2500  {
    2501    __gnat_adjust_context_for_raise (sig, ucontext);
    2502  
    2503    /* The Darwin libc comes with a signal trampoline, except for ARM64.  */
    2504  #ifdef __arm64__
    2505    __gnat_sigtramp (sig, (void *)si, ucontext,
    2506  		   (__sigtramphandler_t *)&__gnat_map_signal);
    2507  #else
    2508    __gnat_map_signal (sig, si, ucontext);
    2509  #endif
    2510  }
    2511  
    2512  void
    2513  __gnat_install_handler (void)
    2514  {
    2515    struct sigaction act;
    2516  
    2517    /* Set up signal handler to map synchronous signals to appropriate
    2518       exceptions.  Make sure that the handler isn't interrupted by another
    2519       signal that might cause a scheduling event!  Also setup an alternate
    2520       stack region for the handler execution so that stack overflows can be
    2521       handled properly, avoiding a SEGV generation from stack usage by the
    2522       handler itself (and it is required by Darwin).  */
    2523  
    2524    stack_t stack;
    2525    stack.ss_sp = __gnat_alternate_stack;
    2526    stack.ss_size = sizeof (__gnat_alternate_stack);
    2527    stack.ss_flags = 0;
    2528    sigaltstack (&stack, NULL);
    2529  
    2530    act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
    2531    act.sa_sigaction = __gnat_error_handler;
    2532    sigemptyset (&act.sa_mask);
    2533  
    2534    /* Do not install handlers if interrupt state is "System".  */
    2535    if (__gnat_get_interrupt_state (SIGABRT) != 's')
    2536      sigaction (SIGABRT, &act, NULL);
    2537    if (__gnat_get_interrupt_state (SIGFPE) != 's')
    2538      sigaction (SIGFPE,  &act, NULL);
    2539    if (__gnat_get_interrupt_state (SIGILL) != 's')
    2540      sigaction (SIGILL,  &act, NULL);
    2541  
    2542    act.sa_flags |= SA_ONSTACK;
    2543    if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    2544      sigaction (SIGSEGV, &act, NULL);
    2545    if (__gnat_get_interrupt_state (SIGBUS) != 's')
    2546      sigaction (SIGBUS,  &act, NULL);
    2547  
    2548    __gnat_handler_installed = 1;
    2549  }
    2550  
    2551  #elif defined(__QNX__)
    2552  
    2553  /***************/
    2554  /* QNX Section */
    2555  /***************/
    2556  
    2557  #include <signal.h>
    2558  #include <unistd.h>
    2559  #include <string.h>
    2560  #include <errno.h>
    2561  #include "sigtramp.h"
    2562  
    2563  #if defined (__ARMEL__) && !defined (__aarch64__)
    2564  
    2565  /* ARM-QNX case with arm unwinding exceptions */
    2566  #define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
    2567  
    2568  #include <ucontext.h>
    2569  #include <arm/cpu.h>
    2570  #include <stdint.h>
    2571  
    2572  void
    2573  __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED,
    2574  				 void *sc ATTRIBUTE_UNUSED)
    2575  {
    2576    /* In case of ARM exceptions, the registers context have the PC pointing
    2577       to the instruction that raised the signal.  However the unwinder expects
    2578       the instruction to be in the range [PC+2,PC+3].  */
    2579    uintptr_t *pc_addr;
    2580    mcontext_t *mcontext = &((ucontext_t *) sc)->uc_mcontext;
    2581    pc_addr = (uintptr_t *)&mcontext->cpu.gpr [ARM_REG_PC];
    2582  
    2583    /* ARM Bump has to be an even number because of odd/even architecture.  */
    2584    *pc_addr += 2;
    2585  #ifdef __thumb2__
    2586    /* For thumb, the return address must have the low order bit set, otherwise
    2587       the unwinder will reset to "arm" mode upon return.  As long as the
    2588       compilation unit containing the landing pad is compiled with the same
    2589       mode (arm vs thumb) as the signaling compilation unit, this works.  */
    2590    if (mcontext->cpu.spsr & ARM_CPSR_T)
    2591      *pc_addr += 1;
    2592  #endif
    2593  }
    2594  #endif /* ARMEL */
    2595  
    2596  void
    2597  __gnat_map_signal (int sig,
    2598  		   siginfo_t *si ATTRIBUTE_UNUSED,
    2599  		   void *mcontext ATTRIBUTE_UNUSED)
    2600  {
    2601    struct Exception_Data *exception;
    2602    const char *msg;
    2603  
    2604    switch(sig)
    2605    {
    2606      case SIGFPE:
    2607        exception = &constraint_error;
    2608        msg = "SIGFPE";
    2609        break;
    2610      case SIGILL:
    2611        exception = &constraint_error;
    2612        msg = "SIGILL";
    2613        break;
    2614      case SIGSEGV:
    2615        exception = &storage_error;
    2616        msg = "stack overflow or erroneous memory access";
    2617        break;
    2618      case SIGBUS:
    2619        exception = &constraint_error;
    2620        msg = "SIGBUS";
    2621        break;
    2622      default:
    2623        exception = &program_error;
    2624        msg = "unhandled signal";
    2625      }
    2626  
    2627      Raise_From_Signal_Handler (exception, msg);
    2628  }
    2629  
    2630  static void
    2631  __gnat_error_handler (int sig, siginfo_t *si, void *ucontext)
    2632  {
    2633  #ifdef HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
    2634    /* We need to sometimes to adjust the PC in case of signals so that it
    2635       doesn't reference the exception that actually raised the signal but the
    2636       instruction before it.  */
    2637    __gnat_adjust_context_for_raise (sig, ucontext);
    2638  #endif
    2639  
    2640    __gnat_sigtramp (sig, (void *) si, (void *) ucontext,
    2641  		   (__sigtramphandler_t *)&__gnat_map_signal);
    2642  }
    2643  
    2644  /* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.  */
    2645  /* sigaltstack is currently not supported by QNX7 */
    2646  char __gnat_alternate_stack[0];
    2647  
    2648  void
    2649  __gnat_install_handler (void)
    2650  {
    2651    struct sigaction act;
    2652    int err;
    2653  
    2654    act.sa_sigaction = __gnat_error_handler;
    2655    act.sa_flags = SA_NODEFER | SA_SIGINFO;
    2656    sigemptyset (&act.sa_mask);
    2657  
    2658    /* Do not install handlers if interrupt state is "System" */
    2659    if (__gnat_get_interrupt_state (SIGFPE) != 's') {
    2660      err = sigaction (SIGFPE,  &act, NULL);
    2661      if (err == -1) {
    2662        err = errno;
    2663        perror ("error while attaching SIGFPE");
    2664        perror (strerror (err));
    2665      }
    2666    }
    2667    if (__gnat_get_interrupt_state (SIGILL) != 's') {
    2668      err = sigaction (SIGILL,  &act, NULL);
    2669      if (err == -1) {
    2670        err = errno;
    2671        perror ("error while attaching SIGILL");
    2672        perror (strerror (err));
    2673      }
    2674    }
    2675    if (__gnat_get_interrupt_state (SIGSEGV) != 's') {
    2676      err = sigaction (SIGSEGV, &act, NULL);
    2677      if (err == -1) {
    2678        err = errno;
    2679        perror ("error while attaching SIGSEGV");
    2680        perror (strerror (err));
    2681      }
    2682    }
    2683    if (__gnat_get_interrupt_state (SIGBUS) != 's') {
    2684      err = sigaction (SIGBUS,  &act, NULL);
    2685      if (err == -1) {
    2686        err = errno;
    2687        perror ("error while attaching SIGBUS");
    2688        perror (strerror (err));
    2689      }
    2690    }
    2691    __gnat_handler_installed = 1;
    2692  }
    2693  
    2694  /*****************/
    2695  /* RTEMS Section */
    2696  /*****************/
    2697  
    2698  #elif defined(__rtems__)
    2699  
    2700  #include <signal.h>
    2701  #include <unistd.h>
    2702  
    2703  static void
    2704  __gnat_error_handler (int sig)
    2705  {
    2706    struct Exception_Data *exception;
    2707    const char *msg;
    2708  
    2709    switch(sig)
    2710    {
    2711      case SIGFPE:
    2712        exception = &constraint_error;
    2713        msg = "SIGFPE";
    2714        break;
    2715      case SIGILL:
    2716        exception = &constraint_error;
    2717        msg = "SIGILL";
    2718        break;
    2719      case SIGSEGV:
    2720        exception = &storage_error;
    2721        msg = "erroneous memory access";
    2722        break;
    2723      case SIGBUS:
    2724        exception = &constraint_error;
    2725        msg = "SIGBUS";
    2726        break;
    2727      default:
    2728        exception = &program_error;
    2729        msg = "unhandled signal";
    2730      }
    2731  
    2732      Raise_From_Signal_Handler (exception, msg);
    2733  }
    2734  
    2735  void
    2736  __gnat_install_handler (void)
    2737  {
    2738    struct sigaction act;
    2739  
    2740    act.sa_handler = __gnat_error_handler;
    2741    sigemptyset (&act.sa_mask);
    2742  
    2743    /* Do not install handlers if interrupt state is "System".  */
    2744    if (__gnat_get_interrupt_state (SIGFPE) != 's')
    2745      sigaction (SIGFPE,  &act, NULL);
    2746    if (__gnat_get_interrupt_state (SIGILL) != 's')
    2747      sigaction (SIGILL,  &act, NULL);
    2748    if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    2749      sigaction (SIGSEGV, &act, NULL);
    2750    if (__gnat_get_interrupt_state (SIGBUS) != 's')
    2751      sigaction (SIGBUS,  &act, NULL);
    2752  
    2753    __gnat_handler_installed = 1;
    2754  }
    2755  
    2756  #elif defined (__DJGPP__)
    2757  
    2758  void
    2759  __gnat_install_handler ()
    2760  {
    2761    __gnat_handler_installed = 1;
    2762  }
    2763  
    2764  #elif defined(__ANDROID__)
    2765  
    2766  /*******************/
    2767  /* Android Section */
    2768  /*******************/
    2769  
    2770  #include <signal.h>
    2771  #include <sys/ucontext.h>
    2772  #include "sigtramp.h"
    2773  
    2774  #define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
    2775  
    2776  void
    2777  __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
    2778  {
    2779    mcontext_t *mcontext = &((ucontext_t *) ucontext)->uc_mcontext;
    2780  
    2781    /* ARM Bump has to be an even number because of odd/even architecture.  */
    2782    ((mcontext_t *) mcontext)->arm_pc += 2;
    2783  }
    2784  
    2785  static void
    2786  __gnat_map_signal (int sig,
    2787  		   siginfo_t *si ATTRIBUTE_UNUSED,
    2788  		   void *mcontext ATTRIBUTE_UNUSED)
    2789  {
    2790    struct Exception_Data *exception;
    2791    const char *msg;
    2792  
    2793    switch (sig)
    2794      {
    2795      case SIGSEGV:
    2796        exception = &storage_error;
    2797        msg = "stack overflow or erroneous memory access";
    2798        break;
    2799  
    2800      case SIGBUS:
    2801        exception = &constraint_error;
    2802        msg = "SIGBUS";
    2803        break;
    2804  
    2805      case SIGFPE:
    2806        exception = &constraint_error;
    2807        msg = "SIGFPE";
    2808        break;
    2809  
    2810      default:
    2811        exception = &program_error;
    2812        msg = "unhandled signal";
    2813      }
    2814  
    2815    Raise_From_Signal_Handler (exception, msg);
    2816  }
    2817  
    2818  static void
    2819  __gnat_error_handler (int sig, siginfo_t *si, void *ucontext)
    2820  {
    2821    __gnat_adjust_context_for_raise (sig, ucontext);
    2822  
    2823    __gnat_sigtramp (sig, (void *) si, (void *) ucontext,
    2824  		   (__sigtramphandler_t *)&__gnat_map_signal);
    2825  }
    2826  
    2827  /* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.  */
    2828  char __gnat_alternate_stack[16 * 1024];
    2829  
    2830  void
    2831  __gnat_install_handler (void)
    2832  {
    2833    struct sigaction act;
    2834  
    2835    /* Set up signal handler to map synchronous signals to appropriate
    2836       exceptions.  Make sure that the handler isn't interrupted by another
    2837       signal that might cause a scheduling event!  Also setup an alternate
    2838       stack region for the handler execution so that stack overflows can be
    2839       handled properly, avoiding a SEGV generation from stack usage by the
    2840       handler itself.  */
    2841  
    2842    stack_t stack;
    2843    stack.ss_sp = __gnat_alternate_stack;
    2844    stack.ss_size = sizeof (__gnat_alternate_stack);
    2845    stack.ss_flags = 0;
    2846    sigaltstack (&stack, NULL);
    2847  
    2848    act.sa_sigaction = __gnat_error_handler;
    2849    act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
    2850    sigemptyset (&act.sa_mask);
    2851  
    2852    sigaction (SIGABRT, &act, NULL);
    2853    sigaction (SIGFPE,  &act, NULL);
    2854    sigaction (SIGILL,  &act, NULL);
    2855    sigaction (SIGBUS,  &act, NULL);
    2856    act.sa_flags |= SA_ONSTACK;
    2857    sigaction (SIGSEGV, &act, NULL);
    2858  
    2859    __gnat_handler_installed = 1;
    2860  }
    2861  
    2862  #else
    2863  
    2864  /* For all other versions of GNAT, the handler does nothing.  */
    2865  
    2866  /*******************/
    2867  /* Default Section */
    2868  /*******************/
    2869  
    2870  void
    2871  __gnat_install_handler (void)
    2872  {
    2873    __gnat_handler_installed = 1;
    2874  }
    2875  
    2876  #endif
    2877  
    2878  /*********************/
    2879  /* __gnat_init_float */
    2880  /*********************/
    2881  
    2882  #if defined (_WIN32) || defined (__INTERIX) || defined (__linux__) \
    2883    || defined (__Lynx__) || defined(__NetBSD__) || defined(__FreeBSD__) \
    2884    || defined (__OpenBSD__) || defined (__DragonFly__) || defined(__QNX__)
    2885  
    2886  #define HAVE_GNAT_INIT_FLOAT
    2887  
    2888  void
    2889  __gnat_init_float (void)
    2890  {
    2891  #if defined (__i386__) || defined (__x86_64__)
    2892    /* This is used to properly initialize the FPU to 64-bit precision on an x86
    2893       for each process thread and also for floating-point I/O.  */
    2894    asm ("finit");
    2895  #endif
    2896  }
    2897  #endif
    2898  
    2899  #ifndef HAVE_GNAT_INIT_FLOAT
    2900  
    2901  /* All targets without a specific __gnat_init_float will use an empty one.  */
    2902  void
    2903  __gnat_init_float (void)
    2904  {
    2905  }
    2906  #endif
    2907  
    2908  /***********************************/
    2909  /* __gnat_adjust_context_for_raise */
    2910  /***********************************/
    2911  
    2912  #ifndef HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
    2913  
    2914  /* All targets without a specific version will use an empty one.  */
    2915  
    2916  /* Given UCONTEXT a pointer to a context structure received by a signal
    2917     handler for SIGNO, perform the necessary adjustments to let the handler
    2918     raise an exception.  Calls to this routine are not conditioned by the
    2919     propagation scheme in use.  */
    2920  
    2921  void
    2922  __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED,
    2923  				 void *ucontext ATTRIBUTE_UNUSED)
    2924  {
    2925    /* We used to compensate here for the raised from call vs raised from signal
    2926       exception discrepancy with the GCC ZCX scheme, but this now can be dealt
    2927       with generically in the unwinder (see GCC PR other/26208).  This however
    2928       requires the use of the _Unwind_GetIPInfo routine in raise-gcc.c, which
    2929       is predicated on the definition of HAVE_GETIPINFO at compile time.  Only
    2930       the VMS ports still do the compensation described in the few lines below.
    2931  
    2932       *** Call vs signal exception discrepancy with GCC ZCX scheme ***
    2933  
    2934       The GCC unwinder expects to be dealing with call return addresses, since
    2935       this is the "nominal" case of what we retrieve while unwinding a regular
    2936       call chain.
    2937  
    2938       To evaluate if a handler applies at some point identified by a return
    2939       address, the propagation engine needs to determine what region the
    2940       corresponding call instruction pertains to.  Because the return address
    2941       may not be attached to the same region as the call, the unwinder always
    2942       subtracts "some" amount from a return address to search the region
    2943       tables, amount chosen to ensure that the resulting address is inside the
    2944       call instruction.
    2945  
    2946       When we raise an exception from a signal handler, e.g. to transform a
    2947       SIGSEGV into Storage_Error, things need to appear as if the signal
    2948       handler had been "called" by the instruction which triggered the signal,
    2949       so that exception handlers that apply there are considered.  What the
    2950       unwinder will retrieve as the return address from the signal handler is
    2951       what it will find as the faulting instruction address in the signal
    2952       context pushed by the kernel.  Leaving this address untouched looses, if
    2953       the triggering instruction happens to be the very first of a region, as
    2954       the later adjustments performed by the unwinder would yield an address
    2955       outside that region.  We need to compensate for the unwinder adjustments
    2956       at some point, and this is what this routine is expected to do.
    2957  
    2958       signo is passed because on some targets for some signals the PC in
    2959       context points to the instruction after the faulting one, in which case
    2960       the unwinder adjustment is still desired.  */
    2961  }
    2962  
    2963  #endif
    2964  
    2965  #ifdef __cplusplus
    2966  }
    2967  #endif