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