Преглед изворни кода

Darwin/AArch64: detect when SIGILL indicates an FPU exception

Parse the ESR (ESR_ELx, Exception Syndrome Register (ELx)), return run error
as in float_raise
Jonas Maebe пре 2 година
родитељ
комит
ae4c8359aa
3 измењених фајлова са 52 додато и 5 уклоњено
  1. 7 2
      rtl/darwin/aarch64/sig_cpu.inc
  2. 42 3
      rtl/darwin/aarch64/sighnd.inc
  3. 3 0
      rtl/darwin/signal.inc

+ 7 - 2
rtl/darwin/aarch64/sig_cpu.inc

@@ -4,6 +4,11 @@
 {$ENDIF}
 
 
+  { ESR bits (exception syndrome) values relevant to FPU exceptions }
+  const
+    __ESR_EC_Mask = cuint32($3f) shl 26;
+    __ESR_EC_TrappedAArch64_FloatingPoint = cuint32(%101100) shl 26;
+    __ESR_ISS_TFV = cuint32(1) shl 23;
 
   type
      __darwin_arm_exception_state64 = record
@@ -19,6 +24,7 @@
           __sp : cuint64;
           __pc : cuint64;
           __cpsr : cuint32;
+          __pad : cuint32;
        end;
 
      __darwin_arm_neon_state64 = record
@@ -28,7 +34,7 @@
           __fpcr : cuint32;
           { array of cuint128 is aligned/padded to multiple of 16 bytes }
           pad: cuint64;
-       end;
+       end {$ifdef VER_3_3}align 16{$endif};
 
      __darwin_arm_debug_state64 = record
           __bvr : array[0..15] of cuint64;
@@ -44,4 +50,3 @@
           __ns : __darwin_arm_neon_state64;
        end;
 
-

+ 42 - 3
rtl/darwin/aarch64/sighnd.inc

@@ -16,6 +16,7 @@
 
 procedure SignalToRunerror(Sig: cint; info : PSigInfo; SigContext:PSigContext); public name '_FPC_DEFAULTSIGHANDLER'; cdecl;
 var
+  fpuexceptionflags: cardinal;
   res : word;
 begin
   res:=0;
@@ -31,11 +32,51 @@ begin
           FPE_FLTINV : Res:=207;  { invalid floating point operation }
           Else
             Res:=207; {coprocessor error}
+          SigContext^.uc_mcontext^.__ns.__fpsr:=SigContext^.uc_mcontext^.__ns.__fpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift);
         end;
       end;
     SIGBUS:
         res:=214;
-    SIGILL,
+    SIGILL:
+      begin
+        { right now, macOS generates SIGILL signals for fpu exceptions on AArch64.
+          Additionally, fpsr is 0 in the context when this happens. Fortunately,
+          the esr is valid, so we can decode that one. }
+        if (Info^.si_code=ILL_ILLTRP) and
+           { Trapped AArch64 floating point exception }
+           ((SigContext^.uc_mcontext^.__es.__esr and __ESR_EC_Mask)=__ESR_EC_TrappedAArch64_FloatingPoint) then
+          begin
+            { the FPU status bits in the ESR are valid }
+            if (SigContext^.uc_mcontext^.__es.__esr and __ESR_ISS_TFV)<>0 then
+              begin
+                fpuexceptionflags:=(SigContext^.uc_mcontext^.__es.__esr shl fpu_exception_mask_to_status_mask_shift) and fpu_exception_mask;
+                if (fpuexceptionflags and fpu_dze)<>0 then
+                  res:=208
+                else if (fpuexceptionflags and fpu_ofe)<>0 then
+                  res:=205
+                else if (fpuexceptionflags and fpu_ufe)<>0 then
+                  res:=206
+                else if (fpuexceptionflags and fpu_ioe)<>0 then
+                  res:=207
+                else if (fpuexceptionflags and fpu_ixe)<>0 then
+                  res:=207
+                else if (fpuexceptionflags and fpu_ide)<>0 then
+                  res:=216
+                else
+                  { unknown FPU exception }
+                  res:=207
+              end
+            else
+              { unknown FPU exception }
+              res:=207;
+          end
+        else
+          res:=216;
+        { for safety, always clear in case we had a SIGILL to prevent potential
+          infinite trap loops, even if it can cause us to miss some FPU
+          exceptions in case we process an actual illegal instruction }
+        SigContext^.uc_mcontext^.__ns.__fpsr:=SigContext^.uc_mcontext^.__ns.__fpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift);
+      end;
     SIGSEGV :
         res:=216;
     SIGINT:
@@ -43,8 +84,6 @@ begin
     SIGQUIT:
         res:=233;
   end;
-  { right now, macOS generates SIGILL signals for fpu exceptions, so always clear the fpu exceptions }
-  SigContext^.uc_mcontext^.__ns.__fpsr:=SigContext^.uc_mcontext^.__ns.__fpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift);
   {$ifdef FPC_USE_SIGPROCMASK}
    reenable_signal(sig);
   {$endif }

+ 3 - 0
rtl/darwin/signal.inc

@@ -298,3 +298,6 @@ const
      FPE_FLTSUB    =  6;  { subscript out of range -NOTIMP on Mac OS X 10.4.7 }
      FPE_INTDIV    =  7;  { integer divide by zero -NOTIMP on Mac OS X 10.4.7 }
      FPE_INTOVF    =  8;  { integer overflow -NOTIMP on Mac OS X 10.4.7 }
+
+{ Codes for SIGILL }
+     ILL_ILLTRP    = 2;   {  /* [XSI] illegal trap */ }