123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- {
- This file is part of the Free Pascal run time library.
- This unit implements unix like signal handling for win32
- Copyright (c) 1999-2006 by the Free Pascal development team.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit signals;
- interface
- {$PACKRECORDS C}
- { Signals }
- const
- SIGABRT = 288;
- SIGFPE = 289;
- SIGILL = 290;
- SIGSEGV = 291;
- SIGTERM = 292;
- SIGALRM = 293;
- SIGHUP = 294;
- SIGINT = 295;
- SIGKILL = 296;
- SIGPIPE = 297;
- SIGQUIT = 298;
- SIGUSR1 = 299;
- SIGUSR2 = 300;
- SIGNOFP = 301;
- SIGTRAP = 302;
- SIGTIMR = 303; { Internal for setitimer (SIGALRM, SIGPROF) }
- SIGPROF = 304;
- SIGMAX = 320;
- SIG_BLOCK = 1;
- SIG_SETMASK = 2;
- SIG_UNBLOCK = 3;
- function SIG_DFL( x: longint) : longint; cdecl;
- function SIG_ERR( x: longint) : longint; cdecl;
- function SIG_IGN( x: longint) : longint; cdecl;
- type
- SignalHandler = function (v : longint) : longint;cdecl;
- PSignalHandler = ^SignalHandler; { to be compatible with linux.pp }
- function signal(sig : longint;func : SignalHandler) : SignalHandler;
- const
- EXCEPTION_MAXIMUM_PARAMETERS = 15;
- type
- FLOATING_SAVE_AREA = record
- ControlWord : DWORD;
- StatusWord : DWORD;
- TagWord : DWORD;
- ErrorOffset : DWORD;
- ErrorSelector : DWORD;
- DataOffset : DWORD;
- DataSelector : DWORD;
- RegisterArea : array[0..79] of BYTE;
- Cr0NpxState : DWORD;
- end;
- _FLOATING_SAVE_AREA = FLOATING_SAVE_AREA;
- TFLOATINGSAVEAREA = FLOATING_SAVE_AREA;
- PFLOATINGSAVEAREA = ^FLOATING_SAVE_AREA;
- CONTEXT = record
- ContextFlags : DWORD;
- Dr0 : DWORD;
- Dr1 : DWORD;
- Dr2 : DWORD;
- Dr3 : DWORD;
- Dr6 : DWORD;
- Dr7 : DWORD;
- FloatSave : FLOATING_SAVE_AREA;
- SegGs : DWORD;
- SegFs : DWORD;
- SegEs : DWORD;
- SegDs : DWORD;
- Edi : DWORD;
- Esi : DWORD;
- Ebx : DWORD;
- Edx : DWORD;
- Ecx : DWORD;
- Eax : DWORD;
- Ebp : DWORD;
- Eip : DWORD;
- SegCs : DWORD;
- EFlags : DWORD;
- Esp : DWORD;
- SegSs : DWORD;
- end;
- LPCONTEXT = ^CONTEXT;
- _CONTEXT = CONTEXT;
- TCONTEXT = CONTEXT;
- PCONTEXT = ^CONTEXT;
- type
- pexception_record = ^exception_record;
- EXCEPTION_RECORD = record
- ExceptionCode : cardinal;
- ExceptionFlags : longint;
- ExceptionRecord : pexception_record;
- ExceptionAddress : pointer;
- NumberParameters : longint;
- ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of pointer;
- end;
- PEXCEPTION_POINTERS = ^EXCEPTION_POINTERS;
- EXCEPTION_POINTERS = record
- ExceptionRecord : PEXCEPTION_RECORD ;
- ContextRecord : PCONTEXT ;
- end;
- implementation
- const
- EXCEPTION_ACCESS_VIOLATION = $c0000005;
- EXCEPTION_BREAKPOINT = $80000003;
- EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
- EXCEPTION_SINGLE_STEP = $80000004;
- EXCEPTION_ARRAY_BOUNDS_EXCEEDED = $c000008c;
- EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d;
- EXCEPTION_FLT_DIVIDE_BY_ZERO = $c000008e;
- EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
- EXCEPTION_FLT_INVALID_OPERATION = $c0000090;
- EXCEPTION_FLT_OVERFLOW = $c0000091;
- EXCEPTION_FLT_STACK_CHECK = $c0000092;
- EXCEPTION_FLT_UNDERFLOW = $c0000093;
- EXCEPTION_INT_DIVIDE_BY_ZERO = $c0000094;
- EXCEPTION_INT_OVERFLOW = $c0000095;
- EXCEPTION_INVALID_HANDLE = $c0000008;
- EXCEPTION_PRIV_INSTRUCTION = $c0000096;
- EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
- EXCEPTION_NONCONTINUABLE = $1;
- EXCEPTION_STACK_OVERFLOW = $c00000fd;
- EXCEPTION_INVALID_DISPOSITION = $c0000026;
- EXCEPTION_ILLEGAL_INSTRUCTION = $C000001D;
- EXCEPTION_IN_PAGE_ERROR = $C0000006;
- EXCEPTION_EXECUTE_HANDLER = 1;
- EXCEPTION_CONTINUE_EXECUTION = -(1);
- EXCEPTION_CONTINUE_SEARCH = 0;
- type
- { type of functions that should be used for exception handling }
- LPTOP_LEVEL_EXCEPTION_FILTER = function(excep :PEXCEPTION_POINTERS) : longint;stdcall;
- function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : LPTOP_LEVEL_EXCEPTION_FILTER)
- : LPTOP_LEVEL_EXCEPTION_FILTER;
- stdcall; external 'kernel32' name 'SetUnhandledExceptionFilter';
- var
- signal_list : Array[SIGABRT..SIGMAX] of SignalHandler;
- var
- { value of the stack segment
- to check if the call stack can be written on exceptions }
- _SS : cardinal;
- const
- Exception_handler_installed : boolean = false;
- MAX_Level = 16;
- except_level : byte = 0;
- var
- except_eip : array[0..Max_level-1] of longint;
- except_signal : array[0..Max_level-1] of longint;
- reset_fpu : array[0..max_level-1] of boolean;
- procedure JumpToHandleSignal;
- var
- res, eip, _ebp, sigtype : longint;
- begin
- asm
- movl (%ebp),%eax
- movl %eax,_ebp
- end;
- {$ifdef SIGNALS_DEBUG}
- if IsConsole then
- Writeln(stderr,'In start of JumpToHandleSignal');
- {$endif SIGNALS_DEBUG}
- if except_level>0 then
- dec(except_level)
- else
- RunError(216);
- eip:=except_eip[except_level];
- sigtype:=except_signal[except_level];
- if reset_fpu[except_level] then
- SysResetFPU;
- if assigned(System_exception_frame) then
- { get the handler in front again }
- asm
- movl System_exception_frame,%eax
- movl %eax,%fs:(0)
- end;
- if (sigtype>=SIGABRT) and (sigtype<=SIGMAX) and
- (signal_list[sigtype]<>@SIG_DFL) then
- begin
- res:=signal_list[sigtype](sigtype);
- end
- else
- res:=0;
- if res=0 then
- Begin
- {$ifdef SIGNALS_DEBUG}
- if IsConsole then
- Writeln(stderr,'In JumpToHandleSignal');
- {$endif SIGNALS_DEBUG}
- RunError(sigtype);
- end
- else
- { jump back to old code }
- asm
- movl eip,%eax
- push %eax
- movl _ebp,%eax
- push %eax
- leave
- ret
- end;
- end;
- function Signals_exception_handler
- (excep_exceptionrecord :PEXCEPTION_RECORD;
- excep_frame : PEXCEPTION_FRAME;
- excep_contextrecord : PCONTEXT;
- dispatch : pointer) : longint;stdcall;
- var frame,res : longint;
- function CallSignal(sigtype,frame : longint;must_reset_fpu : boolean) : longint;
- begin
- {$ifdef SIGNALS_DEBUG}
- if IsConsole then
- begin
- writeln(stderr,'CallSignal called for signal ',sigtype);
- dump_stack(stderr,pointer(frame));
- end;
- {$endif SIGNALS_DEBUG}
- {if frame=0 then
- begin
- CallSignal:=1;
- writeln(stderr,'CallSignal frame is zero');
- end
- else }
- begin
- if except_level >= Max_level then
- exit;
- except_eip[except_level]:=excep_ContextRecord^.Eip;
- except_signal[except_level]:=sigtype;
- reset_fpu[except_level]:=must_reset_fpu;
- inc(except_level);
- {dec(excep^.ContextRecord^.Esp,4);
- plongint (excep^.ContextRecord^.Esp)^ := longint(excep^.ContextRecord^.Eip);}
- excep_ContextRecord^.Eip:=longint(@JumpToHandleSignal);
- excep_ExceptionRecord^.ExceptionCode:=0;
- CallSignal:=0;
- {$ifdef SIGNALS_DEBUG}
- if IsConsole then
- writeln(stderr,'Exception_Continue_Execution set');
- {$endif SIGNALS_DEBUG}
- end;
- end;
- begin
- if excep_ContextRecord^.SegSs=_SS then
- frame:=excep_ContextRecord^.Ebp
- else
- frame:=0;
- { default : unhandled !}
- res:=1;
- {$ifdef SIGNALS_DEBUG}
- if IsConsole then
- writeln(stderr,'Signals exception ',
- hexstr(excep_ExceptionRecord^.ExceptionCode,8));
- {$endif SIGNALS_DEBUG}
- case excep_ExceptionRecord^.ExceptionCode of
- EXCEPTION_ACCESS_VIOLATION :
- res:=CallSignal(SIGSEGV,frame,false);
- { EXCEPTION_BREAKPOINT = $80000003;
- EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
- EXCEPTION_SINGLE_STEP = $80000004; }
- EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
- res:=CallSignal(SIGSEGV,frame,false);
- EXCEPTION_FLT_DENORMAL_OPERAND :
- begin
- res:=CallSignal(SIGFPE,frame,true);
- end;
- EXCEPTION_FLT_DIVIDE_BY_ZERO :
- begin
- res:=CallSignal(SIGFPE,frame,true);
- {excep^.ContextRecord^.FloatSave.StatusWord:=excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
- end;
- {EXCEPTION_FLT_INEXACT_RESULT = $c000008f; }
- EXCEPTION_FLT_INVALID_OPERATION :
- begin
- res:=CallSignal(SIGFPE,frame,true);
- end;
- EXCEPTION_FLT_OVERFLOW :
- begin
- res:=CallSignal(SIGFPE,frame,true);
- end;
- EXCEPTION_FLT_STACK_CHECK :
- begin
- res:=CallSignal(SIGFPE,frame,true);
- end;
- EXCEPTION_FLT_UNDERFLOW :
- begin
- res:=CallSignal(SIGFPE,frame,true); { should be accepted as zero !! }
- end;
- EXCEPTION_INT_DIVIDE_BY_ZERO :
- res:=CallSignal(SIGFPE,frame,false);
- EXCEPTION_INT_OVERFLOW :
- res:=CallSignal(SIGFPE,frame,false);
- {EXCEPTION_INVALID_HANDLE = $c0000008;
- EXCEPTION_PRIV_INSTRUCTION = $c0000096;
- EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
- EXCEPTION_NONCONTINUABLE = $1;}
- EXCEPTION_STACK_OVERFLOW :
- res:=CallSignal(SIGSEGV,frame,false);
- {EXCEPTION_INVALID_DISPOSITION = $c0000026;}
- EXCEPTION_ILLEGAL_INSTRUCTION,
- EXCEPTION_PRIV_INSTRUCTION,
- EXCEPTION_IN_PAGE_ERROR,
- EXCEPTION_SINGLE_STEP : res:=CallSignal(SIGSEGV,frame,false);
- { Ignore EXCEPTION_INVALID_HANDLE exceptions }
- EXCEPTION_INVALID_HANDLE : res:=0;
- end;
- Signals_exception_handler:=res;
- end;
- function API_signals_exception_handler(exceptptrs : PEXCEPTION_POINTERS) : longint; stdcall;
- begin
- API_signals_exception_handler:=Signals_exception_handler(
- @exceptptrs^.ExceptionRecord,
- nil,
- @exceptptrs^.ContextRecord,
- nil);
- end;
- const
- PreviousHandler : LPTOP_LEVEL_EXCEPTION_FILTER = nil;
- Prev_Handler : pointer = nil;
- Prev_fpc_handler : pointer = nil;
- procedure install_exception_handler;
- {$ifdef SIGNALS_DEBUG}
- var
- oldexceptaddr,newexceptaddr : longint;
- {$endif SIGNALS_DEBUG}
- begin
- if Exception_handler_installed then
- exit;
- if assigned(System_exception_frame) then
- begin
- prev_fpc_handler:=System_exception_frame^.handler;
- System_exception_frame^.handler:=@Signals_exception_handler;
- { get the handler in front again }
- asm
- movl %fs:(0),%eax
- movl %eax,prev_handler
- movl System_exception_frame,%eax
- movl %eax,%fs:(0)
- end;
- Exception_handler_installed:=true;
- exit;
- end;
- {$ifdef SIGNALS_DEBUG}
- asm
- movl $0,%eax
- movl %fs:(%eax),%eax
- movl %eax,oldexceptaddr
- end;
- {$endif SIGNALS_DEBUG}
- PreviousHandler:=SetUnhandledExceptionFilter(@API_signals_exception_handler);
- {$ifdef SIGNALS_DEBUG}
- asm
- movl $0,%eax
- movl %fs:(%eax),%eax
- movl %eax,newexceptaddr
- end;
- if IsConsole then
- begin
- writeln(stderr,'Old exception ',hexstr(oldexceptaddr,8),
- ' new exception ',hexstr(newexceptaddr,8));
- writeln('SetUnhandledExceptionFilter returned ',hexstr(longint(PreviousHandler),8));
- end;
- {$endif SIGNALS_DEBUG}
- Exception_handler_installed := true;
- end;
- procedure remove_exception_handler;
- begin
- if not Exception_handler_installed then
- exit;
- if assigned(System_exception_frame) then
- begin
- if assigned(prev_fpc_handler) then
- System_exception_frame^.handler:=prev_fpc_handler;
- prev_fpc_handler:=nil;
- { restore old handler order again }
- if assigned(prev_handler) then
- asm
- movl prev_handler,%eax
- movl %eax,%fs:(0)
- end;
- prev_handler:=nil;
- Exception_handler_installed:=false;
- exit;
- end;
- SetUnhandledExceptionFilter(PreviousHandler);
- PreviousHandler:=nil;
- Exception_handler_installed:=false;
- end;
- function SIG_ERR(x:longint):longint; cdecl;
- begin
- SIG_ERR:=-1;
- end;
- function SIG_IGN(x:longint):longint; cdecl;
- begin
- SIG_IGN:=-1;
- end;
- function SIG_DFL(x:longint):longint; cdecl;
- begin
- SIG_DFL:=0;
- end;
- function signal(sig : longint;func : SignalHandler) : SignalHandler;
- var
- temp : SignalHandler;
- begin
- if ((sig < SIGABRT) or (sig > SIGMAX) or (sig = SIGKILL)) then
- begin
- signal:=@SIG_ERR;
- runerror(201);
- end;
- if not Exception_handler_installed then
- install_exception_handler;
- temp := signal_list[sig];
- signal_list[sig] := func;
- signal:=temp;
- end;
- var
- i : longint;
- initialization
- asm
- xorl %eax,%eax
- movw %ss,%ax
- movl %eax,_SS
- end;
- for i:=SIGABRT to SIGMAX do
- signal_list[i]:=@SIG_DFL;
- {install_exception_handler;
- delay this to first use
- as other units also might install their handlers PM }
- finalization
- remove_exception_handler;
- end.
|