fpcatch.pas 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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. {$ifdef Unix}
  111. Procedure Catchsignal(Sig : Longint);cdecl;
  112. {$else}
  113. Function Catchsignal(Sig : longint):longint;
  114. {$endif}
  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. {$ifdef FPC}
  158. if GetDosTicks>LastCtrlC+10 then
  159. begin
  160. CtrlCPressed:=true;
  161. Keyboard.PutKeyEvent((kbCtrl shl 16) or kbCtrlC);
  162. LastCtrlC:=GetDosTicks;
  163. end;
  164. {$endif FPC}
  165. end
  166. else
  167. begin
  168. if Assigned(Application) then
  169. MustQuit:=MessageBox(#3+msg_QuitConfirm,nil,mferror+mfyesbutton+mfnobutton)=cmYes
  170. else
  171. MustQuit:=true;
  172. end;
  173. if MustQuit then
  174. begin
  175. if Assigned(Application) then IDEApp.Done;
  176. {$ifndef DEBUG}
  177. Halt;
  178. {$else DEBUG}
  179. RunError(216);
  180. {$endif DEBUG}
  181. end;
  182. end;
  183. end;
  184. {$ifndef Unix}
  185. CatchSignal:=0;
  186. {$endif}
  187. end;
  188. {$endif def HasSignal}
  189. Const
  190. CatchSignalsEnabled : boolean = false;
  191. Procedure EnableCatchSignals;
  192. {$ifdef Windows}
  193. var Mode: DWORD;
  194. {$endif Windows}
  195. begin
  196. if CatchSignalsEnabled then
  197. exit;
  198. {$ifdef Windows}
  199. if GetConsoleMode(GetStdHandle(cardinal(Std_Input_Handle)), @Mode) then
  200. begin
  201. {$ifdef DEBUG}
  202. Writeln(stderr,'Starting value of ConsoleMode is $',hexstr(Mode,8));
  203. {$endif DEBUG}
  204. SetConsoleMode(GetStdHandle(cardinal(Std_Input_Handle)),
  205. (Mode or ENABLE_MOUSE_INPUT) and not ENABLE_PROCESSED_INPUT);
  206. {$ifdef DEBUG}
  207. end
  208. else
  209. begin
  210. Writeln(stderr,'Call to GetConsoleMode failed, GetLastError=',
  211. GetLastError);
  212. {$endif DEBUG}
  213. end;
  214. {$endif Windows}
  215. {$ifdef go32v2}
  216. {
  217. I think that it was an error to put that here PM
  218. djgpp_set_ctrl_c(false);
  219. at least since that this is now handled in fpusrscr.pas unit
  220. }
  221. {$endif go32v2}
  222. {$ifdef HasSignal}
  223. {$ifndef TP}
  224. NewSignal:=SignalHandler(@CatchSignal);
  225. {$else TP}
  226. NewSignal:=SignalHandler(CatchSignal);
  227. {$endif TP}
  228. OldSigSegm:={$ifdef unix}{$ifdef ver1_0}Signal{$else}fpSignal{$endif}{$else}Signal{$endif}(SIGSEGV,NewSignal);
  229. OldSigInt:={$ifdef unix}{$ifdef ver1_0}Signal{$else}fpSignal{$endif}{$else}Signal{$endif}(SIGINT,NewSignal);
  230. OldSigFPE:={$ifdef unix}{$ifdef ver1_0}Signal{$else}fpSignal{$endif}{$else}Signal{$endif}(SIGFPE,NewSignal);
  231. OldSigILL:={$ifdef unix}{$ifdef ver1_0}Signal{$else}fpSignal{$endif}{$else}Signal{$endif}(SIGILL,NewSignal);
  232. CatchSignalsEnabled:=true;
  233. {$endif}
  234. end;
  235. Procedure DisableCatchSignals;
  236. begin
  237. {$ifdef HasSignal}
  238. if not CatchSignalsEnabled then
  239. exit;
  240. {$ifdef unix}{$ifdef ver1_0}Signal{$else}fpSignal{$endif}{$else}Signal{$endif}(SIGSEGV,OldSigSegm);
  241. {$ifdef unix}{$ifdef ver1_0}Signal{$else}fpSignal{$endif}{$else}Signal{$endif}(SIGINT,OldSigInt);
  242. {$ifdef unix}{$ifdef ver1_0}Signal{$else}fpSignal{$endif}{$else}Signal{$endif}(SIGFPE,OldSigFPE);
  243. {$ifdef unix}{$ifdef ver1_0}Signal{$else}fpSignal{$endif}{$else}Signal{$endif}(SIGILL,OldSigILL);
  244. CatchSignalsEnabled:=false;
  245. {$endif}
  246. end;
  247. end.