Browse Source

* multiple exception handling works
(for linux only if syslinux is compiled with -dnewsignal)

pierre 25 years ago
parent
commit
74907e307a
2 changed files with 239 additions and 26 deletions
  1. 71 6
      rtl/linux/syslinux.pp
  2. 168 20
      rtl/win32/syswin32.pp

+ 71 - 6
rtl/linux/syslinux.pp

@@ -625,11 +625,40 @@ end;
                          SystemUnit Initialization
 *****************************************************************************}
 
+{$ifdef I386}
+{ this should be defined in i386 directory !! PM }
+const
+  fpucw : word = $1332;
+  FPU_Invalid = 1;
+  FPU_Denormal = 2;
+  FPU_DivisionByZero = 4;
+  FPU_Overflow = 8;
+  FPU_Underflow = $10;
+  FPU_StackUnderflow = $20;
+  FPU_StackOverflow = $40;
+
+{$endif I386}
+
+Procedure ResetFPU;
+begin
+{$ifdef I386}
+  asm
+    fninit
+    fldcw   fpucw
+  end;
+{$endif I386}
+end;
+
 {$ifndef newSignal}
 Procedure SignalToRunError(Sig:longint);
 begin
   case sig of
-    8 : HandleError(200);
+    8 : begin
+    { this is not allways necessary but I don't know yet
+      how to tell if it is or not PM }
+          ResetFPU;
+          HandleError(200);
+        end;
    11 : HandleError(216);
   end;
 end;
@@ -650,20 +679,52 @@ end;
 
 {$i i386/signal.inc}
 
-procedure SignalToRunerror(Sig: longint); cdecl;
+procedure SignalToRunerror(Sig: longint; SigContext: SigContextRec); cdecl;
+var
+  res,fpustate : word;
 begin
   case sig of
-    8 : HandleError(200);
+    8 : begin
+    { this is not allways necessary but I don't know yet
+      how to tell if it is or not PM }
+{$ifdef I386}
+          fpustate:=0;
+          res:=200;
+          if assigned(SigContext.fpstate) then
+            fpuState:=SigContext.fpstate^.sw;
+{$ifdef SYSTEMDEBUG}
+          Writeln(stderr,'FpuState = ',Hexstr(FpuState,4));
+{$endif SYSTEMDEBUG}
+          if (FpuState and $7f) <> 0 then
+            begin
+              if (FpuState and FPU_Invalid)<>0 then
+                res:=216
+              else if (FpuState and FPU_Denormal)<>0 then
+                res:=216
+              else if (FpuState and FPU_DivisionByZero)<>0 then
+                res:=200
+              else if (FpuState and FPU_Overflow)<>0 then
+                res:=205
+              else if (FpuState and FPU_Underflow)<>0 then
+                res:=206
+              else
+                res:=207;  {'Coprocessor Error'}
+              ResetFPU;
+            end;
+{$endif I386}
+          HandleError(res);
+        end;
    11 : HandleError(216);
   end;
 end;
 
 Procedure InstallSignals;
 const
-  act: SigActionRec = (handler:(Sh:@SignalToRunError);sa_mask:0;sa_flags:$40000000 or $10000000;
+  act: SigActionRec = (handler:(Sa:@SignalToRunError);sa_mask:0;sa_flags:0;
                        Sa_restorer: NIL);
   oldact: PSigActionRec = Nil;
 begin
+  ResetFPU;
   SigAction(8,@act,oldact);
   SigAction(11,@act,oldact);
 end;
@@ -747,7 +808,11 @@ End.
 
 {
   $Log$
-  Revision 1.40  2000-03-31 13:24:28  jonas
+  Revision 1.41  2000-03-31 23:21:19  pierre
+    * multiple exception handling works
+      (for linux only if syslinux is compiled with -dnewsignal)
+
+  Revision 1.40  2000/03/31 13:24:28  jonas
     * signal handling using sigaction when compiled with -dnewsignal
       (allows multiple signals to be received in one run)
 
@@ -798,4 +863,4 @@ End.
   Revision 1.25  1999/07/28 23:18:36  peter
     * closedir fixes, which now disposes the pdir itself
 
-}
+}

+ 168 - 20
rtl/win32/syswin32.pp

@@ -17,6 +17,10 @@
 unit syswin32;
 interface
 
+{$ifdef SYSTEMDEBUG}
+  {$define SYSTEMEXCEPTIONDEBUG}
+{$endif SYSTEMDEBUG}
+
 {$ifdef i386}
   {$define Set_i386_Exception_handler}
 {$endif i386}
@@ -792,6 +796,9 @@ var
     to check if the call stack can be written on exceptions }
   _SS : longint;
 
+const
+  fpucw : word = $1332;
+
 procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
   begin
      IsLibrary:=false;
@@ -807,6 +814,8 @@ procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
         movl %eax,Win32StackTop
         movw %ss,%bp
         movl %ebp,_SS
