* multiple exception handling works

(for linux only if syslinux is compiled with -dnewsignal)
This commit is contained in:
pierre 2000-03-31 23:21:19 +00:00
parent f6da28673a
commit 74907e307a
2 changed files with 240 additions and 27 deletions

View File

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

View File

@ -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';
function syswin32_i386_exception_handler(excep :PEXCEPTION_POINTERS) : longint;
var frame : longint;
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,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