#include "tsystem.h"
#include <sys/stat.h>
-/* We don't have libiberty, so us malloc. */
+/* We don't have libiberty, so use malloc. */
#define xmalloc(S) malloc (S)
#else
#include "config.h"
file now sets the __gl_* variables directly. */
void
-__gnat_set_globals ()
+__gnat_set_globals (void)
{
}
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 * uc ATTRIBUTE_UNUSED)
{
struct Exception_Data *exception;
const char *msg;
}
recurse = 0;
- Raise_From_Signal_Handler (exception, (char *) msg);
+ Raise_From_Signal_Handler (exception, (const char *) msg);
}
void
static void
__gnat_error_handler
- (int sig, siginfo_t *siginfo ATTRIBUTE_UNUSED, void *ucontext)
+ (int sig,
+ siginfo_t *siginfo ATTRIBUTE_UNUSED,
+ void *ucontext ATTRIBUTE_UNUSED)
{
struct Exception_Data *exception;
const char *msg;
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];
/* The pattern is "orl $0x0,(%esp)" for a probe in 32-bit mode. */
if (signo == SIGSEGV && pattern == 0x00240c83)
- mcontext->gregs[REG_ESP] += 4096;
+ 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;
+ mcontext->gregs[REG_RSP] += 4096 + 4 * sizeof (unsigned long);
#elif defined (__ia64__)
/* ??? The IA-64 unwinder doesn't compensate for signals. */
mcontext->sc_ip++;
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 *sip, ucontext_t *cx ATTRIBUTE_UNUSED)
{
struct Exception_Data *exception;
static int recurse = 0;
#define SS$_RESIGNAL 2328
/* These codes are in standard message libraries. */
+extern int C$_SIGKILL;
extern int CMA$_EXIT_THREAD;
extern int SS$_DEBUG;
extern int SS$_INTDIV;
resignal_predicate (int code);
const int *cond_resignal_table [] = {
+ &C$_SIGKILL,
&CMA$_EXIT_THREAD,
&SS$_DEBUG,
&LIB$_KEYNOTFOU,
}
#endif
-/* VxWorks expects the field excCnt to be zeroed when a signal is handled.
- The VxWorks version of longjmp does this; GCC's builtin_longjmp doesn't. */
+/* VxWorks 653 vThreads expects the field excCnt to be zeroed when a signal is.
+ handled. The VxWorks version of longjmp does this; GCC's builtin_longjmp
+ doesn't. */
void
__gnat_clear_exception_count (void)
{
break;
case SIGSEGV:
exception = &storage_error;
- msg = "SIGSEGV: possible stack overflow";
+ msg = "SIGSEGV";
break;
case SIGBUS:
exception = &storage_error;
msg = "SIGBUS: possible stack overflow";
break;
-#else
-#ifdef __RTP__
- /* In RTP mode a SIGSEGV is most likely due to a stack overflow,
- since stack checking uses the probing mechanism. */
+#elif (_WRS_VXWORKS_MAJOR == 6)
case SIGILL:
exception = &constraint_error;
msg = "SIGILL";
break;
+#ifdef __RTP__
+ /* In RTP mode a SIGSEGV is most likely due to a stack overflow,
+ since stack checking uses the probing mechanism. */
case SIGSEGV:
exception = &storage_error;
msg = "SIGSEGV: possible stack overflow";
break;
+ case SIGBUS:
+ exception = &program_error;
+ msg = "SIGBUS";
+ break;
#else
- /* In kernel mode a SIGILL is most likely due to a stack overflow,
+ /* VxWorks 6 kernel mode with probing. SIGBUS for guard page hit */
+ case SIGSEGV:
+ exception = &storage_error;
+ msg = "SIGSEGV";
+ break;
+ case SIGBUS:
+ exception = &storage_error;
+ msg = "SIGBUS: possible stack overflow";
+ break;
+#endif
+#else
+ /* VxWorks 5: a SIGILL is most likely due to a stack overflow,
since stack checking uses the stack limit mechanism. */
case SIGILL:
exception = &storage_error;
msg = "SIGILL: possible stack overflow";
break;
case SIGSEGV:
- exception = &program_error;
+ exception = &storage_error;
msg = "SIGSEGV";
break;
-#endif
case SIGBUS:
exception = &program_error;
msg = "SIGBUS";
overflow settings are an OS configuration issue. The instructions
below have no effect. */
#if defined (_ARCH_PPC) && !defined (_SOFT_FLOAT) && !defined (VTHREADS)
+#if defined (__SPE__)
+ {
+ const unsigned long spefscr_mask = 0xfffffff3;
+ unsigned long spefscr;
+ asm ("mfspr %0, 512" : "=r" (spefscr));
+ spefscr = spefscr & spefscr_mask;
+ asm ("mtspr 512, %0\n\tisync" : : "r" (spefscr));
+ }
+#else
asm ("mtfsb0 25");
asm ("mtfsb0 26");
#endif
+#endif
#if (defined (__i386__) || defined (i386)) && !defined (VTHREADS)
/* This is used to properly initialize the FPU on an x86 for each
checking is not used. */
void (*__gnat_set_stack_limit_hook)(void) = (void (*)(void))0;
-
/******************/
/* NetBSD Section */
/******************/
#elif defined(__APPLE__)
#include <signal.h>
+#include <mach/mach_vm.h>
+#include <mach/mach_init.h>
+#include <mach/vm_statistics.h>
+
+/* This must be in keeping with System.OS_Interface.Alternate_Stack_Size. */
+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 */
+#define UC_RESET_ALT_STACK 0x80000000
+extern int sigreturn (void *uc, int flavour);
+
+/* Return true if ADDR is within a stack guard area. */
+static int
+__gnat_is_stack_guard (mach_vm_address_t addr)
+{
+ kern_return_t kret;
+ vm_region_submap_info_data_64_t info;
+ mach_vm_address_t start;
+ mach_vm_size_t size;
+ natural_t depth;
+ mach_msg_type_number_t count;
+
+ count = VM_REGION_SUBMAP_INFO_COUNT_64;
+ start = addr;
+ size = -1;
+ depth = 9999;
+ kret = mach_vm_region_recurse (mach_task_self (), &start, &size, &depth,
+ (vm_region_recurse_info_t) &info, &count);
+ if (kret == KERN_SUCCESS
+ && addr >= start && addr < (start + size)
+ && info.protection == VM_PROT_NONE
+ && info.user_tag == VM_MEMORY_STACK)
+ return 1;
+ return 0;
+}
+
static void
-__gnat_error_handler (int sig, siginfo_t * si, void * uc)
+__gnat_error_handler (int sig, siginfo_t * si, void * uc ATTRIBUTE_UNUSED)
{
struct Exception_Data *exception;
const char *msg;
switch (sig)
{
case SIGSEGV:
- /* FIXME: we need to detect the case of a *real* SIGSEGV. */
- exception = &storage_error;
- msg = "stack overflow or erroneous memory access";
- break;
-
case SIGBUS:
- exception = &constraint_error;
- msg = "SIGBUS";
+ if (__gnat_is_stack_guard ((unsigned long)si->si_addr))
+ {
+ exception = &storage_error;
+ msg = "stack overflow";
+ }
+ else
+ {
+ exception = &constraint_error;
+ 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);
break;
case SIGFPE:
/* 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! */
+ 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 (and it is required by Darwin). */
+
+ 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_NODEFER | SA_RESTART | SA_SIGINFO;
act.sa_sigaction = __gnat_error_handler;
sigaction (SIGFPE, &act, NULL);
if (__gnat_get_interrupt_state (SIGILL) != 's')
sigaction (SIGILL, &act, NULL);
+
+ act.sa_flags |= SA_ONSTACK;
if (__gnat_get_interrupt_state (SIGSEGV) != 's')
sigaction (SIGSEGV, &act, NULL);
if (__gnat_get_interrupt_state (SIGBUS) != 's')
void
__gnat_init_float (void)
{
-#if defined (__i386__) || defined (i386)
+#if defined (__i386__) || defined (i386) || defined (__x86_64)
/* This is used to properly initialize the FPU on an x86 for each
process thread. */