signals.pp 14 KB

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