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