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