* *
* C Implementation File *
* *
- * Copyright (C) 1992-2009, Free Software Foundation, Inc. *
+ * Copyright (C) 1992-2015, Free Software Foundation, Inc. *
* *
* GNAT is free software; you can redistribute it and/or modify it under *
* terms of the GNU General Public License as published by the Free Soft- *
installed by this file are used to catch the resulting signals that come
from these probes failing (i.e. touching protected pages). */
-/* This file should be kept synchronized with 2sinit.ads, 2sinit.adb,
- s-init-ae653-cert.adb and s-init-xi-sparc.adb. All these files implement
- the required functionality for different targets. */
+/* This file should be kept synchronized with s-init.ads, s-init.adb and the
+ s-init-*.adb variants. All these files implement the required functionality
+ for different targets. */
/* The following include is here to meet the published VxWorks requirement
that the __vxworks header appear before any other include. */
#include "vxWorks.h"
#endif
+#ifdef __ANDROID__
+#undef __linux__
+#endif
+
#ifdef IN_RTS
#include "tconfig.h"
#include "tsystem.h"
#include "adaint.h"
#include "raise.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern void __gnat_raise_program_error (const char *, int);
/* Addresses of exception data blocks for predefined exceptions. Tasking_Error
- is not used in this unit, and the abort signal is only used on IRIX. */
+ is not used in this unit, and the abort signal is only used on IRIX.
+ ??? Revisit this part since IRIX is no longer supported. */
extern struct Exception_Data constraint_error;
extern struct Exception_Data numeric_error;
extern struct Exception_Data program_error;
/* Global values computed by the binder. */
int __gl_main_priority = -1;
+int __gl_main_cpu = -1;
int __gl_time_slice_val = -1;
char __gl_wc_encoding = 'n';
char __gl_locking_policy = ' ';
int __gl_num_interrupt_states = 0;
int __gl_unreserve_all_interrupts = 0;
int __gl_exception_tracebacks = 0;
-int __gl_zero_cost_exceptions = 0;
int __gl_detect_blocking = 0;
int __gl_default_stack_size = -1;
int __gl_leap_seconds_support = 0;
int __gl_canonical_streams = 0;
+/* This value is not used anymore, but kept for bootstrapping purpose. */
+int __gl_zero_cost_exceptions = 0;
+
/* Indication of whether synchronous signal handler has already been
installed by a previous call to adainit. */
int __gnat_handler_installed = 0;
file now sets the __gl_* variables directly. */
void
-__gnat_set_globals ()
+__gnat_set_globals (void)
{
}
#endif /* _AIXVERSION_430 */
-static void __gnat_error_handler (int sig, siginfo_t * si, void * uc);
-
static void
-__gnat_error_handler (int sig, siginfo_t * si, void * uc)
+__gnat_error_handler (int sig,
+ siginfo_t *si ATTRIBUTE_UNUSED,
+ void *ucontext ATTRIBUTE_UNUSED)
{
struct Exception_Data *exception;
const char *msg;
}
/*****************/
-/* Tru64 section */
+/* HP-UX section */
/*****************/
-#elif defined(__alpha__) && defined(__osf__)
+#elif defined (__hpux__)
#include <signal.h>
-#include <sys/siginfo.h>
-
-static void __gnat_error_handler (int, siginfo_t *, struct sigcontext *);
-extern char *__gnat_get_code_loc (struct sigcontext *);
-extern void __gnat_set_code_loc (struct sigcontext *, char *);
-extern size_t __gnat_machine_state_length (void);
-
-#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
-
-void
-__gnat_adjust_context_for_raise (int signo, void *ucontext)
-{
- struct sigcontext *sigcontext = (struct sigcontext *) ucontext;
-
- /* The unwinder expects the signal context to contain the address of the
- faulting instruction. For SIGFPE, this depends on the trap shadow
- situation (see man ieee). We nonetheless always compensate for it,
- considering that PC designates the instruction following the one that
- trapped. This is not necessarily true but corresponds to what we have
- always observed. */
- if (signo == SIGFPE)
- sigcontext->sc_pc--;
-}
-
-static void
-__gnat_error_handler
- (int sig, siginfo_t *sip, struct sigcontext *context)
-{
- struct Exception_Data *exception;
- static int recurse = 0;
- const char *msg;
-
- /* Adjusting is required for every fault context, so adjust for this one
- now, before we possibly trigger a recursive fault below. */
- __gnat_adjust_context_for_raise (sig, context);
-
- /* If this was an explicit signal from a "kill", just resignal it. */
- if (SI_FROMUSER (sip))
- {
- signal (sig, SIG_DFL);
- kill (getpid(), sig);
- }
-
- /* Otherwise, treat it as something we handle. */
- switch (sig)
- {
- case SIGSEGV:
- /* If the problem was permissions, this is a constraint error.
- Likewise if the failing address isn't maximally aligned or if
- we've recursed.
-
- ??? Using a static variable here isn't task-safe, but it's
- much too hard to do anything else and we're just determining
- which exception to raise. */
- if (sip->si_code == SEGV_ACCERR
- || (((long) sip->si_addr) & 3) != 0
- || recurse)
- {
- exception = &constraint_error;
- msg = "SIGSEGV";
- }
- else
- {
- /* See if the page before the faulting page is accessible. Do that
- by trying to access it. We'd like to simply try to access
- 4096 + the faulting address, but it's not guaranteed to be
- the actual address, just to be on the same page. */
- recurse++;
- ((volatile char *)
- ((long) sip->si_addr & - getpagesize ()))[getpagesize ()];
- msg = "stack overflow (or erroneous memory access)";
- exception = &storage_error;
- }
- break;
-
- case SIGBUS:
- exception = &program_error;
- msg = "SIGBUS";
- break;
-
- case SIGFPE:
- exception = &constraint_error;
- msg = "SIGFPE";
- break;
-
- default:
- exception = &program_error;
- msg = "unhandled signal";
- }
-
- recurse = 0;
- Raise_From_Signal_Handler (exception, (char *) msg);
-}
-
-void
-__gnat_install_handler (void)
-{
- struct sigaction act;
-
- /* Setup signal handler to map synchronous signals to appropriate
- exceptions. Make sure that the handler isn't interrupted by another
- signal that might cause a scheduling event! */
-
- act.sa_handler = (void (*) (int)) __gnat_error_handler;
- act.sa_flags = SA_RESTART | SA_NODEFER | SA_SIGINFO;
- sigemptyset (&act.sa_mask);
-
- /* Do not install handlers if interrupt state is "System". */
- if (__gnat_get_interrupt_state (SIGABRT) != 's')
- sigaction (SIGABRT, &act, NULL);
- if (__gnat_get_interrupt_state (SIGFPE) != 's')
- sigaction (SIGFPE, &act, NULL);
- if (__gnat_get_interrupt_state (SIGILL) != 's')
- sigaction (SIGILL, &act, NULL);
- if (__gnat_get_interrupt_state (SIGSEGV) != 's')
- sigaction (SIGSEGV, &act, NULL);
- if (__gnat_get_interrupt_state (SIGBUS) != 's')
- sigaction (SIGBUS, &act, NULL);
-
- __gnat_handler_installed = 1;
-}
+#include <sys/ucontext.h>
-/* Routines called by s-mastop-tru64.adb. */
+#if defined (IN_RTS) && defined (__ia64__)
-#define SC_GP 29
+#include <sys/uc_access.h>
-char *
-__gnat_get_code_loc (struct sigcontext *context)
-{
- return (char *) context->sc_pc;
-}
+#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
void
-__gnat_set_code_loc (struct sigcontext *context, char *pc)
+__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
{
- context->sc_pc = (long) pc;
-}
+ ucontext_t *uc = (ucontext_t *) ucontext;
+ uint64_t ip;
-size_t
-__gnat_machine_state_length (void)
-{
- return sizeof (struct sigcontext);
+ /* Adjust on itanium, as GetIPInfo is not supported. */
+ __uc_get_ip (uc, &ip);
+ __uc_set_ip (uc, ip + 1);
}
+#endif /* IN_RTS && __ia64__ */
-/*****************/
-/* HP-UX section */
-/*****************/
-
-#elif defined (__hpux__)
-
-#include <signal.h>
-#include <sys/ucontext.h>
-
-static void
-__gnat_error_handler (int sig, siginfo_t *siginfo, void *ucontext);
+/* Tasking and Non-tasking signal handler. Map SIGnal to Ada exception
+ propagation after the required low level adjustments. */
static void
-__gnat_error_handler
- (int sig, siginfo_t *siginfo ATTRIBUTE_UNUSED, void *ucontext)
+__gnat_error_handler (int sig,
+ siginfo_t *si ATTRIBUTE_UNUSED,
+ void *ucontext ATTRIBUTE_UNUSED)
{
struct Exception_Data *exception;
const char *msg;
+ __gnat_adjust_context_for_raise (sig, ucontext);
+
switch (sig)
{
case SIGSEGV:
/* GNU/Linux Section */
/*********************/
-#elif defined (linux) && (defined (i386) || defined (__x86_64__) \
- || defined (__ia64__) || defined (__powerpc__))
+#elif defined (__linux__)
#include <signal.h>
#pragma weak linux_sigaction
int linux_sigaction (int signum, const struct sigaction *act,
- struct sigaction *oldact) {
+ struct sigaction *oldact)
+{
return sigaction (signum, act, oldact);
}
#define sigaction(signum, act, oldact) linux_sigaction (signum, act, oldact)
#pragma weak fake_linux_sigfillset
-void fake_linux_sigfillset (sigset_t *set) {
+void fake_linux_sigfillset (sigset_t *set)
+{
sigfillset (set);
}
#define sigfillset(set) fake_linux_sigfillset (set)
#pragma weak fake_linux_sigemptyset
-void fake_linux_sigemptyset (sigset_t *set) {
+void fake_linux_sigemptyset (sigset_t *set)
+{
sigemptyset (set);
}
#define sigemptyset(set) fake_linux_sigemptyset (set)
#endif
-static void __gnat_error_handler (int, siginfo_t *siginfo, void *ucontext);
-
-#if defined (i386) || defined (__x86_64__) || defined (__ia64__)
+#if defined (__i386__) || defined (__x86_64__) || defined (__ia64__) \
+ || defined (__ARMEL__)
#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
by the time the EH return is executed.
We therefore adjust the saved value of the stack pointer by the size
- of one page, in order to make sure that it points to an accessible
- address in case it's used as the target CFA. The stack checking code
- guarantees that this page is unused by the time this happens. */
+ of one page + a small dope of 4 words, in order to make sure that it
+ points to an accessible address in case it's used as the target CFA.
+ The stack checking code guarantees that this address is unused by the
+ time this happens. */
-#if defined (i386)
- unsigned long pattern = *(unsigned long *)mcontext->gregs[REG_EIP];
+#if defined (__i386__)
+ unsigned long *pc = (unsigned long *)mcontext->gregs[REG_EIP];
/* The pattern is "orl $0x0,(%esp)" for a probe in 32-bit mode. */
- if (signo == SIGSEGV && pattern == 0x00240c83)
- mcontext->gregs[REG_ESP] += 4096;
+ if (signo == SIGSEGV && pc && *pc == 0x00240c83)
+ mcontext->gregs[REG_ESP] += 4096 + 4 * sizeof (unsigned long);
#elif defined (__x86_64__)
- unsigned long pattern = *(unsigned long *)mcontext->gregs[REG_RIP];
- /* The pattern is "orq $0x0,(%rsp)" for a probe in 64-bit mode. */
- if (signo == SIGSEGV && (pattern & 0xffffffffff) == 0x00240c8348)
- mcontext->gregs[REG_RSP] += 4096;
+ unsigned long long *pc = (unsigned long long *)mcontext->gregs[REG_RIP];
+ if (signo == SIGSEGV && pc
+ /* The pattern is "orq $0x0,(%rsp)" for a probe in 64-bit mode. */
+ && ((*pc & 0xffffffffffLL) == 0x00240c8348LL
+ /* The pattern may also be "orl $0x0,(%esp)" for a probe in
+ x32 mode. */
+ || (*pc & 0xffffffffLL) == 0x00240c83LL))
+ mcontext->gregs[REG_RSP] += 4096 + 4 * sizeof (unsigned long);
#elif defined (__ia64__)
/* ??? The IA-64 unwinder doesn't compensate for signals. */
mcontext->sc_ip++;
+#elif defined (__ARMEL__)
+ /* ARM Bump has to be an even number because of odd/even architecture. */
+ mcontext->arm_pc+=2;
#endif
}
#endif
static void
-__gnat_error_handler (int sig,
- siginfo_t *siginfo ATTRIBUTE_UNUSED,
- void *ucontext)
+__gnat_error_handler (int sig, siginfo_t *si ATTRIBUTE_UNUSED, void *ucontext)
{
struct Exception_Data *exception;
const char *msg;
- static int recurse = 0;
+
+ /* Adjusting is required for every fault context, so adjust for this one
+ now, before we possibly trigger a recursive fault below. */
+ __gnat_adjust_context_for_raise (sig, ucontext);
switch (sig)
{
case SIGSEGV:
- /* If the problem was permissions, this is a constraint error.
- Likewise if the failing address isn't maximally aligned or if
- we've recursed.
-
- ??? Using a static variable here isn't task-safe, but it's
- much too hard to do anything else and we're just determining
- which exception to raise. */
- if (recurse)
- {
- exception = &constraint_error;
- msg = "SIGSEGV";
- }
- else
- {
- /* Here we would like a discrimination test to see whether the
- page before the faulting address is accessible. Unfortunately
- Linux seems to have no way of giving us the faulting address.
-
- In versions of a-init.c before 1.95, we had a test of the page
- before the stack pointer using:
+ /* Here we would like a discrimination test to see whether the page
+ before the faulting address is accessible. Unfortunately, Linux
+ seems to have no way of giving us the faulting address.
- recurse++;
- ((volatile char *)
- ((long) info->esp_at_signal & - getpagesize ()))[getpagesize ()];
+ In old versions of init.c, we had a test of the page before the
+ stack pointer:
- but that's wrong, since it tests the stack pointer location, and
- the current stack probe code does not move the stack pointer
- until all probes succeed.
+ ((volatile char *)
+ ((long) si->esp_at_signal & - getpagesize ()))[getpagesize ()];
- For now we simply do not attempt any discrimination at all. Note
- that this is quite acceptable, since a "real" SIGSEGV can only
- occur as the result of an erroneous program. */
+ but that's wrong since it tests the stack pointer location and the
+ stack probing code may not move it until all probes succeed.
- msg = "stack overflow (or erroneous memory access)";
- exception = &storage_error;
- }
+ For now we simply do not attempt any discrimination at all. Note
+ that this is quite acceptable, since a "real" SIGSEGV can only
+ occur as the result of an erroneous program. */
+ exception = &storage_error;
+ msg = "stack overflow or erroneous memory access";
break;
case SIGBUS:
- exception = &constraint_error;
- msg = "SIGBUS";
+ exception = &storage_error;
+ msg = "SIGBUS: possible stack overflow";
break;
case SIGFPE:
exception = &program_error;
msg = "unhandled signal";
}
- recurse = 0;
-
- /* We adjust the interrupted context here (and not in the fallback
- unwinding routine) because recent versions of the Native POSIX
- Thread Library (NPTL) are compiled with unwind information, so
- the fallback routine is never executed for signal frames. */
- __gnat_adjust_context_for_raise (sig, ucontext);
Raise_From_Signal_Handler (exception, msg);
}
-#if defined (i386) || defined (__x86_64__)
-/* This must be in keeping with System.OS_Interface.Alternate_Stack_Size. */
-char __gnat_alternate_stack[16 * 1024]; /* 2 * SIGSTKSZ */
+#ifndef __ia64__
+#define HAVE_GNAT_ALTERNATE_STACK 1
+/* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.
+ It must be larger than MINSIGSTKSZ and hopefully near 2 * SIGSTKSZ. */
+# if 16 * 1024 < MINSIGSTKSZ
+# error "__gnat_alternate_stack too small"
+# endif
+char __gnat_alternate_stack[16 * 1024];
#endif
#ifdef __XENO__
/* Turn the current Linux task into a native Xenomai task */
- rt_task_shadow(&main_task, "environment_task", prio, T_FPU);
+ rt_task_shadow (&main_task, "environment_task", prio, T_FPU);
#endif
/* Set up signal handler to map synchronous signals to appropriate
handled properly, avoiding a SEGV generation from stack usage by the
handler itself. */
-#if defined (i386) || defined (__x86_64__)
- stack_t stack;
- stack.ss_sp = __gnat_alternate_stack;
- stack.ss_size = sizeof (__gnat_alternate_stack);
- stack.ss_flags = 0;
- sigaltstack (&stack, NULL);
-#endif
-
act.sa_sigaction = __gnat_error_handler;
act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
sigemptyset (&act.sa_mask);
sigaction (SIGILL, &act, NULL);
if (__gnat_get_interrupt_state (SIGBUS) != 's')
sigaction (SIGBUS, &act, NULL);
-#if defined (i386) || defined (__x86_64__)
- act.sa_flags |= SA_ONSTACK;
-#endif
if (__gnat_get_interrupt_state (SIGSEGV) != 's')
- sigaction (SIGSEGV, &act, NULL);
-
- __gnat_handler_installed = 1;
-}
-
-/****************/
-/* IRIX Section */
-/****************/
-
-#elif defined (sgi)
-
-#include <signal.h>
-#include <siginfo.h>
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#define SIGADAABORT 48
-#define SIGNAL_STACK_SIZE 4096
-#define SIGNAL_STACK_ALIGNMENT 64
-
-#define Check_Abort_Status \
- system__soft_links__check_abort_status
-extern int (*Check_Abort_Status) (void);
-
-extern struct Exception_Data _abort_signal;
-
-static void __gnat_error_handler (int, int, sigcontext_t *);
-
-/* We are not setting the SA_SIGINFO bit in the sigaction flags when
- connecting that handler, with the effects described in the sigaction
- man page:
-
- SA_SIGINFO [...]
- If cleared and the signal is caught, the first argument is
- also the signal number but the second argument is the signal
- code identifying the cause of the signal. The third argument
- points to a sigcontext_t structure containing the receiving
- process's context when the signal was delivered. */
-
-static void
-__gnat_error_handler (int sig, int code, sigcontext_t *sc ATTRIBUTE_UNUSED)
-{
- struct Exception_Data *exception;
- const char *msg;
-
- switch (sig)
{
- case SIGSEGV:
- if (code == EFAULT)
- {
- exception = &program_error;
- msg = "SIGSEGV: (Invalid virtual address)";
- }
- else if (code == ENXIO)
- {
- exception = &program_error;
- msg = "SIGSEGV: (Read beyond mapped object)";
- }
- else if (code == ENOSPC)
- {
- exception = &program_error; /* ??? storage_error ??? */
- msg = "SIGSEGV: (Autogrow for file failed)";
- }
- else if (code == EACCES || code == EEXIST)
- {
- /* ??? We handle stack overflows here, some of which do trigger
- SIGSEGV + EEXIST on Irix 6.5 although EEXIST is not part of
- the documented valid codes for SEGV in the signal(5) man
- page. */
-
- /* ??? Re-add smarts to further verify that we launched
- the stack into a guard page, not an attempt to
- write to .text or something. */
- exception = &storage_error;
- msg = "SIGSEGV: (stack overflow or erroneous memory access)";
- }
- else
- {
- /* Just in case the OS guys did it to us again. Sometimes
- they fail to document all of the valid codes that are
- passed to signal handlers, just in case someone depends
- on knowing all the codes. */
- exception = &program_error;
- msg = "SIGSEGV: (Undocumented reason)";
- }
- break;
-
- case SIGBUS:
- /* Map all bus errors to Program_Error. */
- exception = &program_error;
- msg = "SIGBUS";
- break;
-
- case SIGFPE:
- /* Map all fpe errors to Constraint_Error. */
- exception = &constraint_error;
- msg = "SIGFPE";
- break;
-
- case SIGADAABORT:
- if ((*Check_Abort_Status) ())
- {
- exception = &_abort_signal;
- msg = "";
- }
- else
- return;
-
- break;
-
- default:
- /* Everything else is a Program_Error. */
- exception = &program_error;
- msg = "unhandled signal";
+#ifdef HAVE_GNAT_ALTERNATE_STACK
+ /* Setup an alternate stack region for the handler execution so that
+ stack overflows can be handled properly, avoiding a SEGV generation
+ from stack usage by the handler itself. */
+ stack_t stack;
+
+ stack.ss_sp = __gnat_alternate_stack;
+ stack.ss_size = sizeof (__gnat_alternate_stack);
+ stack.ss_flags = 0;
+ sigaltstack (&stack, NULL);
+
+ act.sa_flags |= SA_ONSTACK;
+#endif
+ sigaction (SIGSEGV, &act, NULL);
}
- Raise_From_Signal_Handler (exception, msg);
-}
-
-void
-__gnat_install_handler (void)
-{
- struct sigaction act;
-
- /* Setup signal handler to map synchronous signals to appropriate
- exceptions. Make sure that the handler isn't interrupted by another
- signal that might cause a scheduling event! */
-
- act.sa_handler = __gnat_error_handler;
- act.sa_flags = SA_NODEFER + SA_RESTART;
- sigfillset (&act.sa_mask);
- sigemptyset (&act.sa_mask);
-
- /* Do not install handlers if interrupt state is "System". */
- if (__gnat_get_interrupt_state (SIGABRT) != 's')
- sigaction (SIGABRT, &act, NULL);
- if (__gnat_get_interrupt_state (SIGFPE) != 's')
- sigaction (SIGFPE, &act, NULL);
- if (__gnat_get_interrupt_state (SIGILL) != 's')
- sigaction (SIGILL, &act, NULL);
- if (__gnat_get_interrupt_state (SIGSEGV) != 's')
- sigaction (SIGSEGV, &act, NULL);
- if (__gnat_get_interrupt_state (SIGBUS) != 's')
- sigaction (SIGBUS, &act, NULL);
- if (__gnat_get_interrupt_state (SIGADAABORT) != 's')
- sigaction (SIGADAABORT, &act, NULL);
-
__gnat_handler_installed = 1;
}
msg = "unhandled signal";
}
- Raise_From_Signal_Handler(exception, msg);
+ Raise_From_Signal_Handler (exception, msg);
}
void
/* Solaris Section */
/*******************/
-#elif defined (sun) && defined (__SVR4) && !defined (__vxworks)
+#elif defined (__sun__) && !defined (__vxworks)
#include <signal.h>
#include <siginfo.h>
#include <sys/ucontext.h>
#include <sys/regset.h>
-/* The code below is common to SPARC and x86. Beware of the delay slot
- differences for signal context adjustments. */
-
-#if defined (__sparc)
-#define RETURN_ADDR_OFFSET 8
-#else
-#define RETURN_ADDR_OFFSET 0
-#endif
-
-/* Likewise regarding how the "instruction pointer" register slot can
- be identified in signal machine contexts. We have either "REG_PC"
- or "PC" at hand, depending on the target CPU and Solaris version. */
-
-#if !defined (REG_PC)
-#define REG_PC PC
-#endif
-
-static void __gnat_error_handler (int, siginfo_t *, ucontext_t *);
-
static void
-__gnat_error_handler (int sig, siginfo_t *sip, ucontext_t *uctx)
+__gnat_error_handler (int sig, siginfo_t *si, void *ucontext ATTRIBUTE_UNUSED)
{
struct Exception_Data *exception;
static int recurse = 0;
const char *msg;
- /* If this was an explicit signal from a "kill", just resignal it. */
- if (SI_FROMUSER (sip))
- {
- signal (sig, SIG_DFL);
- kill (getpid(), sig);
- }
-
- /* Otherwise, treat it as something we handle. */
switch (sig)
{
case SIGSEGV:
??? Using a static variable here isn't task-safe, but it's
much too hard to do anything else and we're just determining
which exception to raise. */
- if (sip->si_code == SEGV_ACCERR
- || (((long) sip->si_addr) & 3) != 0
+ if (si->si_code == SEGV_ACCERR
+ || (long) si->si_addr == 0
+ || (((long) si->si_addr) & 3) != 0
|| recurse)
{
exception = &constraint_error;
the actual address, just to be on the same page. */
recurse++;
((volatile char *)
- ((long) sip->si_addr & - getpagesize ()))[getpagesize ()];
+ ((long) si->si_addr & - getpagesize ()))[getpagesize ()];
exception = &storage_error;
- msg = "stack overflow (or erroneous memory access)";
+ msg = "stack overflow or erroneous memory access";
}
break;
}
recurse = 0;
-
Raise_From_Signal_Handler (exception, msg);
}
exceptions. Make sure that the handler isn't interrupted by another
signal that might cause a scheduling event! */
- act.sa_handler = __gnat_error_handler;
+ act.sa_sigaction = __gnat_error_handler;
act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
sigemptyset (&act.sa_mask);
#elif defined (VMS)
/* Routine called from binder to override default feature values. */
-void __gnat_set_features ();
+void __gnat_set_features (void);
int __gnat_features_set = 0;
-
-long __gnat_error_handler (int *, void *);
+void (*__gnat_ctrl_c_handler) (void) = 0;
#ifdef __IA64
#define lib_get_curr_invo_context LIB$I64_GET_CURR_INVO_CONTEXT
#define lib_get_invo_handle LIB$GET_INVO_HANDLE
#endif
-#if defined (IN_RTS) && !defined (__IA64)
-
-/* The prehandler actually gets control first on a condition. It swaps the
- stack pointer and calls the handler (__gnat_error_handler). */
-extern long __gnat_error_prehandler (void);
-
-extern char *__gnat_error_prehandler_stack; /* Alternate signal stack */
-#endif
+/* Masks for facility identification. */
+#define FAC_MASK 0x0fff0000
+#define DECADA_M_FACILITY 0x00310000
/* Define macro symbols for the VMS conditions that become Ada exceptions.
- Most of these are also defined in the header file ssdef.h which has not
- yet been converted to be recognized by GNU C. */
+ It would be better to just include <ssdef.h> */
-/* Defining these as macros, as opposed to external addresses, allows
- them to be used in a case statement below. */
+#define SS$_CONTINUE 1
#define SS$_ACCVIO 12
#define SS$_HPARITH 1284
+#define SS$_INTDIV 1156
#define SS$_STKOVF 1364
+#define SS$_CONTROLC 1617
#define SS$_RESIGNAL 2328
+#define MTH$_FLOOVEMAT 1475268 /* Some ACVC_21 CXA tests */
+
+/* The following codes must be resignalled, and not handled here. */
+
/* These codes are in standard message libraries. */
-extern int CMA$_EXIT_THREAD;
+extern int C$_SIGKILL;
+extern int C$_SIGINT;
extern int SS$_DEBUG;
-extern int SS$_INTDIV;
extern int LIB$_KEYNOTFOU;
extern int LIB$_ACTIMAGE;
-extern int MTH$_FLOOVEMAT; /* Some ACVC_21 CXA tests */
/* These codes are non standard, which is to say the author is
not sure if they are defined in the standard message libraries
so keep them as macros for now. */
#define RDB$_STREAM_EOF 20480426
#define FDL$_UNPRIKW 11829410
+#define CMA$_EXIT_THREAD 4227492
+
+struct cond_sigargs
+{
+ unsigned int sigarg;
+ unsigned int sigargval;
+};
+
+struct cond_subtests
+{
+ unsigned int num;
+ const struct cond_sigargs sigargs[];
+};
-struct cond_except {
- const int *cond;
+struct cond_except
+{
+ unsigned int cond;
const struct Exception_Data *except;
+ unsigned int needs_adjust; /* 1 = adjust PC, 0 = no adjust */
+ const struct cond_subtests *subtests;
};
-struct descriptor_s {unsigned short len, mbz; __char_ptr32 adr; };
+struct descriptor_s
+{
+ unsigned short len, mbz;
+ __char_ptr32 adr;
+};
/* Conditions that don't have an Ada exception counterpart must raise
Non_Ada_Error. Since this is defined in s-auxdec, it should only be
extern struct Exception_Data Non_Ada_Error;
#define Coded_Exception system__vms_exception_table__coded_exception
-extern struct Exception_Data *Coded_Exception (Exception_Code);
+extern struct Exception_Data *Coded_Exception (void *);
#define Base_Code_In system__vms_exception_table__base_code_in
-extern Exception_Code Base_Code_In (Exception_Code);
+extern void *Base_Code_In (void *);
/* DEC Ada exceptions are not defined in a header file, so they
- must be declared as external addresses. */
-
-extern int ADA$_PROGRAM_ERROR;
-extern int ADA$_LOCK_ERROR;
-extern int ADA$_EXISTENCE_ERROR;
-extern int ADA$_KEY_ERROR;
-extern int ADA$_KEYSIZERR;
-extern int ADA$_STAOVF;
-extern int ADA$_CONSTRAINT_ERRO;
-extern int ADA$_IOSYSFAILED;
-extern int ADA$_LAYOUT_ERROR;
-extern int ADA$_STORAGE_ERROR;
-extern int ADA$_DATA_ERROR;
-extern int ADA$_DEVICE_ERROR;
-extern int ADA$_END_ERROR;
-extern int ADA$_MODE_ERROR;
-extern int ADA$_NAME_ERROR;
-extern int ADA$_STATUS_ERROR;
-extern int ADA$_NOT_OPEN;
-extern int ADA$_ALREADY_OPEN;
-extern int ADA$_USE_ERROR;
-extern int ADA$_UNSUPPORTED;
-extern int ADA$_FAC_MODE_MISMAT;
-extern int ADA$_ORG_MISMATCH;
-extern int ADA$_RFM_MISMATCH;
-extern int ADA$_RAT_MISMATCH;
-extern int ADA$_MRS_MISMATCH;
-extern int ADA$_MRN_MISMATCH;
-extern int ADA$_KEY_MISMATCH;
-extern int ADA$_MAXLINEXC;
-extern int ADA$_LINEXCMRS;
+ must be declared. */
+
+#define ADA$_ALREADY_OPEN 0x0031a594
+#define ADA$_CONSTRAINT_ERRO 0x00318324
+#define ADA$_DATA_ERROR 0x003192c4
+#define ADA$_DEVICE_ERROR 0x003195e4
+#define ADA$_END_ERROR 0x00319904
+#define ADA$_FAC_MODE_MISMAT 0x0031a8b3
+#define ADA$_IOSYSFAILED 0x0031af04
+#define ADA$_KEYSIZERR 0x0031aa3c
+#define ADA$_KEY_MISMATCH 0x0031a8e3
+#define ADA$_LAYOUT_ERROR 0x00319c24
+#define ADA$_LINEXCMRS 0x0031a8f3
+#define ADA$_MAXLINEXC 0x0031a8eb
+#define ADA$_MODE_ERROR 0x00319f44
+#define ADA$_MRN_MISMATCH 0x0031a8db
+#define ADA$_MRS_MISMATCH 0x0031a8d3
+#define ADA$_NAME_ERROR 0x0031a264
+#define ADA$_NOT_OPEN 0x0031a58c
+#define ADA$_ORG_MISMATCH 0x0031a8bb
+#define ADA$_PROGRAM_ERROR 0x00318964
+#define ADA$_RAT_MISMATCH 0x0031a8cb
+#define ADA$_RFM_MISMATCH 0x0031a8c3
+#define ADA$_STAOVF 0x00318cac
+#define ADA$_STATUS_ERROR 0x0031a584
+#define ADA$_STORAGE_ERROR 0x00318c84
+#define ADA$_UNSUPPORTED 0x0031a8ab
+#define ADA$_USE_ERROR 0x0031a8a4
/* DEC Ada specific conditions. */
-static const struct cond_except dec_ada_cond_except_table [] = {
- {&ADA$_PROGRAM_ERROR, &program_error},
- {&ADA$_USE_ERROR, &Use_Error},
- {&ADA$_KEYSIZERR, &program_error},
- {&ADA$_STAOVF, &storage_error},
- {&ADA$_CONSTRAINT_ERRO, &constraint_error},
- {&ADA$_IOSYSFAILED, &Device_Error},
- {&ADA$_LAYOUT_ERROR, &Layout_Error},
- {&ADA$_STORAGE_ERROR, &storage_error},
- {&ADA$_DATA_ERROR, &Data_Error},
- {&ADA$_DEVICE_ERROR, &Device_Error},
- {&ADA$_END_ERROR, &End_Error},
- {&ADA$_MODE_ERROR, &Mode_Error},
- {&ADA$_NAME_ERROR, &Name_Error},
- {&ADA$_STATUS_ERROR, &Status_Error},
- {&ADA$_NOT_OPEN, &Use_Error},
- {&ADA$_ALREADY_OPEN, &Use_Error},
- {&ADA$_USE_ERROR, &Use_Error},
- {&ADA$_UNSUPPORTED, &Use_Error},
- {&ADA$_FAC_MODE_MISMAT, &Use_Error},
- {&ADA$_ORG_MISMATCH, &Use_Error},
- {&ADA$_RFM_MISMATCH, &Use_Error},
- {&ADA$_RAT_MISMATCH, &Use_Error},
- {&ADA$_MRS_MISMATCH, &Use_Error},
- {&ADA$_MRN_MISMATCH, &Use_Error},
- {&ADA$_KEY_MISMATCH, &Use_Error},
- {&ADA$_MAXLINEXC, &constraint_error},
- {&ADA$_LINEXCMRS, &constraint_error},
- {0, 0}
-};
+static const struct cond_except dec_ada_cond_except_table [] =
+{
+ {ADA$_PROGRAM_ERROR, &program_error, 0, 0},
+ {ADA$_USE_ERROR, &Use_Error, 0, 0},
+ {ADA$_KEYSIZERR, &program_error, 0, 0},
+ {ADA$_STAOVF, &storage_error, 0, 0},
+ {ADA$_CONSTRAINT_ERRO, &constraint_error, 0, 0},
+ {ADA$_IOSYSFAILED, &Device_Error, 0, 0},
+ {ADA$_LAYOUT_ERROR, &Layout_Error, 0, 0},
+ {ADA$_STORAGE_ERROR, &storage_error, 0, 0},
+ {ADA$_DATA_ERROR, &Data_Error, 0, 0},
+ {ADA$_DEVICE_ERROR, &Device_Error, 0, 0},
+ {ADA$_END_ERROR, &End_Error, 0, 0},
+ {ADA$_MODE_ERROR, &Mode_Error, 0, 0},
+ {ADA$_NAME_ERROR, &Name_Error, 0, 0},
+ {ADA$_STATUS_ERROR, &Status_Error, 0, 0},
+ {ADA$_NOT_OPEN, &Use_Error, 0, 0},
+ {ADA$_ALREADY_OPEN, &Use_Error, 0, 0},
+ {ADA$_USE_ERROR, &Use_Error, 0, 0},
+ {ADA$_UNSUPPORTED, &Use_Error, 0, 0},
+ {ADA$_FAC_MODE_MISMAT, &Use_Error, 0, 0},
+ {ADA$_ORG_MISMATCH, &Use_Error, 0, 0},
+ {ADA$_RFM_MISMATCH, &Use_Error, 0, 0},
+ {ADA$_RAT_MISMATCH, &Use_Error, 0, 0},
+ {ADA$_MRS_MISMATCH, &Use_Error, 0, 0},
+ {ADA$_MRN_MISMATCH, &Use_Error, 0, 0},
+ {ADA$_KEY_MISMATCH, &Use_Error, 0, 0},
+ {ADA$_MAXLINEXC, &constraint_error, 0, 0},
+ {ADA$_LINEXCMRS, &constraint_error, 0, 0},
#if 0
/* Already handled by a pragma Import_Exception
in Aux_IO_Exceptions */
- {&ADA$_LOCK_ERROR, &Lock_Error},
- {&ADA$_EXISTENCE_ERROR, &Existence_Error},
- {&ADA$_KEY_ERROR, &Key_Error},
+ {ADA$_LOCK_ERROR, &Lock_Error, 0, 0},
+ {ADA$_EXISTENCE_ERROR, &Existence_Error, 0, 0},
+ {ADA$_KEY_ERROR, &Key_Error, 0, 0},
#endif
+ {0, 0, 0, 0}
+};
+
#endif /* IN_RTS */
-/* Non-DEC Ada specific conditions. We could probably also put
- SS$_HPARITH here and possibly SS$_ACCVIO, SS$_STKOVF. */
-static const struct cond_except cond_except_table [] = {
- {&MTH$_FLOOVEMAT, &constraint_error},
- {&SS$_INTDIV, &constraint_error},
- {0, 0}
+/* Non-DEC Ada specific conditions that map to Ada exceptions. */
+
+/* Subtest for ACCVIO Constraint_Error, kept for compatibility,
+ in hindsight should have just made ACCVIO == Storage_Error. */
+#define ACCVIO_VIRTUAL_ADDR 3
+static const struct cond_subtests accvio_c_e =
+{1, /* number of subtests below */
+ {
+ { ACCVIO_VIRTUAL_ADDR, 0 }
+ }
+};
+
+/* Macro flag to adjust PC which gets off by one for some conditions,
+ not sure if this is reliably true, PC could be off by more for
+ HPARITH for example, unless a trapb is inserted. */
+#define NEEDS_ADJUST 1
+
+static const struct cond_except system_cond_except_table [] =
+{
+ {MTH$_FLOOVEMAT, &constraint_error, 0, 0},
+ {SS$_INTDIV, &constraint_error, 0, 0},
+ {SS$_HPARITH, &constraint_error, NEEDS_ADJUST, 0},
+ {SS$_ACCVIO, &constraint_error, NEEDS_ADJUST, &accvio_c_e},
+ {SS$_ACCVIO, &storage_error, NEEDS_ADJUST, 0},
+ {SS$_STKOVF, &storage_error, NEEDS_ADJUST, 0},
+ {0, 0, 0, 0}
};
/* To deal with VMS conditions and their mapping to Ada exceptions,
That predicate function is called indirectly, via a function pointer,
by __gnat_error_handler, and changing that pointer is allowed to the
- the user code by way of the __gnat_set_resignal_predicate interface.
+ user code by way of the __gnat_set_resignal_predicate interface.
The user level function may then implement what it likes, including
for instance the maintenance of a dynamic data structure if the set
should be use with caution since the implementation has been kept
very simple. */
-typedef int
-resignal_predicate (int code);
+typedef int resignal_predicate (int code);
-const int *cond_resignal_table [] = {
- &CMA$_EXIT_THREAD,
+static const int * const cond_resignal_table [] =
+{
+ &C$_SIGKILL,
+ (int *)CMA$_EXIT_THREAD,
&SS$_DEBUG,
&LIB$_KEYNOTFOU,
&LIB$_ACTIMAGE,
0
};
-const int facility_resignal_table [] = {
+static const int facility_resignal_table [] =
+{
0x1380000, /* RDB */
0x2220000, /* SQL */
0
int i, iexcept;
for (i = 0; facility_resignal_table [i]; i++)
- if ((code & 0xfff0000) == facility_resignal_table [i])
+ if ((code & FAC_MASK) == facility_resignal_table [i])
return 1;
for (i = 0, iexcept = 0;
- cond_resignal_table [i] &&
- !(iexcept = LIB$MATCH_COND (&code, &cond_resignal_table [i]));
+ cond_resignal_table [i]
+ && !(iexcept = LIB$MATCH_COND (&code, &cond_resignal_table [i]));
i++);
return iexcept;
/* Static pointer to predicate that the __gnat_error_handler exception
vector invokes to determine if it should resignal a condition. */
-static resignal_predicate * __gnat_resignal_p = __gnat_default_resignal_p;
+static resignal_predicate *__gnat_resignal_p = __gnat_default_resignal_p;
/* User interface to change the predicate pointer to PREDICATE. Reset to
the default if PREDICATE is null. */
void
-__gnat_set_resignal_predicate (resignal_predicate * predicate)
+__gnat_set_resignal_predicate (resignal_predicate *predicate)
{
- if (predicate == 0)
+ if (predicate == NULL)
__gnat_resignal_p = __gnat_default_resignal_p;
else
__gnat_resignal_p = predicate;
/* Action routine for SYS$PUTMSG. There may be multiple
conditions, each with text to be appended to MESSAGE
and separated by line termination. */
-
static int
-copy_msg (msgdesc, message)
- struct descriptor_s *msgdesc;
- char *message;
+copy_msg (struct descriptor_s *msgdesc, char *message)
{
int len = strlen (message);
int copy_len;
return 0;
}
+/* Scan TABLE for a match for the condition contained in SIGARGS,
+ and return the entry, or the empty entry if no match found. */
+static const struct cond_except *
+scan_conditions ( int *sigargs, const struct cond_except *table [])
+{
+ int i;
+ struct cond_except entry;
+
+ /* Scan the exception condition table for a match and fetch
+ the associated GNAT exception pointer. */
+ for (i = 0; (*table) [i].cond; i++)
+ {
+ unsigned int match = LIB$MATCH_COND (&sigargs [1], &(*table) [i].cond);
+ const struct cond_subtests *subtests = (*table) [i].subtests;
+
+ if (match)
+ {
+ if (!subtests)
+ {
+ return &(*table) [i];
+ }
+ else
+ {
+ unsigned int ii;
+ int num = (*subtests).num;
+
+ /* Perform subtests to differentiate exception. */
+ for (ii = 0; ii < num; ii++)
+ {
+ unsigned int arg = (*subtests).sigargs [ii].sigarg;
+ unsigned int argval = (*subtests).sigargs [ii].sigargval;
+
+ if (sigargs [arg] != argval)
+ {
+ num = 0;
+ break;
+ }
+ }
+
+ /* All subtests passed. */
+ if (num == (*subtests).num)
+ return &(*table) [i];
+ }
+ }
+ }
+
+ /* No match, return the null terminating entry. */
+ return &(*table) [i];
+}
+
+/* __gnat_handle_vms_condtition is both a frame based handler
+ for the runtime, and an exception vector for the compiler. */
long
__gnat_handle_vms_condition (int *sigargs, void *mechargs)
{
struct Exception_Data *exception = 0;
- Exception_Code base_code;
- struct descriptor_s gnat_facility = {4,0,"GNAT"};
+ unsigned int needs_adjust = 0;
+ void *base_code;
+ struct descriptor_s gnat_facility = {4, 0, "GNAT"};
char message [Default_Exception_Msg_Max_Length];
const char *msg = "";
Import_Exception. */
if (__gnat_resignal_p (sigargs [1]))
return SS$_RESIGNAL;
+#ifndef IN_RTS
+ /* toplev.c handles this for compiler. */
+ if (sigargs [1] == SS$_HPARITH)
+ return SS$_RESIGNAL;
+#endif
#ifdef IN_RTS
/* See if it's an imported exception. Beware that registered exceptions
are bound to their base code, with the severity bits masked off. */
- base_code = Base_Code_In ((Exception_Code) sigargs [1]);
+ base_code = Base_Code_In ((void *) sigargs[1]);
exception = Coded_Exception (base_code);
+#endif
- if (exception)
+ if (exception == 0)
+#ifdef IN_RTS
{
- message [0] = 0;
-
- /* Subtract PC & PSL fields which messes with PUTMSG. */
- sigargs [0] -= 2;
- SYS$PUTMSG (sigargs, copy_msg, &gnat_facility, message);
- sigargs [0] += 2;
- msg = message;
+ int i;
+ struct cond_except cond;
+ const struct cond_except *cond_table;
+ const struct cond_except *cond_tables [] = {dec_ada_cond_except_table,
+ system_cond_except_table,
+ 0};
+ unsigned int ctrlc = SS$_CONTROLC;
+ unsigned int *sigint = &C$_SIGINT;
+ int ctrlc_match = LIB$MATCH_COND (&sigargs [1], &ctrlc);
+ int sigint_match = LIB$MATCH_COND (&sigargs [1], &sigint);
+
+ extern int SYS$DCLAST (void (*astadr)(), unsigned long long astprm,
+ unsigned int acmode);
+
+ /* If SS$_CONTROLC has been imported as an exception, it will take
+ priority over a a Ctrl/C handler. See above. SIGINT has a
+ different condition value due to it's DECCCRTL roots and it's
+ the condition that gets raised for a "kill -INT". */
+ if ((ctrlc_match || sigint_match) && __gnat_ctrl_c_handler)
+ {
+ SYS$DCLAST (__gnat_ctrl_c_handler, 0, 0);
+ return SS$_CONTINUE;
+ }
- exception->Name_Length = 19;
- /* ??? The full name really should be get sys$getmsg returns. */
- exception->Full_Name = "IMPORTED_EXCEPTION";
- exception->Import_Code = base_code;
+ i = 0;
+ while ((cond_table = cond_tables[i++]) && !exception)
+ {
+ cond = *scan_conditions (sigargs, &cond_table);
+ exception = (struct Exception_Data *) cond.except;
+ }
-#ifdef __IA64
- /* Do not adjust the program counter as already points to the next
- instruction (just after the call to LIB$STOP). */
- Raise_From_Signal_Handler (exception, msg);
-#endif
+ if (exception)
+ needs_adjust = cond.needs_adjust;
+ else
+ /* User programs expect Non_Ada_Error to be raised if no match,
+ reference DEC Ada test CXCONDHAN. */
+ exception = &Non_Ada_Error;
+ }
+#else
+ {
+ /* Pretty much everything is just a program error in the compiler */
+ exception = &program_error;
}
#endif
- if (exception == 0)
- switch (sigargs[1])
- {
- case SS$_ACCVIO:
- if (sigargs[3] == 0)
- {
- exception = &constraint_error;
- msg = "access zero";
- }
- else
- {
- exception = &storage_error;
- msg = "stack overflow (or erroneous memory access)";
- }
- __gnat_adjust_context_for_raise (0, (void *)mechargs);
- break;
+ message[0] = 0;
+ /* Subtract PC & PSL fields as per ABI for SYS$PUTMSG. */
+ sigargs[0] -= 2;
- case SS$_STKOVF:
- exception = &storage_error;
- msg = "stack overflow";
- __gnat_adjust_context_for_raise (0, (void *)mechargs);
- break;
+ extern int SYS$PUTMSG (void *, int (*)(), void *, unsigned long long);
- case SS$_HPARITH:
-#ifndef IN_RTS
- return SS$_RESIGNAL; /* toplev.c handles for compiler */
-#else
- exception = &constraint_error;
- msg = "arithmetic error";
-#ifndef __alpha__
- /* No need to adjust pc on Alpha: the pc is already on the instruction
- after the trapping one. */
- __gnat_adjust_context_for_raise (0, (void *)mechargs);
-#endif
-#endif
- break;
+ /* If it was a DEC Ada specific condtiion, make it GNAT otherwise
+ keep the old facility. */
+ if (sigargs [1] & FAC_MASK == DECADA_M_FACILITY)
+ SYS$PUTMSG (sigargs, copy_msg, &gnat_facility,
+ (unsigned long long ) message);
+ else
+ SYS$PUTMSG (sigargs, copy_msg, 0,
+ (unsigned long long ) message);
- default:
-#ifdef IN_RTS
- {
- int i;
-
- /* Scan the DEC Ada exception condition table for a match and fetch
- the associated GNAT exception pointer. */
- for (i = 0;
- dec_ada_cond_except_table [i].cond &&
- !LIB$MATCH_COND (&sigargs [1],
- &dec_ada_cond_except_table [i].cond);
- i++);
- exception = (struct Exception_Data *)
- dec_ada_cond_except_table [i].except;
-
- if (!exception)
- {
- /* Scan the VMS standard condition table for a match and fetch
- the associated GNAT exception pointer. */
- for (i = 0;
- cond_except_table [i].cond &&
- !LIB$MATCH_COND (&sigargs [1], &cond_except_table [i].cond);
- i++);
- exception = (struct Exception_Data *)
- cond_except_table [i].except;
-
- if (!exception)
- /* User programs expect Non_Ada_Error to be raised, reference
- DEC Ada test CXCONDHAN. */
- exception = &Non_Ada_Error;
- }
- }
-#else
- exception = &program_error;
-#endif
- message [0] = 0;
- /* Subtract PC & PSL fields which messes with PUTMSG. */
- sigargs [0] -= 2;
- SYS$PUTMSG (sigargs, copy_msg, &gnat_facility, message);
- sigargs [0] += 2;
- msg = message;
- break;
- }
+ /* Add back PC & PSL fields as per ABI for SYS$PUTMSG. */
+ sigargs[0] += 2;
+ msg = message;
+
+ if (needs_adjust)
+ __gnat_adjust_context_for_raise (sigargs [1], (void *)mechargs);
Raise_From_Signal_Handler (exception, msg);
}
-long
-__gnat_error_handler (int *sigargs, void *mechargs)
+#if defined (IN_RTS) && defined (__IA64)
+/* Called only from adasigio.b32. This is a band aid to avoid going
+ through the VMS signal handling code which results in a 0x8000 per
+ handled exception memory leak in P2 space (see VMS source listing
+ sys/lis/exception.lis) due to the allocation of working space that
+ is expected to be deallocated upon return from the condition handler,
+ which doesn't return in GNAT compiled code. */
+void
+GNAT$STOP (int *sigargs)
{
- return __gnat_handle_vms_condition (sigargs, mechargs);
+ /* Note that there are no mechargs. We rely on the fact that condtions
+ raised from DEClib I/O do not require an "adjust". Also the count
+ will be off by 2, since LIB$STOP didn't get a chance to add the
+ PC and PSL fields, so we bump it so PUTMSG comes out right. */
+ sigargs [0] += 2;
+ __gnat_handle_vms_condition (sigargs, 0);
}
+#endif
void
__gnat_install_handler (void)
long prvhnd ATTRIBUTE_UNUSED;
#if !defined (IN_RTS)
- SYS$SETEXV (1, __gnat_error_handler, 3, &prvhnd);
+ extern int SYS$SETEXV (unsigned int vector, int (*addres)(),
+ unsigned int accmode, void *(*(prvhnd)));
+ SYS$SETEXV (1, __gnat_handle_vms_condition, 3, &prvhnd);
#endif
- /* On alpha-vms, we avoid the global vector annoyance thanks to frame based
- handlers to turn conditions into exceptions since GCC 3.4. The global
- vector is still required for earlier GCC versions. We're resorting to
- the __gnat_error_prehandler assembly function in this case. */
+ __gnat_handler_installed = 1;
+}
+
+/* __gnat_adjust_context_for_raise for Alpha - see comments along with the
+ default version later in this file. */
#if defined (IN_RTS) && defined (__alpha__)
- if ((__GNUC__ * 10 + __GNUC_MINOR__) < 34)
+
+#include <vms/chfctxdef.h>
+#include <vms/chfdef.h>
+
+#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
+
+void
+__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
+{
+ if (signo == SS$_HPARITH)
{
- char * c = (char *) xmalloc (2049);
+ /* Sub one to the address of the instruction signaling the condition,
+ located in the sigargs array. */
- __gnat_error_prehandler_stack = &c[2048];
- SYS$SETEXV (1, __gnat_error_prehandler, 3, &prvhnd);
- }
-#endif
+ CHF$MECH_ARRAY * mechargs = (CHF$MECH_ARRAY *) ucontext;
+ CHF$SIGNAL_ARRAY * sigargs
+ = (CHF$SIGNAL_ARRAY *) mechargs->chf$q_mch_sig_addr;
- __gnat_handler_installed = 1;
+ int vcount = sigargs->chf$is_sig_args;
+ int * pc_slot = & (&sigargs->chf$l_sig_name)[vcount-2];
+
+ (*pc_slot)--;
+ }
}
-/* __gnat_adjust_context_for_raise for Alpha - see comments along with the
- default version later in this file. */
+#endif
-#if defined (IN_RTS) && defined (__alpha__)
+/* __gnat_adjust_context_for_raise for ia64. */
+
+#if defined (IN_RTS) && defined (__IA64)
#include <vms/chfctxdef.h>
#include <vms/chfdef.h>
#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
+typedef unsigned long long u64;
+
void
__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
{
/* Add one to the address of the instruction signaling the condition,
- located in the sigargs array. */
+ located in the 64bits sigargs array. */
+
+ CHF$MECH_ARRAY * mechargs = (CHF$MECH_ARRAY *) ucontext;
+
+ CHF64$SIGNAL_ARRAY *chfsig64
+ = (CHF64$SIGNAL_ARRAY *) mechargs->chf$ph_mch_sig64_addr;
+
+ u64 * post_sigarray
+ = (u64 *)chfsig64 + 1 + chfsig64->chf64$l_sig_args;
+
+ u64 * ih_pc_loc = post_sigarray - 2;
+
+ (*ih_pc_loc) ++;
+}
+
+#endif
+
+/* Easier interface for LIB$GET_LOGICAL: put the equivalence of NAME into BUF,
+ always NUL terminated. In case of error or if the result is longer than
+ LEN (length of BUF) an empty string is written info BUF. */
+
+static void
+__gnat_vms_get_logical (const char *name, char *buf, int len)
+{
+ struct descriptor_s name_desc, result_desc;
+ int status;
+ unsigned short rlen;
+
+ /* Build the descriptor for NAME. */
+ name_desc.len = strlen (name);
+ name_desc.mbz = 0;
+ name_desc.adr = (char *)name;
- CHF$MECH_ARRAY * mechargs = (CHF$MECH_ARRAY *) ucontext;
- CHF$SIGNAL_ARRAY * sigargs
- = (CHF$SIGNAL_ARRAY *) mechargs->chf$q_mch_sig_addr;
+ /* Build the descriptor for the result. */
+ result_desc.len = len;
+ result_desc.mbz = 0;
+ result_desc.adr = buf;
- int vcount = sigargs->chf$is_sig_args;
- int * pc_slot = & (&sigargs->chf$l_sig_name)[vcount-2];
+ status = LIB$GET_LOGICAL (&name_desc, &result_desc, &rlen);
- (*pc_slot) ++;
+ if ((status & 1) == 1 && rlen < len)
+ buf[rlen] = 0;
+ else
+ buf[0] = 0;
}
-#endif
-
-/* __gnat_adjust_context_for_raise for ia64. */
+/* Size of a page on ia64 and alpha VMS. */
+#define VMS_PAGESIZE 8192
-#if defined (IN_RTS) && defined (__IA64)
+/* User mode. */
+#define PSL__C_USER 3
-#include <vms/chfctxdef.h>
-#include <vms/chfdef.h>
+/* No access. */
+#define PRT__C_NA 0
-#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
+/* Descending region. */
+#define VA__M_DESCEND 1
-typedef unsigned long long u64;
+/* Get by virtual address. */
+#define VA___REGSUM_BY_VA 1
-void
-__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
+/* Memory region summary. */
+struct regsum
{
- /* Add one to the address of the instruction signaling the condition,
- located in the 64bits sigargs array. */
+ unsigned long long q_region_id;
+ unsigned int l_flags;
+ unsigned int l_region_protection;
+ void *pq_start_va;
+ unsigned long long q_region_size;
+ void *pq_first_free_va;
+};
- CHF$MECH_ARRAY * mechargs = (CHF$MECH_ARRAY *) ucontext;
+extern int SYS$GET_REGION_INFO (unsigned int, unsigned long long *,
+ void *, void *, unsigned int,
+ void *, unsigned int *);
+extern int SYS$EXPREG_64 (unsigned long long *, unsigned long long,
+ unsigned int, unsigned int, void **,
+ unsigned long long *);
+extern int SYS$SETPRT_64 (void *, unsigned long long, unsigned int,
+ unsigned int, void **, unsigned long long *,
+ unsigned int *);
- CHF64$SIGNAL_ARRAY *chfsig64
- = (CHF64$SIGNAL_ARRAY *) mechargs->chf$ph_mch_sig64_addr;
+/* Add a guard page in the memory region containing ADDR at ADDR +/- SIZE.
+ (The sign depends on the kind of the memory region). */
- u64 * post_sigarray
- = (u64 *)chfsig64 + 1 + chfsig64->chf64$l_sig_args;
+static int
+__gnat_set_stack_guard_page (void *addr, unsigned long size)
+{
+ int status;
+ void *ret_va;
+ unsigned long long ret_len;
+ unsigned int ret_prot;
+ void *start_va;
+ unsigned long long length;
+ unsigned int retlen;
+ struct regsum buffer;
+
+ /* Get the region for ADDR. */
+ status = SYS$GET_REGION_INFO
+ (VA___REGSUM_BY_VA, NULL, addr, NULL, sizeof (buffer), &buffer, &retlen);
+
+ if ((status & 1) != 1)
+ return -1;
+
+ /* Extend the region. */
+ status = SYS$EXPREG_64 (&buffer.q_region_id,
+ size, 0, 0, &start_va, &length);
+
+ if ((status & 1) != 1)
+ return -1;
+
+ /* Create a guard page. */
+ if (!(buffer.l_flags & VA__M_DESCEND))
+ start_va = (void *)((unsigned long long)start_va + length - VMS_PAGESIZE);
+
+ status = SYS$SETPRT_64 (start_va, VMS_PAGESIZE, PSL__C_USER, PRT__C_NA,
+ &ret_va, &ret_len, &ret_prot);
+
+ if ((status & 1) != 1)
+ return -1;
+ return 0;
+}
- u64 * ih_pc_loc = post_sigarray - 2;
+/* Read logicals to limit the stack(s) size. */
- (*ih_pc_loc) ++;
-}
+static void
+__gnat_set_stack_limit (void)
+{
+#ifdef __ia64__
+ void *sp;
+ unsigned long size;
+ char value[16];
+ char *e;
+
+ /* The main stack. */
+ __gnat_vms_get_logical ("GNAT_STACK_SIZE", value, sizeof (value));
+ size = strtoul (value, &e, 0);
+ if (e > value && *e == 0)
+ {
+ asm ("mov %0=sp" : "=r" (sp));
+ __gnat_set_stack_guard_page (sp, size * 1024);
+ }
+ /* The register stack. */
+ __gnat_vms_get_logical ("GNAT_RBS_SIZE", value, sizeof (value));
+ size = strtoul (value, &e, 0);
+ if (e > value && *e == 0)
+ {
+ asm ("mov %0=ar.bsp" : "=r" (sp));
+ __gnat_set_stack_guard_page (sp, size * 1024);
+ }
#endif
+}
-/* Feature logical name and global variable address pair */
-struct feature {char *name; int* gl_addr;};
+#ifdef IN_RTS
+extern int SYS$IEEE_SET_FP_CONTROL (void *, void *, void *);
+#define K_TRUE 1
+#define __int64 long long
+#define __NEW_STARLET
+#include <vms/ieeedef.h>
+#endif
-/* Default values for GNAT features set by environment. */
-int __gl_no_malloc_64 = 0;
+/* Feature logical name and global variable address pair.
+ If we ever add another feature logical to this list, the
+ feature struct will need to be enhanced to take into account
+ possible values for *gl_addr. */
+struct feature {
+ const char *name;
+ int *gl_addr;
+};
-/* Array feature logical names and global variable addresses */
-static struct feature features[] = {
- {"GNAT$NO_MALLOC_64", &__gl_no_malloc_64},
+/* Default values for GNAT features set by environment or binder. */
+int __gl_heap_size = 64;
+
+/* Default float format is 'I' meaning IEEE. If gnatbind detetcts that a
+ VAX Float format is specified, it will set this global variable to 'V'.
+ Subsequently __gnat_set_features will test the variable and if set for
+ VAX Float will call a Starlet function to enable trapping for invalid
+ operation, drivide by zero, and overflow. This will prevent the VMS runtime
+ (specifically OTS$CHECK_FP_MODE) from complaining about inconsistent
+ floating point settings in a mixed language program. Ideally the setting
+ would be determined at link time based on setttings in the object files,
+ however the VMS linker seems to take the setting from the first object
+ in the link, e.g. pcrt0.o which is float representation neutral. */
+char __gl_float_format = 'I';
+
+/* Array feature logical names and global variable addresses. */
+static const struct feature features[] =
+{
+ {"GNAT$NO_MALLOC_64", &__gl_heap_size},
{0, 0}
};
-void __gnat_set_features ()
+void
+__gnat_set_features (void)
{
- struct descriptor_s name_desc, result_desc;
- int i, status;
- unsigned short rlen;
+ int i;
+ char buff[16];
+#ifdef IN_RTS
+ IEEE clrmsk, setmsk, prvmsk;
+
+ clrmsk.ieee$q_flags = 0LL;
+ setmsk.ieee$q_flags = 0LL;
+#endif
-#define MAXEQUIV 10
- char buff [MAXEQUIV];
+ /* Loop through features array and test name for enable/disable. */
+ for (i = 0; features[i].name; i++)
+ {
+ __gnat_vms_get_logical (features[i].name, buff, sizeof (buff));
+
+ if (strcmp (buff, "ENABLE") == 0
+ || strcmp (buff, "TRUE") == 0
+ || strcmp (buff, "1") == 0)
+ *features[i].gl_addr = 32;
+ else if (strcmp (buff, "DISABLE") == 0
+ || strcmp (buff, "FALSE") == 0
+ || strcmp (buff, "0") == 0)
+ *features[i].gl_addr = 64;
+ }
- /* Loop through features array and test name for enable/disable */
- for (i=0; features [i].name; i++)
+ /* Features to artificially limit the stack size. */
+ __gnat_set_stack_limit ();
+
+#ifdef IN_RTS
+ if (__gl_float_format == 'V')
{
- name_desc.len = strlen (features [i].name);
- name_desc.mbz = 0;
- name_desc.adr = features [i].name;
+ setmsk.ieee$v_trap_enable_inv = K_TRUE;
+ setmsk.ieee$v_trap_enable_dze = K_TRUE;
+ setmsk.ieee$v_trap_enable_ovf = K_TRUE;
+ SYS$IEEE_SET_FP_CONTROL (&clrmsk, &setmsk, &prvmsk);
+ }
+#endif
- result_desc.len = MAXEQUIV - 1;
- result_desc.mbz = 0;
- result_desc.adr = buff;
+ __gnat_features_set = 1;
+}
- status = LIB$GET_LOGICAL (&name_desc, &result_desc, &rlen);
+/* Return true if the VMS version is 7.x. */
- if (((status & 1) == 1) && (rlen < MAXEQUIV))
- buff [rlen] = 0;
- else
- strcpy (buff, "");
+extern unsigned int LIB$GETSYI (int *, ...);
- if (strcmp (buff, "ENABLE") == 0)
- *features [i].gl_addr = 1;
- else if (strcmp (buff, "DISABLE") == 0)
- *features [i].gl_addr = 0;
- }
+#define SYI$_VERSION 0x1000
+
+int
+__gnat_is_vms_v7 (void)
+{
+ struct descriptor_s desc;
+ char version[8];
+ int status;
+ int code = SYI$_VERSION;
+
+ desc.len = sizeof (version);
+ desc.mbz = 0;
+ desc.adr = version;
- __gnat_features_set = 1;
+ status = LIB$GETSYI (&code, 0, &desc);
+ if ((status & 1) == 1 && version[1] == '7' && version[2] == '.')
+ return 1;
+ else
+ return 0;
}
/*******************/
/* FreeBSD Section */
/*******************/
-#elif defined (__FreeBSD__)
+#elif defined (__FreeBSD__) || defined (__DragonFly__)
#include <signal.h>
#include <sys/ucontext.h>
#include <unistd.h>
-static void __gnat_error_handler (int, siginfo_t *, ucontext_t *);
-
static void
-__gnat_error_handler (int sig, siginfo_t *info __attribute__ ((unused)),
- ucontext_t *ucontext)
+__gnat_error_handler (int sig,
+ siginfo_t *si ATTRIBUTE_UNUSED,
+ void *ucontext ATTRIBUTE_UNUSED)
{
struct Exception_Data *exception;
const char *msg;
break;
case SIGBUS:
- exception = &constraint_error;
- msg = "SIGBUS";
+ exception = &storage_error;
+ msg = "SIGBUS: possible stack overflow";
break;
default:
}
void
-__gnat_install_handler ()
+__gnat_install_handler (void)
{
struct sigaction act;
__gnat_handler_installed = 1;
}
-/*******************/
-/* VxWorks Section */
-/*******************/
+/*************************************/
+/* VxWorks Section (including Vx653) */
+/*************************************/
#elif defined(__vxworks)
#include <signal.h>
#include <taskLib.h>
+#if defined (__i386__) && !defined (VTHREADS)
+#include <sysLib.h>
+#endif
#ifndef __RTP__
#include <intLib.h>
#include <iv.h>
#endif
+#if defined (ARMEL) && (_WRS_VXWORKS_MAJOR == 6)
+#include <vmLib.h>
+#endif
+
#ifdef VTHREADS
#include "private/vThreadsP.h"
#endif
-void __gnat_error_handler (int, void *, struct sigcontext *);
-
#ifndef __RTP__
/* Directly vectored Interrupt routines are not supported when using RTPs. */
int
__gnat_inum_to_ivec (int num)
{
- return INUM_TO_IVEC (num);
+ return (int) INUM_TO_IVEC (num);
}
#endif
-#if !defined(__alpha_vxworks) && (_WRS_VXWORKS_MAJOR != 6) && !defined(__RTP__)
+#if !defined(__alpha_vxworks) && ((_WRS_VXWORKS_MAJOR != 6) && (_WRS_VXWORKS_MAJOR != 7)) && !defined(__RTP__)
/* getpid is used by s-parint.adb, but is not defined by VxWorks, except
on Alpha VxWorks and VxWorks 6.x (including RTPs). */
}
/* Handle different SIGnal to exception mappings in different VxWorks
- versions. */
-static void
-__gnat_map_signal (int sig)
+ versions. */
+void
+__gnat_map_signal (int sig, siginfo_t *si ATTRIBUTE_UNUSED,
+ void *sc ATTRIBUTE_UNUSED)
{
struct Exception_Data *exception;
const char *msg;
msg = "SIGFPE";
break;
#ifdef VTHREADS
+#ifdef __VXWORKSMILS__
+ case SIGILL:
+ exception = &storage_error;
+ msg = "SIGILL: possible stack overflow";
+ break;
+ case SIGSEGV:
+ exception = &storage_error;
+ msg = "SIGSEGV";
+ break;
+ case SIGBUS:
+ exception = &program_error;
+ msg = "SIGBUS";
+ break;
+#else
case SIGILL:
exception = &constraint_error;
msg = "Floating point exception or SIGILL";
exception = &storage_error;
msg = "SIGBUS: possible stack overflow";
break;
-#elif (_WRS_VXWORKS_MAJOR == 6)
+#endif
+#elif (_WRS_VXWORKS_MAJOR >= 6)
case SIGILL:
exception = &constraint_error;
msg = "SIGILL";
msg = "unhandled signal";
}
+ /* On ARM VxWorks 6.x, the guard page is left un-armed by the kernel
+ after being violated, so subsequent violations aren't detected.
+ so we retrieve the address of the guard page from the TCB and compare it
+ with the page that is violated (pREG 12 in the context) and re-arm that
+ page if there's a match. Additionally we're are assured this is a
+ genuine stack overflow condition and and set the message and exception
+ to that effect. */
+#if defined (ARMEL) && (_WRS_VXWORKS_MAJOR == 6)
+
+ /* We re-arm the guard page by marking it invalid */
+
+#define PAGE_SIZE 4096
+#define REG_IP 12
+
+ if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL)
+ {
+ TASK_ID tid = taskIdSelf ();
+ WIND_TCB *pTcb = taskTcb (tid);
+ unsigned long violated_page
+ = ((struct sigcontext *) sc)->sc_pregs->r[REG_IP] & ~(PAGE_SIZE - 1);
+
+ if ((unsigned long) (pTcb->pStackEnd - PAGE_SIZE) == violated_page)
+ {
+ vmStateSet (NULL, violated_page,
+ PAGE_SIZE, VM_STATE_MASK_VALID, VM_STATE_VALID_NOT);
+ exception = &storage_error;
+
+ switch (sig)
+ {
+ case SIGSEGV:
+ msg = "SIGSEGV: stack overflow";
+ break;
+ case SIGBUS:
+ msg = "SIGBUS: stack overflow";
+ break;
+ case SIGILL:
+ msg = "SIGILL: stack overflow";
+ break;
+ }
+ }
+ }
+#endif /* defined (ARMEL) && (_WRS_VXWORKS_MAJOR == 6) */
+
__gnat_clear_exception_count ();
Raise_From_Signal_Handler (exception, msg);
}
+#if defined (__i386__) && !defined (VTHREADS)
+extern void
+__gnat_vxsim_error_handler (int sig, siginfo_t *si, void *sc);
+
+static int is_vxsim = 0;
+#endif
+
/* Tasking and Non-tasking signal handler. Map SIGnal to Ada exception
propagation after the required low level adjustments. */
-void
-__gnat_error_handler (int sig, void * si ATTRIBUTE_UNUSED,
- struct sigcontext * sc)
+static void
+__gnat_error_handler (int sig, siginfo_t *si, void *sc)
{
sigset_t mask;
sigdelset (&mask, sig);
sigprocmask (SIG_SETMASK, &mask, NULL);
- __gnat_map_signal (sig);
+#if defined (__ARMEL__) || defined (__PPC__) || defined (__i386__)
+ /* On certain targets, kernel mode, we process signals through a Call Frame
+ Info trampoline, voiding the need for myriads of fallback_frame_state
+ variants in the ZCX runtime. We have no simple way to distinguish ZCX
+ from SJLJ here, so we do this for SJLJ as well even though this is not
+ necessary. This only incurs a few extra instructions and a tiny
+ amount of extra stack usage. */
+
+#if defined (__i386__) && !defined (VTHREADS)
+ /* On x86, the vxsim signal context is subtly different and is processeed
+ by a handler compiled especially for vxsim. */
+
+ if (is_vxsim)
+ __gnat_vxsim_error_handler (sig, si, sc);
+#endif
+
+ #include "sigtramp.h"
+
+ __gnat_sigtramp (sig, (void *)si, (void *)sc,
+ (__sigtramphandler_t *)&__gnat_map_signal);
+
+#else
+ __gnat_map_signal (sig, si, sc);
+#endif
}
+#if defined(__leon__) && defined(_WRS_KERNEL)
+/* For LEON VxWorks we need to install a trap handler for stack overflow */
+
+extern void excEnt (void);
+/* VxWorks exception handler entry */
+
+struct trap_entry {
+ unsigned long inst_first;
+ unsigned long inst_second;
+ unsigned long inst_third;
+ unsigned long inst_fourth;
+};
+/* Four instructions representing entries in the trap table */
+
+struct trap_entry *trap_0_entry;
+/* We will set the location of the entry for software trap 0 in the trap
+ table. */
+#endif
+
void
__gnat_install_handler (void)
{
struct sigaction act;
+ char *model ATTRIBUTE_UNUSED;
/* Setup signal handler to map synchronous signals to appropriate
exceptions. Make sure that the handler isn't interrupted by another
signal that might cause a scheduling event! */
- act.sa_handler = __gnat_error_handler;
+ act.sa_sigaction = __gnat_error_handler;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigemptyset (&act.sa_mask);
sigaction (SIGSEGV, &act, NULL);
sigaction (SIGBUS, &act, NULL);
+#if defined(__leon__) && defined(_WRS_KERNEL)
+ /* Specific to the LEON VxWorks kernel run-time library */
+
+ /* For stack checking the compiler triggers a software trap 0 (ta 0) in
+ case of overflow (we use the stack limit mechanism). We need to install
+ the trap handler here for this software trap (the OS does not handle
+ it) as if it were a data_access_exception (trap 9). We do the same as
+ if we put in the trap table a VXSPARC_BAD_TRAP(9). Software trap 0 is
+ located at vector 0x80, and each entry takes 4 words. */
+
+ trap_0_entry = (struct trap_entry *)(intVecBaseGet () + 0x80 * 4);
+
+ /* mov 0x9, %l7 */
+
+ trap_0_entry->inst_first = 0xae102000 + 9;
+
+ /* sethi %hi(excEnt), %l6 */
+
+ /* The 22 most significant bits of excEnt are obtained shifting 10 times
+ to the right. */
+
+ trap_0_entry->inst_second = 0x2d000000 + ((unsigned long)excEnt >> 10);
+
+ /* jmp %l6+%lo(excEnt) */
+
+ /* The 10 least significant bits of excEnt are obtained by masking */
+
+ trap_0_entry->inst_third = 0x81c5a000 + ((unsigned long)excEnt & 0x3ff);
+
+ /* rd %psr, %l0 */
+
+ trap_0_entry->inst_fourth = 0xa1480000;
+#endif
+
+#if defined (__i386__) && !defined (VTHREADS)
+ /* By experiment, found that sysModel () returns the following string
+ prefix for vxsim when running on Linux and Windows. */
+ model = sysModel ();
+ if ((strncmp (model, "Linux", 5) == 0)
+ || (strncmp (model, "Windows", 7) == 0))
+ is_vxsim = 1;
+#endif
+
__gnat_handler_installed = 1;
}
to get correct Ada semantics. Note that for AE653 vThreads, the HW
overflow settings are an OS configuration issue. The instructions
below have no effect. */
-#if defined (_ARCH_PPC) && !defined (_SOFT_FLOAT) && !defined (VTHREADS)
+#if defined (_ARCH_PPC) && !defined (_SOFT_FLOAT) && (!defined (VTHREADS) || defined (__VXWORKSMILS__))
+#if defined (__SPE__)
+ {
+ /* For e500v2, do nothing and leave the responsibility to install the
+ handler and enable the exceptions to the BSP. */
+ }
+#else
asm ("mtfsb0 25");
asm ("mtfsb0 26");
#endif
+#endif
-#if (defined (__i386__) || defined (i386)) && !defined (VTHREADS)
+#if defined (__i386__) && !defined (VTHREADS)
/* This is used to properly initialize the FPU on an x86 for each
process thread. */
asm ("finit");
msg = "unhandled signal";
}
- Raise_From_Signal_Handler(exception, msg);
+ Raise_From_Signal_Handler (exception, msg);
}
void
msg = "unhandled signal";
}
- Raise_From_Signal_Handler(exception, msg);
+ Raise_From_Signal_Handler (exception, msg);
}
void
#elif defined(__APPLE__)
#include <signal.h>
-#include <mach/mach_vm.h>
-#include <mach/vm_statistics.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
/* This must be in keeping with System.OS_Interface.Alternate_Stack_Size. */
-char __gnat_alternate_stack[64 * 1024]; /* 2 * MINSIGSTKSZ */
+char __gnat_alternate_stack[32 * 1024]; /* 1 * MINSIGSTKSZ */
-static void __gnat_error_handler (int sig, siginfo_t * si, void * uc);
-
-/* Defined in xnu unix_signal.c */
+/* Defined in xnu unix_signal.c.
+ Tell the kernel to re-use alt stack when delivering a signal. */
#define UC_RESET_ALT_STACK 0x80000000
-extern int sigreturn (void *uc, int flavour);
+
+#ifndef __arm__
+#include <mach/mach_vm.h>
+#include <mach/mach_init.h>
+#include <mach/vm_statistics.h>
+#endif
/* Return true if ADDR is within a stack guard area. */
static int
__gnat_is_stack_guard (mach_vm_address_t addr)
{
+#ifndef __arm__
kern_return_t kret;
vm_region_submap_info_data_64_t info;
mach_vm_address_t start;
&& info.user_tag == VM_MEMORY_STACK)
return 1;
return 0;
+#else
+ /* Pagezero for arm. */
+ return addr >= 4096;
+#endif
+}
+
+#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
+
+#if defined (__x86_64__)
+static int
+__darwin_major_version (void)
+{
+ static int cache = -1;
+ if (cache < 0)
+ {
+ int mib[2] = {CTL_KERN, KERN_OSRELEASE};
+ size_t len;
+
+ /* Find out how big the buffer needs to be (and set cache to 0
+ on failure). */
+ if (sysctl (mib, 2, NULL, &len, NULL, 0) == 0)
+ {
+ char release[len];
+ sysctl (mib, 2, release, &len, NULL, 0);
+ /* Darwin releases are of the form L.M.N where L is the major
+ version, so strtol will return L. */
+ cache = (int) strtol (release, NULL, 10);
+ }
+ else
+ {
+ cache = 0;
+ }
+ }
+ return cache;
+}
+#endif
+
+void
+__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED,
+ void *ucontext ATTRIBUTE_UNUSED)
+{
+#if defined (__x86_64__)
+ if (__darwin_major_version () < 12)
+ {
+ /* Work around radar #10302855, where the unwinders (libunwind or
+ libgcc_s depending on the system revision) and the DWARF unwind
+ data for sigtramp have different ideas about register numbering,
+ causing rbx and rdx to be transposed. */
+ ucontext_t *uc = (ucontext_t *)ucontext;
+ unsigned long t = uc->uc_mcontext->__ss.__rbx;
+
+ uc->uc_mcontext->__ss.__rbx = uc->uc_mcontext->__ss.__rdx;
+ uc->uc_mcontext->__ss.__rdx = t;
+ }
+#endif
}
static void
-__gnat_error_handler (int sig, siginfo_t * si, void * uc)
+__gnat_error_handler (int sig, siginfo_t *si, void *ucontext)
{
struct Exception_Data *exception;
const char *msg;
+ __gnat_adjust_context_for_raise (sig, ucontext);
+
switch (sig)
{
case SIGSEGV:
msg = "erroneous memory access";
}
/* Reset the use of alt stack, so that the alt stack will be used
- for the next signal delivery. */
- sigreturn (NULL, UC_RESET_ALT_STACK);
+ for the next signal delivery.
+ The stack can't be used in case of stack checking. */
+ syscall (SYS_sigreturn, NULL, UC_RESET_ALT_STACK);
break;
case SIGFPE:
__gnat_handler_installed = 1;
}
+#elif defined(__ANDROID__)
+
+/*******************/
+/* Android Section */
+/*******************/
+
+#include <signal.h>
+#include "sigtramp.h"
+
+#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
+
+void
+__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
+{
+ mcontext_t *mcontext = &((ucontext_t *) ucontext)->uc_mcontext;
+
+ /* ARM Bump has to be an even number because of odd/even architecture. */
+ ((mcontext_t *) mcontext)->arm_pc += 2;
+}
+
+static void
+__gnat_map_signal (int sig,
+ siginfo_t *si ATTRIBUTE_UNUSED,
+ void *ucontext ATTRIBUTE_UNUSED)
+{
+ struct Exception_Data *exception;
+ const char *msg;
+
+ switch (sig)
+ {
+ case SIGSEGV:
+ exception = &storage_error;
+ msg = "stack overflow or erroneous memory access";
+ break;
+
+ case SIGBUS:
+ exception = &constraint_error;
+ msg = "SIGBUS";
+ break;
+
+ case SIGFPE:
+ exception = &constraint_error;
+ msg = "SIGFPE";
+ break;
+
+ default:
+ exception = &program_error;
+ msg = "unhandled signal";
+ }
+
+ Raise_From_Signal_Handler (exception, msg);
+}
+
+static void
+__gnat_error_handler (int sig,
+ siginfo_t *si ATTRIBUTE_UNUSED,
+ void *ucontext ATTRIBUTE_UNUSED)
+{
+ __gnat_adjust_context_for_raise (sig, ucontext);
+
+ __gnat_sigtramp (sig, (void *) si, (void *) ucontext,
+ (__sigtramphandler_t *)&__gnat_map_signal);
+}
+
+/* This must be in keeping with System.OS_Interface.Alternate_Stack_Size. */
+char __gnat_alternate_stack[16 * 1024];
+
+void
+__gnat_install_handler (void)
+{
+ struct sigaction act;
+
+ /* Set up signal handler to map synchronous signals to appropriate
+ exceptions. Make sure that the handler isn't interrupted by another
+ signal that might cause a scheduling event! Also setup an alternate
+ stack region for the handler execution so that stack overflows can be
+ handled properly, avoiding a SEGV generation from stack usage by the
+ handler itself. */
+
+ stack_t stack;
+ stack.ss_sp = __gnat_alternate_stack;
+ stack.ss_size = sizeof (__gnat_alternate_stack);
+ stack.ss_flags = 0;
+ sigaltstack (&stack, NULL);
+
+ act.sa_sigaction = __gnat_error_handler;
+ act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
+ sigemptyset (&act.sa_mask);
+
+ sigaction (SIGABRT, &act, NULL);
+ sigaction (SIGFPE, &act, NULL);
+ sigaction (SIGILL, &act, NULL);
+ sigaction (SIGBUS, &act, NULL);
+ act.sa_flags |= SA_ONSTACK;
+ sigaction (SIGSEGV, &act, NULL);
+
+ __gnat_handler_installed = 1;
+}
+
#else
/* For all other versions of GNAT, the handler does nothing. */
/*********************/
/* This routine is called as each process thread is created, for possible
- initialization of the FP processor. This version is used under INTERIX,
- WIN32 and could be used under OS/2. */
+ initialization of the FP processor. This version is used under INTERIX
+ and WIN32. */
-#if defined (_WIN32) || defined (__INTERIX) || defined (__EMX__) \
+#if defined (_WIN32) || defined (__INTERIX) \
|| defined (__Lynx__) || defined(__NetBSD__) || defined(__FreeBSD__) \
- || defined (__OpenBSD__)
+ || defined (__OpenBSD__) || defined (__DragonFly__)
#define HAVE_GNAT_INIT_FLOAT
void
__gnat_init_float (void)
{
-#if defined (__i386__) || defined (i386) || defined (__x86_64)
+#if defined (__i386__) || defined (__x86_64__)
/* This is used to properly initialize the FPU on an x86 for each
process thread. */
{
/* We used to compensate here for the raised from call vs raised from signal
exception discrepancy with the GCC ZCX scheme, but this now can be dealt
- with generically in the unwinder (see GCC PR other/26208). Only the VMS
- ports still do the compensation described in the few lines below.
+ with generically in the unwinder (see GCC PR other/26208). This however
+ requires the use of the _Unwind_GetIPInfo routine in raise-gcc.c, which
+ is predicated on the definition of HAVE_GETIPINFO at compile time. Only
+ the VMS ports still do the compensation described in the few lines below.
*** Call vs signal exception discrepancy with GCC ZCX scheme ***
}
#endif
+
+#ifdef __cplusplus
+}
+#endif