Hi,

this isn't really valid Ada semantics, but some people enable traps-on-fp-
exceptions in the FPU on Solaris and expect the Ada exception to be caught.
There is a glitch with the x87 and the SPARC FPUs: the SIGFPE is delivered 
after the faulting instruction by Solaris, so the unwinder is fooled and 
miscomputes the faulting address.

Fixed thusly, tested on x86/Solaris and SPARC/Solaris, OK for mainline?


2013-05-23  Eric Botcazou  <ebotca...@adacore.com>

libgcc/
        * config/sparc/sol2-unwind.h (MD_FALLBACK_FRAME_STATE_FOR): Do not set
        fs->signal_frame for SIGFPE raised for IEEE-754 exceptions.
        * config/i386/sol2-unwind.h (x86_fallback_frame_state): Likewise.


2013-05-23  Eric Botcazou  <ebotca...@adacore.com>

        * gnat.dg/fp_exception.adb: New test.


-- 
Eric Botcazou
Index: config/sparc/sol2-unwind.h
===================================================================
--- config/sparc/sol2-unwind.h	(revision 199191)
+++ config/sparc/sol2-unwind.h	(working copy)
@@ -403,7 +403,12 @@ MD_FALLBACK_FRAME_STATE_FOR (struct _Unw
   fs->retaddr_column = 0;
   fs->regs.reg[0].how = REG_SAVED_OFFSET;
   fs->regs.reg[0].loc.offset = (long)shifted_ra_location - new_cfa;
-  fs->signal_frame = 1;
+
+  /* SIGFPE for IEEE-754 exceptions is delivered after the faulting insn
+     rather than before it, so don't set fs->signal_frame in that case.
+     We test whether the cexc field of the FSR is zero.  */
+  if ((mctx->fpregs.fpu_fsr & 0x1f) == 0)
+    fs->signal_frame = 1;
 
   return _URC_NO_REASON;
 }
Index: config/i386/sol2-unwind.h
===================================================================
--- config/i386/sol2-unwind.h	(revision 199190)
+++ config/i386/sol2-unwind.h	(working copy)
@@ -249,7 +249,12 @@ x86_fallback_frame_state (struct _Unwind
   fs->regs.reg[8].how = REG_SAVED_OFFSET;
   fs->regs.reg[8].loc.offset = (long)&mctx->gregs[EIP] - new_cfa;
   fs->retaddr_column = 8;
-  fs->signal_frame = 1;
+
+  /* SIGFPE for IEEE-754 exceptions is delivered after the faulting insn
+     rather than before it, so don't set fs->signal_frame in that case.
+     We test whether the ES field of the Status Register is zero.  */
+  if ((mctx->fpregs.fp_reg_set.fpchip_state.status & 0x80) == 0)
+    fs->signal_frame = 1;
 
   return _URC_NO_REASON;
 }
-- { dg-do run { target *-*-solaris2.* } }

procedure FP_Exception is

  type my_fixed is digits 15;
  for my_fixed'size use 64;
  fixed1 : my_fixed := 1.0;  
  fixed2 : my_fixed := -0.0;
  mask_all : constant integer := 16#1F#;

  procedure fpsetmask(mask : in integer);
  pragma IMPORT (C, fpsetmask, "fpsetmask");

begin 

  -- Mask all floating point exceptions so they can be trapped
  fpsetmask (mask_all);

  fixed1 := fixed1 / fixed2;

exception
  when others => null;
end;

Reply via email to