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
This commit is contained in:
Jonas Maebe 2022-10-23 09:46:48 +02:00
parent a1ea1dd98e
commit ae4c8359aa
3 changed files with 52 additions and 5 deletions

View File

@ -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;

View File

@ -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 }

View File

@ -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 */ }