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