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