+        fninit
+        fldcw   fpucw
         xorl %ebp,%ebp
         call PASCALMAIN
         popl %ebp
@@ -910,8 +919,9 @@ const
      EXCEPTION_ILLEGAL_INSTRUCTION = $C000001D;
      EXCEPTION_IN_PAGE_ERROR = $C0000006;
 
-     ExceptionContinueExecution = 0;
-     ExceptionContinueSearch = 1;
+     EXCEPTION_EXECUTE_HANDLER = 1;
+     EXCEPTION_CONTINUE_EXECUTION = -(1);
+     EXCEPTION_CONTINUE_SEARCH = 0;
   type
 
      FLOATING_SAVE_AREA = record
@@ -984,55 +994,189 @@ type pexception_record = ^exception_record;
        : LPTOP_LEVEL_EXCEPTION_FILTER;
        external 'kernel32' name 'SetUnhandledExceptionFilter';
 
+const
+  MAX_Level = 16;
+  except_level : byte = 0;
+var
+  except_eip   : array[0..Max_level-1] of longint;
+  except_error : array[0..Max_level-1] of byte;
+  reset_fpu    : array[0..max_level-1] of boolean;
+
+{$ifdef SYSTEMEXCEPTIONDEBUG}
+  procedure DebugHandleErrorAddrFrame(error, addr, frame : longint);
+    begin
+      if IsConsole then
+        begin
+          write(stderr,'call to HandleErrorAddrFrame(error=',error);
+          write(stderr,',addr=',hexstr(addr,8));
+          writeln(stderr,',frame=',hexstr(frame,8),')');
+        end;
+      HandleErrorAddrFrame(error,addr,frame);
+    end;
+{$endif SYSTEMEXCEPTIONDEBUG}
+
+  procedure JumpToHandleErrorFrame;
+    var
+      eip,ebp,error : longint;
+    begin
+      asm
+        movl (%ebp),%eax
+        movl %eax,ebp
+      end;
+      if except_level>0 then
+        dec(except_level);
+      eip:=except_eip[except_level];
+      error:=except_error[except_level];
+{$ifdef SYSTEMEXCEPTIONDEBUG}
+      if IsConsole then
+        begin
+          writeln(stderr,'In JumpToHandleErrorFrame error=',error);
+        end;
+{$endif SYSTEMEXCEPTIONDEBUG}
+      if reset_fpu[except_level] then
+        asm
+          fninit
+          fldcw   fpucw
+        end;
+      { build a fake stack }
+      asm
+        movl   ebp,%eax
+        pushl  %eax
+        movl   eip,%eax
+        pushl  %eax
+        movl   error,%eax
+        pushl  %eax
+        movl   eip,%eax
+        pushl  %eax
+        movl   ebp,%ebp // Change frame pointer
+{$ifdef SYSTEMEXCEPTIONDEBUG}
+        jmpl   DebugHandleErrorAddrFrame
+{$else not SYSTEMEXCEPTIONDEBUG}
+        jmpl   HandleErrorAddrFrame
+{$endif SYSTEMEXCEPTIONDEBUG}
+      end;
+
+    end;
+
   function syswin32_i386_exception_handler(excep :PEXCEPTION_POINTERS) : longint;
-    var frame : longint;
+    var frame,res  : longint;
+        function SysHandleErrorFrame(error,frame : longint;must_reset_fpu : boolean) : longint;
+          begin
+            if frame=0 then
+              SysHandleErrorFrame:=Exception_Continue_Search
+            else
+              begin
+                 if except_level >= Max_level then
+                   exit;
+                 except_eip[except_level]:=excep^.ContextRecord^.Eip;
+                 except_error[except_level]:=error;
+                 reset_fpu[except_level]:=must_reset_fpu;
+                 inc(except_level);
+                 excep^.ContextRecord^.Eip:=longint(@JumpToHandleErrorFrame);
+                 excep^.ExceptionRecord^.ExceptionCode:=0;
+                 SysHandleErrorFrame:=Exception_Continue_Execution;
+{$ifdef SYSTEMEXCEPTIONDEBUG}
+                 if IsConsole then
+                   begin
+                     writeln(stderr,'Exception Continue Exception set at ',
+                       hexstr(except_eip[except_level],8));
+                     writeln(stderr,'Eip changed to ',
+                       hexstr(longint(@JumpToHandleErrorFrame),8), ' error=',error);
+                   end;
+{$endif SYSTEMEXCEPTIONDEBUG}
+              end;
+          end;
+
     begin
-       { default : unhandled !}
        if excep^.ContextRecord^.SegSs=_SS then
          frame:=excep^.ContextRecord^.Ebp
        else
          frame:=0;
-       syswin32_i386_exception_handler:=ExceptionContinueSearch;
+       { default : unhandled !}
+       res:=Exception_Continue_Search;
+{$ifdef SYSTEMEXCEPTIONDEBUG}
+       if IsConsole then
+         writeln(stderr,'Exception  ',
+           hexstr(excep^.ExceptionRecord^.ExceptionCode,8));
+{$endif SYSTEMEXCEPTIONDEBUG}
        case excep^.ExceptionRecord^.ExceptionCode of
          EXCEPTION_ACCESS_VIOLATION :
-           HandleErrorFrame(216,frame);
+           res:=SysHandleErrorFrame(216,frame,false);
          { EXCEPTION_BREAKPOINT = $80000003;
          EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
          EXCEPTION_SINGLE_STEP = $80000004; }
          EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
-           HandleErrorFrame(201,frame);
-         { EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d; }
+           res:=SysHandleErrorFrame(201,frame,false);
+         EXCEPTION_FLT_DENORMAL_OPERAND :
+           begin
+             res:=SysHandleErrorFrame(216,frame,true);
+           end;
          EXCEPTION_FLT_DIVIDE_BY_ZERO :
-           HandleErrorFrame(200,frame);
-         {EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
-         EXCEPTION_FLT_INVALID_OPERATION = $c0000090;}
+           begin
+             res:=SysHandleErrorFrame(200,frame,true);
+             {excep^.ContextRecord^.FloatSave.StatusWord:=excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
+           end;
+         {EXCEPTION_FLT_INEXACT_RESULT = $c000008f; }
+         EXCEPTION_FLT_INVALID_OPERATION :
+           begin
+             res:=SysHandleErrorFrame(207,frame,true);
+           end;
          EXCEPTION_FLT_OVERFLOW :
-           HandleErrorFrame(205,frame);
+           begin
+             res:=SysHandleErrorFrame(205,frame,true);
+           end;
          EXCEPTION_FLT_STACK_CHECK :
-           HandleErrorFrame(207,frame);
-         { EXCEPTION_FLT_UNDERFLOW :
-           HandleErrorFrame(206,frame); should be accepted as zero !! }
+           begin
+             res:=SysHandleErrorFrame(207,frame,true);
+           end;
+         EXCEPTION_FLT_UNDERFLOW :
+           begin
+             res:=SysHandleErrorFrame(206,frame,true); { should be accepted as zero !! }
+           end;
          EXCEPTION_INT_DIVIDE_BY_ZERO :
-           HandleErrorFrame(200,frame);
+           res:=SysHandleErrorFrame(200,frame,false);
          EXCEPTION_INT_OVERFLOW :
-           HandleErrorFrame(215,frame);
+           res:=SysHandleErrorFrame(215,frame,false);
          {EXCEPTION_INVALID_HANDLE = $c0000008;
          EXCEPTION_PRIV_INSTRUCTION = $c0000096;
          EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
          EXCEPTION_NONCONTINUABLE = $1;}
          EXCEPTION_STACK_OVERFLOW :
-           HandleErrorFrame(202,frame);
+           res:=SysHandleErrorFrame(202,frame,false);
          {EXCEPTION_INVALID_DISPOSITION = $c0000026;}
          EXCEPTION_ILLEGAL_INSTRUCTION,
+         EXCEPTION_PRIV_INSTRUCTION,
          EXCEPTION_IN_PAGE_ERROR,
-         EXCEPTION_SINGLE_STEP : HandleErrorFrame(217,frame)
+         EXCEPTION_SINGLE_STEP : res:=SysHandleErrorFrame(217,frame,false);
          end;
+       syswin32_i386_exception_handler:=res;
     end;
 
 
   procedure install_exception_handlers;
+{$ifdef SYSTEMEXCEPTIONDEBUG}
+    var
+      oldexceptaddr,newexceptaddr : longint;
+{$endif SYSTEMEXCEPTIONDEBUG}
     begin
+{$ifdef SYSTEMEXCEPTIONDEBUG}
+      asm
+        movl $0,%eax
+        movl %fs:(%eax),%eax
+        movl %eax,oldexceptaddr
+      end;
+{$endif SYSTEMEXCEPTIONDEBUG}
       SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
+{$ifdef SYSTEMEXCEPTIONDEBUG}
+      asm
+        movl $0,%eax
+        movl %fs:(%eax),%eax
+        movl %eax,newexceptaddr
+      end;
+      if IsConsole then
+        writeln(stderr,'Old exception  ',hexstr(oldexceptaddr,8),
+          ' new exception  ',hexstr(newexceptaddr,8));
+{$endif SYSTEMEXCEPTIONDEBUG}
     end;
 
   procedure remove_exception_handlers;
@@ -1186,7 +1330,11 @@ end.
 
 {
   $Log$
-  Revision 1.62  2000-03-16 20:42:26  michael
+  Revision 1.63  2000-03-31 23:21:19  pierre
+    * multiple exception handling works
+      (for linux only if syslinux is compiled with -dnewsignal)
+
+  Revision 1.62  2000/03/16 20:42:26  michael
   + Added more system exception handling afte T. Schatzl remark
 
   Revision 1.61  2000/03/10 09:21:11  pierre