fpcatch.pas 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. {
  2. Copyright (c) 1997-98 by Michael Van Canneyt
  3. Unit to catch segmentation faults and Ctrl-C and exit gracefully
  4. under linux and go32v2
  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 fpcatch;
  12. interface
  13. {$i globdir.inc}
  14. {$ifdef Unix}
  15. uses
  16. baseunix,
  17. unix;
  18. {$endif}
  19. {$ifdef go32v2}
  20. uses
  21. dpmiexcp;
  22. {$endif}
  23. {$ifdef Windows}
  24. uses
  25. windows
  26. {$ifdef HasSignal}
  27. ,signals
  28. {$endif}
  29. ;
  30. {$endif}
  31. {$ifdef HasSignal}
  32. Var
  33. NewSignal,OldSigSegm,OldSigILL,
  34. OldSigInt,OldSigFPE : SignalHandler;
  35. {$endif}
  36. Const
  37. CtrlCPressed : Boolean = false;
  38. Procedure EnableCatchSignals;
  39. Procedure DisableCatchSignals;
  40. {$ifdef DEBUG}
  41. procedure Generate_SIGSEGV;
  42. procedure Generate_SIGFPE;
  43. {$endif DEBUG}
  44. var
  45. StopJmp : Jmp_Buf;
  46. const
  47. StopJmpValid : boolean = false;
  48. {$IFNDEF HASSIGNAL}
  49. const
  50. SIGABRT = 288;
  51. SIGFPE = 289;
  52. SIGILL = 290;
  53. SIGSEGV = 291;
  54. SIGTERM = 292;
  55. SIGALRM = 293;
  56. SIGHUP = 294;
  57. SIGINT = 295;
  58. SIGKILL = 296;
  59. SIGPIPE = 297;
  60. SIGQUIT = 298;
  61. SIGUSR1 = 299;
  62. SIGUSR2 = 300;
  63. SIGNOFP = 301;
  64. SIGTRAP = 302;
  65. SIGTIMR = 303; { Internal for setitimer (SIGALRM, SIGPROF) }
  66. SIGPROF = 304;
  67. SIGMAX = 320;
  68. SIG_BLOCK = 1;
  69. SIG_SETMASK = 2;
  70. SIG_UNBLOCK = 3;
  71. {$ENDIF HASSIGNAL}
  72. Implementation
  73. uses
  74. keyboard,
  75. drivers,
  76. FVConsts,
  77. dos,app,msgbox,
  78. FPCompil,FPIDE;
  79. Const
  80. LastCtrlC : longint = 0;
  81. {$ifdef useresstrings}
  82. resourcestring
  83. {$else}
  84. const
  85. {$endif}
  86. msg_quitconfirm = 'Do You really want to quit?';
  87. {$ifdef DEBUG}
  88. procedure Generate_SIGSEGV;
  89. var
  90. l : plongint;
  91. begin
  92. { Force a SIGSEGV }
  93. l:=pointer (ptrint ($ffffffff));
  94. l^:=1;
  95. end;
  96. procedure Generate_SIGFPE;
  97. var
  98. x,y : real;
  99. begin
  100. { Force a SIGFPE }
  101. y:=-5;
  102. x:=sqrt(y);
  103. end;
  104. {$endif DEBUG}
  105. {$ifdef HasSignal}
  106. {$ifndef SignalIsFunction}
  107. Procedure Catchsignal(Sig : Longint);cdecl;
  108. {$else SignalIsFunction}
  109. {$ifdef SignalIsCdecl}
  110. Function Catchsignal(Sig : longint):longint; cdecl;
  111. {$else not SignalIsCdecl}
  112. Function Catchsignal(Sig : longint):longint;
  113. {$endif not SignalIsCdecl}
  114. {$endif SignalIsFunction}
  115. var MustQuit: boolean;
  116. begin
  117. case Sig of
  118. SIGSEGV : begin
  119. if StopJmpValid then
  120. LongJmp(StopJmp,SIGSEGV);
  121. if Assigned(Application) then IDEApp.Done;
  122. Writeln('Internal SIGSEGV Error caught');
  123. {$ifndef DEBUG}
  124. Halt;
  125. {$else DEBUG}
  126. RunError(216);
  127. {$endif DEBUG}
  128. end;
  129. SIGFPE : begin
  130. if StopJmpValid then
  131. LongJmp(StopJmp,SIGFPE);
  132. if Assigned(Application) then IDEApp.Done;
  133. Writeln('Internal SIGFPE Error caught');
  134. {$ifndef DEBUG}
  135. Halt;
  136. {$else DEBUG}
  137. RunError(207);
  138. {$endif DEBUG}
  139. end;
  140. SIGILL : begin
  141. if StopJmpValid then
  142. LongJmp(StopJmp,SIGILL);
  143. if Assigned(Application) then IDEApp.Done;
  144. Writeln('Internal SIGILL Error caught');
  145. {$ifndef DEBUG}
  146. Halt;
  147. {$else DEBUG}
  148. RunError(216);
  149. {$endif DEBUG}
  150. end;
  151. SIGINT : begin
  152. if StopJmpValid then
  153. LongJmp(StopJmp,SIGINT);
  154. IF NOT CtrlCPressed and Assigned(Application) then
  155. begin
  156. MustQuit:=false;
  157. if GetDosTicks>LastCtrlC+10 then
  158. begin
  159. CtrlCPressed:=true;
  160. Keyboard.PutKeyEvent((kbCtrl shl 16) or kbCtrlC);
  161. LastCtrlC:=GetDosTicks;
  162. end;
  163. end
  164. else
  165. begin
  166. if Assigned(Application) then
  167. MustQuit:=MessageBox(#3+msg_QuitConfirm,nil,mferror+mfyesbutton+mfnobutton)=cmYes
  168. else
  169. MustQuit:=true;
  170. end;
  171. if MustQuit then
  172. begin
  173. if Assigned(Application) then IDEApp.Done;
  174. {$ifndef DEBUG}
  175. Halt;
  176. {$else DEBUG}
  177. RunError(216);
  178. {$endif DEBUG}
  179. end;
  180. end;
  181. end;
  182. {$ifdef SignalIsFunction}
  183. CatchSignal:=0;
  184. {$endif SignalIsFunction}
  185. end;
  186. {$endif def HasSignal}
  187. Const
  188. CatchSignalsEnabled : boolean = false;
  189. Procedure EnableCatchSignals;
  190. {$ifdef Windows}
  191. var Mode: DWORD;
  192. {$endif Windows}
  193. begin
  194. if CatchSignalsEnabled then
  195. exit;
  196. {$ifdef Windows}
  197. if GetConsoleMode(GetStdHandle(cardinal(Std_Input_Handle)), @Mode) then
  198. begin
  199. {$ifdef DEBUG}
  200. Writeln(stderr,'Starting value of ConsoleMode is $',hexstr(Mode,8));
  201. {$endif DEBUG}
  202. SetConsoleMode(GetStdHandle(cardinal(Std_Input_Handle)),
  203. (Mode or ENABLE_MOUSE_INPUT) and not ENABLE_PROCESSED_INPUT);
  204. {$ifdef DEBUG}
  205. end
  206. else
  207. begin
  208. Writeln(stderr,'Call to GetConsoleMode failed, GetLastError=',
  209. GetLastError);
  210. {$endif DEBUG}
  211. end;
  212. {$endif Windows}
  213. {$ifdef go32v2}
  214. {
  215. I think that it was an error to put that here PM
  216. djgpp_set_ctrl_c(false);
  217. at least since that this is now handled in fpusrscr.pas unit
  218. }
  219. {$endif go32v2}
  220. {$ifdef HasSignal}
  221. NewSignal:=@CatchSignal;
  222. OldSigSegm:={$ifdef unix}fpSignal{$else}Signal{$endif}(SIGSEGV,NewSignal);
  223. OldSigInt:={$ifdef unix}fpSignal{$else}Signal{$endif}(SIGINT,NewSignal);
  224. OldSigFPE:={$ifdef unix}fpSignal{$else}Signal{$endif}(SIGFPE,NewSignal);
  225. OldSigILL:={$ifdef unix}fpSignal{$else}Signal{$endif}(SIGILL,NewSignal);
  226. CatchSignalsEnabled:=true;
  227. {$endif}
  228. end;
  229. Procedure DisableCatchSignals;
  230. begin
  231. {$ifdef HasSignal}
  232. if not CatchSignalsEnabled then
  233. exit;
  234. {$ifdef unix}fpSignal{$else}Signal{$endif}(SIGSEGV,OldSigSegm);
  235. {$ifdef unix}fpSignal{$else}Signal{$endif}(SIGINT,OldSigInt);
  236. {$ifdef unix}fpSignal{$else}Signal{$endif}(SIGFPE,OldSigFPE);
  237. {$ifdef unix}fpSignal{$else}Signal{$endif}(SIGILL,OldSigILL);
  238. CatchSignalsEnabled:=false;
  239. {$endif}
  240. end;
  241. end.