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