Commit 43316a01 by Olivier Hainque Committed by Arnaud Charlet

system-solaris-x86.ads (ZCX_By_Default): Switch to True.

2007-08-14  Olivier Hainque  <hainque@adacore.com>

	* 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.

From-SVN: r127433
parent 2cd44f5a
......@@ -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
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......@@ -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;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment