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