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