signals.pp 13 KB

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