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