signals.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. {
  2. This file is part of the Free Pascal run time library.
  3. This unit implements unix like signal handling for win32
  4. Copyright (c) 1999-2006 by the Free Pascal development team.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$IFNDEF FPC_DOTTEDUNITS}
  12. unit signals;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. interface
  15. {$PACKRECORDS C}
  16. { Signals }
  17. const
  18. SIGABRT = 288;
  19. SIGFPE = 289;
  20. SIGILL = 290;
  21. SIGSEGV = 291;
  22. SIGTERM = 292;
  23. SIGALRM = 293;
  24. SIGHUP = 294;
  25. SIGINT = 295;
  26. SIGKILL = 296;
  27. SIGPIPE = 297;
  28. SIGQUIT = 298;
  29. SIGUSR1 = 299;
  30. SIGUSR2 = 300;
  31. SIGNOFP = 301;
  32. SIGTRAP = 302;
  33. SIGTIMR = 303; { Internal for setitimer (SIGALRM, SIGPROF) }
  34. SIGPROF = 304;
  35. SIGMAX = 320;
  36. SIG_BLOCK = 1;
  37. SIG_SETMASK = 2;
  38. SIG_UNBLOCK = 3;
  39. function SIG_DFL( x: longint) : longint; cdecl;
  40. function SIG_ERR( x: longint) : longint; cdecl;
  41. function SIG_IGN( x: longint) : longint; cdecl;
  42. type
  43. SignalHandler = function (v : longint) : longint;cdecl;
  44. PSignalHandler = ^SignalHandler; { to be compatible with linux.pp }
  45. function signal(sig : longint;func : SignalHandler) : SignalHandler;
  46. const
  47. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  48. type
  49. FLOATING_SAVE_AREA = record
  50. ControlWord : DWORD;
  51. StatusWord : DWORD;
  52. TagWord : DWORD;
  53. ErrorOffset : DWORD;
  54. ErrorSelector : DWORD;
  55. DataOffset : DWORD;
  56. DataSelector : DWORD;
  57. RegisterArea : array[0..79] of BYTE;
  58. Cr0NpxState : DWORD;
  59. end;
  60. _FLOATING_SAVE_AREA = FLOATING_SAVE_AREA;
  61. TFLOATINGSAVEAREA = FLOATING_SAVE_AREA;
  62. PFLOATINGSAVEAREA = ^FLOATING_SAVE_AREA;
  63. CONTEXT = record
  64. ContextFlags : DWORD;
  65. Dr0 : DWORD;
  66. Dr1 : DWORD;
  67. Dr2 : DWORD;
  68. Dr3 : DWORD;
  69. Dr6 : DWORD;
  70. Dr7 : DWORD;
  71. FloatSave : FLOATING_SAVE_AREA;
  72. SegGs : DWORD;
  73. SegFs : DWORD;
  74. SegEs : DWORD;
  75. SegDs : DWORD;
  76. Edi : DWORD;
  77. Esi : DWORD;
  78. Ebx : DWORD;
  79. Edx : DWORD;
  80. Ecx : DWORD;
  81. Eax : DWORD;
  82. Ebp : DWORD;
  83. Eip : DWORD;
  84. SegCs : DWORD;
  85. EFlags : DWORD;
  86. Esp : DWORD;
  87. SegSs : DWORD;
  88. end;
  89. LPCONTEXT = ^CONTEXT;
  90. _CONTEXT = CONTEXT;
  91. TCONTEXT = CONTEXT;
  92. PCONTEXT = ^CONTEXT;
  93. type
  94. pexception_record = ^exception_record;
  95. EXCEPTION_RECORD = record
  96. ExceptionCode : cardinal;
  97. ExceptionFlags : longint;
  98. ExceptionRecord : pexception_record;
  99. ExceptionAddress : pointer;
  100. NumberParameters : longint;
  101. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of pointer;
  102. end;
  103. PEXCEPTION_POINTERS = ^EXCEPTION_POINTERS;
  104. EXCEPTION_POINTERS = record
  105. ExceptionRecord : PEXCEPTION_RECORD ;
  106. ContextRecord : PCONTEXT ;
  107. end;
  108. implementation
  109. const
  110. EXCEPTION_ACCESS_VIOLATION = $c0000005;
  111. EXCEPTION_BREAKPOINT = $80000003;
  112. EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
  113. EXCEPTION_SINGLE_STEP = $80000004;
  114. EXCEPTION_ARRAY_BOUNDS_EXCEEDED = $c000008c;
  115. EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d;
  116. EXCEPTION_FLT_DIVIDE_BY_ZERO = $c000008e;
  117. EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
  118. EXCEPTION_FLT_INVALID_OPERATION = $c0000090;
  119. EXCEPTION_FLT_OVERFLOW = $c0000091;
  120. EXCEPTION_FLT_STACK_CHECK = $c0000092;
  121. EXCEPTION_FLT_UNDERFLOW = $c0000093;
  122. EXCEPTION_INT_DIVIDE_BY_ZERO = $c0000094;
  123. EXCEPTION_INT_OVERFLOW = $c0000095;
  124. EXCEPTION_INVALID_HANDLE = $c0000008;
  125. EXCEPTION_PRIV_INSTRUCTION = $c0000096;
  126. EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
  127. EXCEPTION_NONCONTINUABLE = $1;
  128. EXCEPTION_STACK_OVERFLOW = $c00000fd;
  129. EXCEPTION_INVALID_DISPOSITION = $c0000026;
  130. EXCEPTION_ILLEGAL_INSTRUCTION = $C000001D;
  131. EXCEPTION_IN_PAGE_ERROR = $C0000006;
  132. EXCEPTION_EXECUTE_HANDLER = 1;
  133. EXCEPTION_CONTINUE_EXECUTION = -(1);
  134. EXCEPTION_CONTINUE_SEARCH = 0;
  135. type
  136. { type of functions that should be used for exception handling }
  137. LPTOP_LEVEL_EXCEPTION_FILTER = function(excep :PEXCEPTION_POINTERS) : longint;stdcall;
  138. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : LPTOP_LEVEL_EXCEPTION_FILTER)
  139. : LPTOP_LEVEL_EXCEPTION_FILTER;
  140. stdcall; external 'kernel32' name 'SetUnhandledExceptionFilter';
  141. var
  142. signal_list : Array[SIGABRT..SIGMAX] of SignalHandler;
  143. var
  144. { value of the stack segment
  145. to check if the call stack can be written on exceptions }
  146. _SS : cardinal;
  147. const
  148. Exception_handler_installed : boolean = false;
  149. MAX_Level = 16;
  150. except_level : byte = 0;
  151. var
  152. except_eip : array[0..Max_level-1] of longint;
  153. except_signal : array[0..Max_level-1] of longint;
  154. reset_fpu : array[0..max_level-1] of boolean;
  155. procedure JumpToHandleSignal;
  156. var
  157. res, eip, _ebp, sigtype : longint;
  158. begin
  159. asm
  160. movl (%ebp),%eax
  161. movl %eax,_ebp
  162. end;
  163. {$ifdef SIGNALS_DEBUG}
  164. if IsConsole then
  165. Writeln(stderr,'In start of JumpToHandleSignal');
  166. {$endif SIGNALS_DEBUG}
  167. if except_level>0 then
  168. dec(except_level)
  169. else
  170. RunError(216);
  171. eip:=except_eip[except_level];
  172. sigtype:=except_signal[except_level];
  173. if reset_fpu[except_level] then
  174. SysResetFPU;
  175. if assigned(System_exception_frame) then
  176. { get the handler in front again }
  177. asm
  178. movl System_exception_frame,%eax
  179. movl %eax,%fs:(0)
  180. end;
  181. if (sigtype>=SIGABRT) and (sigtype<=SIGMAX) and
  182. (signal_list[sigtype]<>@SIG_DFL) then
  183. begin
  184. res:=signal_list[sigtype](sigtype);
  185. end
  186. else
  187. res:=0;
  188. if res=0 then
  189. Begin
  190. {$ifdef SIGNALS_DEBUG}
  191. if IsConsole then
  192. Writeln(stderr,'In JumpToHandleSignal');
  193. {$endif SIGNALS_DEBUG}
  194. RunError(sigtype);
  195. end
  196. else
  197. { jump back to old code }
  198. asm
  199. movl eip,%eax
  200. push %eax
  201. movl _ebp,%eax
  202. push %eax
  203. leave
  204. ret
  205. end;
  206. end;
  207. function Signals_exception_handler
  208. (excep_exceptionrecord :PEXCEPTION_RECORD;
  209. excep_frame : PEXCEPTION_FRAME;
  210. excep_contextrecord : PCONTEXT;
  211. dispatch : pointer) : longint;stdcall;
  212. var frame,res : longint;
  213. function CallSignal(sigtype,frame : longint;must_reset_fpu : boolean) : longint;
  214. begin
  215. {$ifdef SIGNALS_DEBUG}
  216. if IsConsole then
  217. begin
  218. writeln(stderr,'CallSignal called for signal ',sigtype);
  219. dump_stack(stderr,pointer(frame));
  220. end;
  221. {$endif SIGNALS_DEBUG}
  222. {if frame=0 then
  223. begin
  224. CallSignal:=1;
  225. writeln(stderr,'CallSignal frame is zero');
  226. end
  227. else }
  228. begin
  229. if except_level >= Max_level then
  230. exit;
  231. except_eip[except_level]:=excep_ContextRecord^.Eip;
  232. except_signal[except_level]:=sigtype;
  233. reset_fpu[except_level]:=must_reset_fpu;
  234. inc(except_level);
  235. {dec(excep^.ContextRecord^.Esp,4);
  236. plongint (excep^.ContextRecord^.Esp)^ := longint(excep^.ContextRecord^.Eip);}
  237. excep_ContextRecord^.Eip:=longint(@JumpToHandleSignal);
  238. excep_ExceptionRecord^.ExceptionCode:=0;
  239. CallSignal:=0;
  240. {$ifdef SIGNALS_DEBUG}
  241. if IsConsole then
  242. writeln(stderr,'Exception_Continue_Execution set');
  243. {$endif SIGNALS_DEBUG}
  244. end;
  245. end;
  246. begin
  247. if excep_ContextRecord^.SegSs=_SS then
  248. frame:=excep_ContextRecord^.Ebp
  249. else
  250. frame:=0;
  251. { default : unhandled !}
  252. res:=1;
  253. {$ifdef SIGNALS_DEBUG}
  254. if IsConsole then
  255. writeln(stderr,'Signals exception ',
  256. hexstr(excep_ExceptionRecord^.ExceptionCode,8));
  257. {$endif SIGNALS_DEBUG}
  258. case excep_ExceptionRecord^.ExceptionCode of
  259. EXCEPTION_ACCESS_VIOLATION :
  260. res:=CallSignal(SIGSEGV,frame,false);
  261. { EXCEPTION_BREAKPOINT = $80000003;
  262. EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
  263. EXCEPTION_SINGLE_STEP = $80000004; }
  264. EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
  265. res:=CallSignal(SIGSEGV,frame,false);
  266. EXCEPTION_FLT_DENORMAL_OPERAND :
  267. begin
  268. res:=CallSignal(SIGFPE,frame,true);
  269. end;
  270. EXCEPTION_FLT_DIVIDE_BY_ZERO :
  271. begin
  272. res:=CallSignal(SIGFPE,frame,true);
  273. {excep^.ContextRecord^.FloatSave.StatusWord:=excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  274. end;
  275. {EXCEPTION_FLT_INEXACT_RESULT = $c000008f; }
  276. EXCEPTION_FLT_INVALID_OPERATION :
  277. begin
  278. res:=CallSignal(SIGFPE,frame,true);
  279. end;
  280. EXCEPTION_FLT_OVERFLOW :
  281. begin
  282. res:=CallSignal(SIGFPE,frame,true);
  283. end;
  284. EXCEPTION_FLT_STACK_CHECK :
  285. begin
  286. res:=CallSignal(SIGFPE,frame,true);
  287. end;
  288. EXCEPTION_FLT_UNDERFLOW :
  289. begin
  290. res:=CallSignal(SIGFPE,frame,true); { should be accepted as zero !! }
  291. end;
  292. EXCEPTION_INT_DIVIDE_BY_ZERO :
  293. res:=CallSignal(SIGFPE,frame,false);
  294. EXCEPTION_INT_OVERFLOW :
  295. res:=CallSignal(SIGFPE,frame,false);
  296. {EXCEPTION_INVALID_HANDLE = $c0000008;
  297. EXCEPTION_PRIV_INSTRUCTION = $c0000096;
  298. EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
  299. EXCEPTION_NONCONTINUABLE = $1;}
  300. EXCEPTION_STACK_OVERFLOW :
  301. res:=CallSignal(SIGSEGV,frame,false);
  302. {EXCEPTION_INVALID_DISPOSITION = $c0000026;}
  303. EXCEPTION_ILLEGAL_INSTRUCTION,
  304. EXCEPTION_PRIV_INSTRUCTION,
  305. EXCEPTION_IN_PAGE_ERROR,
  306. EXCEPTION_SINGLE_STEP : res:=CallSignal(SIGSEGV,frame,false);
  307. { Ignore EXCEPTION_INVALID_HANDLE exceptions }
  308. EXCEPTION_INVALID_HANDLE : res:=0;
  309. end;
  310. Signals_exception_handler:=res;
  311. end;
  312. function API_signals_exception_handler(exceptptrs : PEXCEPTION_POINTERS) : longint; stdcall;
  313. begin
  314. API_signals_exception_handler:=Signals_exception_handler(
  315. @exceptptrs^.ExceptionRecord,
  316. nil,
  317. @exceptptrs^.ContextRecord,
  318. nil);
  319. end;
  320. const
  321. PreviousHandler : LPTOP_LEVEL_EXCEPTION_FILTER = nil;
  322. Prev_Handler : pointer = nil;
  323. Prev_fpc_handler : pointer = nil;
  324. procedure install_exception_handler;
  325. {$ifdef SIGNALS_DEBUG}
  326. var
  327. oldexceptaddr,newexceptaddr : longint;
  328. {$endif SIGNALS_DEBUG}
  329. begin
  330. if Exception_handler_installed then
  331. exit;
  332. if assigned(System_exception_frame) then
  333. begin
  334. prev_fpc_handler:=System_exception_frame^.handler;
  335. System_exception_frame^.handler:=@Signals_exception_handler;
  336. { get the handler in front again }
  337. asm
  338. movl %fs:(0),%eax
  339. movl %eax,prev_handler
  340. movl System_exception_frame,%eax
  341. movl %eax,%fs:(0)
  342. end;
  343. Exception_handler_installed:=true;
  344. exit;
  345. end;
  346. {$ifdef SIGNALS_DEBUG}
  347. asm
  348. movl $0,%eax
  349. movl %fs:(%eax),%eax
  350. movl %eax,oldexceptaddr
  351. end;
  352. {$endif SIGNALS_DEBUG}
  353. PreviousHandler:=SetUnhandledExceptionFilter(@API_signals_exception_handler);
  354. {$ifdef SIGNALS_DEBUG}
  355. asm
  356. movl $0,%eax
  357. movl %fs:(%eax),%eax
  358. movl %eax,newexceptaddr
  359. end;
  360. if IsConsole then
  361. begin
  362. writeln(stderr,'Old exception ',hexstr(oldexceptaddr,8),
  363. ' new exception ',hexstr(newexceptaddr,8));
  364. writeln('SetUnhandledExceptionFilter returned ',hexstr(longint(PreviousHandler),8));
  365. end;
  366. {$endif SIGNALS_DEBUG}
  367. Exception_handler_installed := true;
  368. end;
  369. procedure remove_exception_handler;
  370. begin
  371. if not Exception_handler_installed then
  372. exit;
  373. if assigned(System_exception_frame) then
  374. begin
  375. if assigned(prev_fpc_handler) then
  376. System_exception_frame^.handler:=prev_fpc_handler;
  377. prev_fpc_handler:=nil;
  378. { restore old handler order again }
  379. if assigned(prev_handler) then
  380. asm
  381. movl prev_handler,%eax
  382. movl %eax,%fs:(0)
  383. end;
  384. prev_handler:=nil;
  385. Exception_handler_installed:=false;
  386. exit;
  387. end;
  388. SetUnhandledExceptionFilter(PreviousHandler);
  389. PreviousHandler:=nil;
  390. Exception_handler_installed:=false;
  391. end;
  392. function SIG_ERR(x:longint):longint; cdecl;
  393. begin
  394. SIG_ERR:=-1;
  395. end;
  396. function SIG_IGN(x:longint):longint; cdecl;
  397. begin
  398. SIG_IGN:=-1;
  399. end;
  400. function SIG_DFL(x:longint):longint; cdecl;
  401. begin
  402. SIG_DFL:=0;
  403. end;
  404. function signal(sig : longint;func : SignalHandler) : SignalHandler;
  405. var
  406. temp : SignalHandler;
  407. begin
  408. if ((sig < SIGABRT) or (sig > SIGMAX) or (sig = SIGKILL)) then
  409. begin
  410. signal:=@SIG_ERR;
  411. runerror(201);
  412. end;
  413. if not Exception_handler_installed then
  414. install_exception_handler;
  415. temp := signal_list[sig];
  416. signal_list[sig] := func;
  417. signal:=temp;
  418. end;
  419. var
  420. i : longint;
  421. initialization
  422. asm
  423. xorl %eax,%eax
  424. movw %ss,%ax
  425. movl %eax,_SS
  426. end;
  427. for i:=SIGABRT to SIGMAX do
  428. signal_list[i]:=@SIG_DFL;
  429. {install_exception_handler;
  430. delay this to first use
  431. as other units also might install their handlers PM }
  432. finalization
  433. remove_exception_handler;
  434. end.