浏览代码

o fixed darwin/i386 signal handling:
* fixed sigcontextrec definition
* work around missing Mac OS X support for reporting integer
division-by-zero as such (reported as generic SIGFPE)
* return from signal handler to HandleErrorFrame (just like
on ppc) instead of calling it (and fix up fpu and sse
status words when doing so)

git-svn-id: trunk@9196 -

Jonas Maebe 18 年之前
父节点
当前提交
52a8c3a40c
共有 2 个文件被更改,包括 57 次插入16 次删除
  1. 18 8
      rtl/darwin/i386/sig_cpu.inc
  2. 39 8
      rtl/darwin/i386/sighnd.inc

+ 18 - 8
rtl/darwin/i386/sig_cpu.inc

@@ -603,16 +603,26 @@
 
 *)
 
+    tdarwin_stack_t = record
+        ss_sp    : pchar;        { signal stack base }
+        ss_size  : clong;         { signal stack length }
+        ss_flags : cint;         { SA_DISABLE and/or SA_ONSTACK }
+    end;
+
     mcontext_t = record
       es: i386_exception_state_t;
-      ss: i386_thread_state_t;
+      ts: i386_thread_state_t;
       fs: i386_float_state_t;
     end;
 
-   psigcontext = ^sigcontextrec;
-   psigcontextrec = ^sigcontextrec;
-   sigcontextrec = record
-     sc_onstack: cint;
-     sc_mask: cint;
-     ts: i386_thread_state;
-   end;
+     psigcontext = ^sigcontextrec;
+     psigcontextrec = ^sigcontextrec;
+     sigcontextrec = record
+        uc_onstack : cint;
+        uc_sigmask : sigset_t;        { signal mask used by this context }
+        uc_stack   : tdarwin_stack_t; { stack used by this context }
+        uc_link    : psigcontextrec;  { pointer to resuming context }
+        uc_mcsize  : size_t;          { size of the machine context passed in }
+        uc_mcontext: ^mcontext_t;      { machine specific context }
+     end;
+

+ 39 - 8
rtl/darwin/i386/sighnd.inc

@@ -16,6 +16,7 @@
 procedure SignalToRunerror(Sig: cint; info : psiginfo; SigContext:PSigContext); cdecl;
 
 var
+  p: pbyte;
   res : word;
 
 begin
@@ -31,15 +32,35 @@ begin
           FPE_FLTRES,             { floating point inexact result }
           FPE_FLTINV : Res:=207;  { invalid floating point operation }
           Else
-            Res:=207; { coprocessor error }
+            begin
+              { Assume that if an integer divide was executed, the }
+              { error was a divide-by-zero (FPE_INTDIV is not      }
+              { implemented as of 10.5.0)                          }
+              p:=pbyte(sigcontext^.uc_mcontext^.ts.eip);
+              if assigned(p) then
+                begin
+                  { skip some prefix bytes }
+                  while (p^ in [$66,$67]) do
+                    inc(p);
+                  if (p^ in [$f6,$f7]) and
+                     (((p+1)^ and (%110 shl 3)) = (%110 shl 3)) then
+                    Res:=200
+                  else
+                    Res:=207; { coprocessor error }
+                end
+              else
+                Res:=207;
+            end;
         end;
-        { the following is true on ppc, but fortunately not on x86 }
-        { FPU exceptions are completely disabled by the kernel if one occurred, it  }
-        { seems this is necessary to be able to return to user mode. They can be    }
-        { enabled by executing a sigreturn, however then the exception is triggered }
-        { triggered again immediately if we don't turn off the "exception occurred" }
-        { flags in fpscr                                                            }
+        { make sure any fpu operations won't trigger new exceptions in handler }
         sysResetFPU;
+        { Now clear exception flags in the context }
+        { perform an fnclex: clear exception and busy flags }
+        sigcontext^.uc_mcontext^.fs.fpu_fsw.flag0:=
+          sigcontext^.uc_mcontext^.fs.fpu_fsw.flag0 and (not(%11111111) and not(1 shl 15));
+        { also clear sse exception flags }
+        sigcontext^.uc_mcontext^.fs.fpu_mxcsr:=
+          sigcontext^.uc_mcontext^.fs.fpu_mxcsr and not(%111111)
       end;
     SIGILL,
     SIGBUS,
@@ -51,6 +72,16 @@ begin
   {$endif }
 
   if (res <> 0) then
-    HandleErrorAddrFrame(res,pointer(sigcontext^.ts.eip),pointer(sigcontext^.ts.ebp));
+    begin
+      { assume regcall calling convention is the default }
+      sigcontext^.uc_mcontext^.ts.eax:=res;
+      sigcontext^.uc_mcontext^.ts.edx:=sigcontext^.uc_mcontext^.ts.eip;
+      sigcontext^.uc_mcontext^.ts.ecx:=sigcontext^.uc_mcontext^.ts.ebp;
+      { the ABI expects the stack pointer to be 4 bytes off alignment }
+      { due to the return address which has been pushed               }
+      dec(sigcontext^.uc_mcontext^.ts.esp,sizeof(pointer));
+      { return to run time error handler }
+      sigcontext^.uc_mcontext^.ts.eip:=ptruint(@HandleErrorAddrFrame);
+    end;
 end;