fpcatch.pas 6.6 KB

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