OSDN Git Service

2007-08-14 Olivier Hainque <hainque@adacore.com>
authorcharlet <charlet@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 14 Aug 2007 08:43:46 +0000 (08:43 +0000)
committercharlet <charlet@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 14 Aug 2007 08:43:46 +0000 (08:43 +0000)
* system-solaris-x86.ads (ZCX_By_Default): Switch to True.
(GCC_ZCX_Support): Switch to True.

* s-intman-solaris.adb (Notify_Exception): Call
Adjust_Context_For_Raise before raising, as expected for signal
handlers in general.

* s-intman-posix.adb (Notify_Exception): Remove declaration of
Adjust_Context_For_Raise, moved to the spec of this unit to be visible
to other implementation bodies.

* s-intman.ads (Adjust_Context_For_Raise): Declare and import here, to
be visible by multiple implementation bodies.

* init.c [VMS section] (__gnat_handle_vms_condition): Adjust context
only for conditions coming from hardware.
[alpha-tru64 section] (__gnat_adjust_context_for_raise): Implement,
adjustments to signal context prior to exception raise from signal
handler.
(__gnat_map_signal for VxWorks): Map SIGSEGV to Storage_Error in RTP
mode.
Solaris section: (__gnat_adjust_context_for_raise): New function.
Implementation of the machine context adjustments to perform prior to
raise from a signal handler. Version for both sparc and x86.
(HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE): Define.
(__gnat_error_handler): Expect a third argument, ucontext_t *. Adjust it
prior to raising as expected for any handler, before possible nested
faults to make sure all the contexts in a chain have been adjusted by
the time we propagate.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@127433 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ada/init.c
gcc/ada/s-intman-posix.adb
gcc/ada/s-intman-solaris.adb
gcc/ada/s-intman.ads
gcc/ada/system-solaris-x86.ads

index 06a1c80..068fca5 100644 (file)
@@ -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
index 0c45116..38379dd 100644 (file)
@@ -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);
 
index 8c4a6c1..626a14c 100644 (file)
@@ -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- --
 --                                                                          --
 ------------------------------------------------------------------------------
 
---  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;
index a7909c9..528fbf4 100644 (file)
@@ -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;
index 57eb7b3..763141f 100644 (file)
@@ -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;