diff options
-rw-r--r-- | gcc/ada/init.c | 197 | ||||
-rw-r--r-- | gcc/ada/s-intman-posix.adb | 17 | ||||
-rw-r--r-- | gcc/ada/s-intman-solaris.adb | 40 | ||||
-rw-r--r-- | gcc/ada/s-intman.ads | 25 | ||||
-rw-r--r-- | gcc/ada/system-solaris-x86.ads | 4 |
5 files changed, 169 insertions, 114 deletions
diff --git a/gcc/ada/init.c b/gcc/ada/init.c index 06a1c804e68..068fca547cf 100644 --- a/gcc/ada/init.c +++ b/gcc/ada/init.c @@ -183,47 +183,6 @@ __gnat_set_globals () #endif -/* Notes on the Zero Cost Exceptions scheme and its impact on the signal - handlers implemented below : - - What we call Zero Cost Exceptions is implemented using the GCC eh - circuitry, even if the underlying implementation is setjmp/longjmp - based. In any case ... - - The GCC unwinder expects to be dealing with call return addresses, since - this is the "nominal" case of what we retrieve while unwinding a regular - call chain. To evaluate if a handler applies at some point in this chain, - the propagation engine needs to determine what region the corresponding - call instruction pertains to. The return address may not be attached to the - same region as the call, so the unwinder unconditionally subtracts "some" - amount to the return addresses it gets to search the region tables. The - exact amount is computed to ensure that the resulting address is inside the - call instruction, and is thus target dependent (think about delay slots for - instance). - - When we raise an exception from a signal handler, e.g. to transform a - SIGSEGV into Storage_Error, things need to appear as if the signal handler - had been "called" by the instruction which triggered the signal, so that - exception handlers that apply there are considered. What the unwinder will - retrieve as the return address from the signal handler is what it will find - as the faulting instruction address in the corresponding signal context - pushed by the kernel. Leaving this address untouched may loose, because if - the triggering instruction happens to be the very first of a region, the - later adjustments performed by the unwinder would yield an address outside - that region. We need to compensate for those adjustments at some point, - which we used to do in the GCC unwinding fallback macro. - - The thread at http://gcc.gnu.org/ml/gcc-patches/2004-05/msg00343.html - describes a couple of issues with the fallback based compensation approach. - First, on some targets the adjustment to apply depends on the triggering - signal, which is not easily accessible from the macro. Besides, other - languages, e.g. Java, deal with this by performing the adjustment in the - signal handler before the raise, so fallback adjustments just break those - front-ends. - - We now follow the Java way for most targets, via adjust_context_for_raise - below. */ - /***************/ /* AIX Section */ /***************/ @@ -347,14 +306,42 @@ 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); +/* __gnat_adjust_context_for_raise - see comments along with the default + version later in this file. */ + +#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE + +void +__gnat_adjust_context_for_raise (int signo, void *context) +{ + struct sigcontext * sigcontext = (struct sigcontext *) context; + + /* The fallback code fetches the faulting insn address from sc_pc, so + adjust that when need be. For SIGFPE, the required adjustment depends + on the trap shadow situation (see man ieee). */ + if (signo == SIGFPE) + { + /* ??? We never adjust here, considering that sc_pc always + designates the instruction following the one which trapped. + This is not necessarily true but corresponds to what we have + always observed. */ + } + else + sigcontext->sc_pc ++; +} + static void __gnat_error_handler - (int sig, siginfo_t *sip, struct sigcontext *context ATTRIBUTE_UNUSED) + (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)) { @@ -973,16 +960,52 @@ __gnat_install_handler (void) #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 *); + +/* __gnat_adjust_context_for_raise - see comments along with the default + version later in this file. */ -static void __gnat_error_handler (int, siginfo_t *); +#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; + mcontext->gregs[REG_PC] += (1 - RETURN_ADDR_OFFSET); +} static void -__gnat_error_handler (int sig, siginfo_t *sip) +__gnat_error_handler (int sig, siginfo_t *sip, ucontext_t *uctx) { 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, (void *)uctx); + /* If this was an explicit signal from a "kill", just resignal it. */ if (SI_FROMUSER (sip)) { @@ -1424,21 +1447,22 @@ __gnat_handle_vms_condition (int *sigargs, void *mechargs) exception = &storage_error; msg = "stack overflow (or erroneous memory access)"; } + __gnat_adjust_context_for_raise (0, (void *)mechargs); break; case SS$_STKOVF: exception = &storage_error; msg = "stack overflow"; + __gnat_adjust_context_for_raise (0, (void *)mechargs); break; case SS$_HPARITH: #ifndef IN_RTS return SS$_RESIGNAL; /* toplev.c handles for compiler */ #else - { - exception = &constraint_error; - msg = "arithmetic error"; - } + exception = &constraint_error; + msg = "arithmetic error"; + __gnat_adjust_context_for_raise (0, (void *)mechargs); #endif break; @@ -1465,7 +1489,8 @@ __gnat_handle_vms_condition (int *sigargs, void *mechargs) 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; + exception = (struct Exception_Data *) + cond_except_table [i].except; if (!exception) /* User programs expect Non_Ada_Error to be raised, reference @@ -1485,7 +1510,6 @@ __gnat_handle_vms_condition (int *sigargs, void *mechargs) break; } - __gnat_adjust_context_for_raise (0, (void *)mechargs); Raise_From_Signal_Handler (exception, msg); } @@ -1760,10 +1784,20 @@ __gnat_map_signal (int sig) exception = &constraint_error; msg = "SIGILL"; break; +/* In RTP mode a SIGSEGV is most likely due to a stack overflow. This is not + the case in kernel mode where stack overflow detection uses a comparison + method instead of memory probes. */ +#ifdef __RTP__ + case SIGSEGV: + exception = &storage_error; + msg = "SIGSEGV: possible stack overflow"; + break; +#else case SIGSEGV: exception = &program_error; msg = "SIGSEGV"; break; +#endif case SIGBUS: exception = &program_error; msg = "SIGBUS"; @@ -1982,34 +2016,57 @@ __gnat_init_float (void) /* All targets without a specific version will use an empty one */ -/* UCONTEXT is a pointer to a context structure received by a signal handler - about to propagate an exception. Adjust it to compensate the fact that the - generic unwinder thinks the corresponding PC is a call return address. */ +/* Given UCONTEXT a pointer to a context structure received by a signal + handler for SIGNO, perform the necessary adjustments to let the handler + raise an exception. Calls to this routine are not conditioned by the + propagation scheme in use. */ void __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext ATTRIBUTE_UNUSED) { - /* The point is that the interrupted context PC typically is the address - that we should search an EH region for, which is different from the call - return address case. The target independent part of the GCC unwinder - don't differentiate the two situations, so we compensate here for the - adjustments it will blindly make. + /* Adjustments are currently required for the GCC ZCX propagation scheme + only. These adjustments (described below) are harmless for the other + schemes, so may be applied unconditionally. */ + + /* Adjustments required for a GCC ZCX propagation scheme: + ------------------------------------------------------ + + The GCC unwinder expects to be dealing with call return addresses, since + this is the "nominal" case of what we retrieve while unwinding a regular + call chain. + + To evaluate if a handler applies at some point identified by a return + address, the propagation engine needs to determine what region the + corresponding call instruction pertains to. Because the return address + may not be attached to the same region as the call, the unwinder always + subtracts "some" amount from a return address to search the region + tables, amount chosen to ensure that the resulting address is inside the + call instruction. + + When we raise an exception from a signal handler, e.g. to transform a + SIGSEGV into Storage_Error, things need to appear as if the signal + handler had been "called" by the instruction which triggered the signal, + so that exception handlers that apply there are considered. What the + unwinder will retrieve as the return address from the signal handler is + what it will find as the faulting instruction address in the signal + context pushed by the kernel. Leaving this address untouched looses, if + the triggering instruction happens to be the very first of a region, as + the later adjustments performed by the unwinder would yield an address + outside that region. We need to compensate for the unwinder adjustments + at some point, and this is what this routine is expected to do. signo is passed because on some targets for some signals the PC in context points to the instruction after the faulting one, in which case - the unwinder adjustment is still desired. */ - - /* On a number of targets, we have arranged for the adjustment to be - performed by the MD_FALLBACK_FRAME_STATE circuitry, so we don't provide a - specific instance of this routine. The MD_FALLBACK doesn't have access - to the signal number, though, so the compensation is systematic there and - might be wrong in some cases. */ - - /* Having the compensation wrong leads to potential failures. A very - typical case is what happens when there is no compensation and a signal - triggers for the first instruction in a region : the unwinder adjustment - has it search in the wrong EH region. */ + the unwinder adjustment is still desired. + + We used to perform the compensation in the GCC unwinding fallback macro. + The thread at http://gcc.gnu.org/ml/gcc-patches/2004-05/msg00343.html + describes a couple of issues with this approach. First, on some targets + the adjustment to apply depends on the triggering signal, which is not + easily accessible from the macro. Besides, other languages, e.g. Java, + deal with this by performing the adjustment in the signal handler before + the raise, so fallback adjustments just break those front-ends. */ } #endif diff --git a/gcc/ada/s-intman-posix.adb b/gcc/ada/s-intman-posix.adb index 0c451164076..38379dd1ecb 100644 --- a/gcc/ada/s-intman-posix.adb +++ b/gcc/ada/s-intman-posix.adb @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1992-2006, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2007, Free Software Foundation, Inc. -- -- -- -- GNARL 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- -- @@ -113,17 +113,6 @@ package body System.Interrupt_Management is is pragma Unreferenced (siginfo); - -- The GCC unwinder requires adjustments to the signal's machine context - -- to be able to properly unwind through the signal handler. This is - -- achieved by the target specific subprogram below, provided by init.c - -- to be usable by the non-tasking handler also. - - procedure Adjust_Context_For_Raise - (signo : Signal; - ucontext : System.Address); - pragma Import - (C, Adjust_Context_For_Raise, "__gnat_adjust_context_for_raise"); - Result : Interfaces.C.int; begin @@ -133,8 +122,8 @@ package body System.Interrupt_Management is Result := pthread_sigmask (SIG_UNBLOCK, Signal_Mask'Access, null); pragma Assert (Result = 0); - -- Perform the necessary context adjustments required by the GCC/ZCX - -- unwinder, harmless in the SJLJ case. + -- Perform the necessary context adjustments prior to a raise + -- from a signal handler. Adjust_Context_For_Raise (signo, ucontext); diff --git a/gcc/ada/s-intman-solaris.adb b/gcc/ada/s-intman-solaris.adb index 8c4a6c17c5b..626a14c39ea 100644 --- a/gcc/ada/s-intman-solaris.adb +++ b/gcc/ada/s-intman-solaris.adb @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1992-2006 Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2007, Free Software Foundation, Inc. -- -- -- -- GNARL 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- -- @@ -31,14 +31,13 @@ -- -- ------------------------------------------------------------------------------ --- This is a Solaris version of this package. +-- This is a Solaris version of this package --- Make a careful study of all signals available under the OS, --- to see which need to be reserved, kept always unmasked, --- or kept always unmasked. +-- Make a careful study of all signals available under the OS, to see which +-- need to be reserved, kept always unmasked, or kept always unmasked. --- Be on the lookout for special signals that --- may be used by the thread library. +-- Be on the lookout for special signals that may be used by the thread +-- library. package body System.Interrupt_Management is @@ -73,10 +72,10 @@ package body System.Interrupt_Management is -- Notify_Exception -- ---------------------- - -- This function identifies the Ada exception to be raised using - -- the information when the system received a synchronous signal. - -- Since this function is machine and OS dependent, different code - -- has to be provided for different target. + -- This function identifies the Ada exception to be raised using the + -- information when the system received a synchronous signal. Since this + -- function is machine and OS dependent, different code has to be provided + -- for different target. procedure Notify_Exception (signo : Signal; @@ -92,8 +91,12 @@ package body System.Interrupt_Management is info : access siginfo_t; context : access ucontext_t) is - pragma Unreferenced (context); begin + -- Perform the necessary context adjustments prior to a raise + -- from a signal handler. + + Adjust_Context_For_Raise (signo, context.all'Address); + -- Check that treatment of exception propagation here -- is consistent with treatment of the abort signal in -- System.Task_Primitives.Operations. @@ -171,9 +174,8 @@ package body System.Interrupt_Management is Result := sigemptyset (mask'Access); pragma Assert (Result = 0); - -- ??? For the same reason explained above, we can't mask these - -- signals because otherwise we won't be able to catch more than - -- one signal. + -- ??? For the same reason explained above, we can't mask these signals + -- because otherwise we won't be able to catch more than one signal. act.sa_mask := mask; @@ -239,10 +241,10 @@ package body System.Interrupt_Management is Reserve (SIGINT) := False; end if; - -- We do not have Signal 0 in reality. We just use this value - -- to identify not existing signals (see s-intnam.ads). Therefore, - -- Signal 0 should not be used in all signal related operations hence - -- mark it as reserved. + -- We do not have Signal 0 in reality. We just use this value to + -- identify not existing signals (see s-intnam.ads). Therefore, Signal 0 + -- should not be used in all signal related operations hence mark it as + -- reserved. Reserve (0) := True; end Initialize; diff --git a/gcc/ada/s-intman.ads b/gcc/ada/s-intman.ads index a7909c91c49..528fbf45090 100644 --- a/gcc/ada/s-intman.ads +++ b/gcc/ada/s-intman.ads @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1992-2005 Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2007, Free Software Foundation, Inc. -- -- -- -- GNARL 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- -- @@ -70,10 +70,8 @@ package System.Interrupt_Management is -- systems, but is always reserved when it is defined. If we have the -- convention that ID zero is not used for any "real" signals, and SIGRARE -- = 0 when SIGRARE is not one of the locally supported signals, we can - -- write - + -- write: -- Reserved (SIGRARE) := True; - -- and the initialization code will be portable. Abort_Task_Interrupt : Interrupt_ID; @@ -96,13 +94,22 @@ package System.Interrupt_Management is -- or used to implement time delays. procedure Initialize; - -- Initialize the various variables defined in this package. - -- This procedure must be called before accessing any object from this - -- package, and can be called multiple times. + -- Initialize the various variables defined in this package. This procedure + -- must be called before accessing any object from this package, and can be + -- called multiple times. private type Interrupt_Mask is new System.OS_Interface.sigset_t; - -- In some implementations Interrupt_Mask can be represented as a linked - -- list. + -- In some implementations Interrupt_Mask is represented as a linked list + + procedure Adjust_Context_For_Raise + (Signo : System.OS_Interface.Signal; + Ucontext : System.Address); + pragma Import + (C, Adjust_Context_For_Raise, "__gnat_adjust_context_for_raise"); + -- Target specific hook performing adjustments to the signal's machine + -- context, to be called before an exception may be raised from a signal + -- handler. This service is provided by init.c, together with the + -- non-tasking signal handler. end System.Interrupt_Management; diff --git a/gcc/ada/system-solaris-x86.ads b/gcc/ada/system-solaris-x86.ads index 57eb7b3053c..763141f66e2 100644 --- a/gcc/ada/system-solaris-x86.ads +++ b/gcc/ada/system-solaris-x86.ads @@ -139,7 +139,7 @@ private Support_Long_Shifts : constant Boolean := True; Suppress_Standard_Library : constant Boolean := False; Use_Ada_Main_Program_Name : constant Boolean := False; - ZCX_By_Default : constant Boolean := False; - GCC_ZCX_Support : constant Boolean := False; + ZCX_By_Default : constant Boolean := True; + GCC_ZCX_Support : constant Boolean := True; end System; |