1: /* signal handling
2:
3: Copyright (C) 1995,1996,1997,1998,2000,2003,2006,2007,2011 Free Software Foundation, Inc.
4:
5: This file is part of Gforth.
6:
7: Gforth is free software; you can redistribute it and/or
8: modify it under the terms of the GNU General Public License
9: as published by the Free Software Foundation, either version 3
10: of the License, or (at your option) any later version.
11:
12: This program is distributed in the hope that it will be useful,
13: but WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: GNU General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with this program; if not, see http://www.gnu.org/licenses/.
19:
20: */
21:
22:
23: #include "config.h"
24: #include "forth.h"
25: #include <stdio.h>
26: #include <setjmp.h>
27: #include <string.h>
28: #include <stdlib.h>
29: #if !defined(apollo) && !defined(MSDOS)
30: #include <sys/ioctl.h>
31: #endif
32: #include <sys/types.h>
33: #include <signal.h>
34: #include <termios.h>
35: #include "io.h"
36:
37: #ifndef HAVE_STACK_T
38: /* Darwin uses "struct sigaltstack" instead of "stack_t" */
39: typedef struct sigaltstack stack_t;
40: #endif
41:
42: #define DEFAULTCOLS 80
43: #if defined(MSDOS) || defined (_WIN32) || defined (__CYGWIN__)
44: #define DEFAULTROWS 25
45: #else
46: #define DEFAULTROWS 24
47: #endif
48:
49: UCell cols=DEFAULTCOLS;
50: UCell rows=DEFAULTROWS;
51:
52: #ifndef SA_NODEFER
53: #define SA_NODEFER 0
54: /* systems that don't have SA_NODEFER hopefully don't block anyway */
55: #endif
56:
57: #ifndef SA_ONSTACK
58: #define SA_ONSTACK 0
59: #endif
60:
61: #ifdef SA_SIGINFO
62: void install_signal_handler(int sig, void (*handler)(int, siginfo_t *, void *))
63: /* installs three-argument signal handler for sig */
64: {
65: struct sigaction action;
66:
67: action.sa_sigaction=handler;
68: sigemptyset(&action.sa_mask);
69: action.sa_flags=SA_RESTART|SA_NODEFER|SA_SIGINFO|SA_ONSTACK; /* pass siginfo */
70: sigaction(sig, &action, NULL);
71: }
72: #endif
73:
74: Sigfunc *bsd_signal(int signo, Sigfunc *func)
75: {
76: struct sigaction act, oact;
77:
78: act.sa_handler=func;
79: sigemptyset(&act.sa_mask);
80: act.sa_flags=SA_NODEFER; /* SA_ONSTACK does not work for graceful_exit */
81: if (sigaction(signo,&act,&oact) < 0)
82: return SIG_ERR;
83: else
84: return oact.sa_handler;
85: }
86:
87: static void
88: graceful_exit (int sig)
89: {
90: deprep_terminal();
91: fprintf (stderr, "\n\n%s.\n", strsignal (sig));
92: exit (0x80|sig);
93: }
94:
95: __thread jmp_buf throw_jmp_buf;
96:
97: void throw(int code)
98: {
99: longjmp(throw_jmp_buf,code); /* !! or use siglongjmp ? */
100: }
101:
102: static void
103: signal_throw(int sig)
104: {
105: int code;
106:
107: switch (sig) {
108: case SIGINT: code=-28; break;
109: case SIGFPE: code=-55; break;
110: #ifdef SIGBUS
111: case SIGBUS: code=-23; break;
112: #endif
113: case SIGSEGV: code=-9; break;
114: #ifdef SIGPIPE
115: case SIGPIPE: code=-2049; break;
116: #endif
117: default: code=-256-sig; break;
118: }
119: #ifdef __CYGWIN__
120: /* the SA_NODEFER apparently does not work on Cygwin 1.3.18(0.69/3/2) */
121: {
122: sigset_t emptyset;
123: sigemptyset(&emptyset);
124: sigprocmask(SIG_SETMASK, &emptyset, NULL);
125: }
126: #endif
127: throw(code);
128: }
129:
130: #ifdef SA_SIGINFO
131: static void
132: sigaction_throw(int sig, siginfo_t *info, void *_)
133: {
134: signal_throw(sig);
135: }
136:
137: static void fpe_handler(int sig, siginfo_t *info, void *_)
138: /* handler for SIGFPE */
139: {
140: int code;
141:
142: switch(info->si_code) {
143: #ifdef FPE_INTDIV
144: case FPE_INTDIV: code=BALL_DIVZERO; break;
145: #endif
146: #ifdef FPE_INTOVF
147: case FPE_INTOVF: code=BALL_RESULTRANGE; break; /* integer overflow */
148: #endif
149: #ifdef FPE_FLTDIV
150: case FPE_FLTDIV: code=-42; break; /* floating point divide by zero */
151: #endif
152: #ifdef FPE_FLTOVF
153: case FPE_FLTOVF: code=-43; break; /* floating point overflow */
154: #endif
155: #ifdef FPE_FLTUND
156: case FPE_FLTUND: code=-54; break; /* floating point underflow */
157: #endif
158: #ifdef FPE_FLTRES
159: case FPE_FLTRES: code=-41; break; /* floating point inexact result */
160: #endif
161: #if 0 /* defined by Unix95, but unnecessary */
162: case FPE_FLTINV: /* invalid floating point operation */
163: case FPE_FLTSUB: /* subscript out of range */
164: #endif
165: default: code=-55; break;
166: }
167: throw(code);
168: }
169:
170:
171: #define SPILLAGE 128
172: /* if there's a SIGSEGV within SPILLAGE bytes of some stack, we assume
173: that this stack has over/underflowed */
174:
175: #define JUSTUNDER(addr1,addr2) (((UCell)((addr2)-1-(addr1)))<SPILLAGE)
176: /* true is addr1 is just under addr2 */
177:
178: #define JUSTOVER(addr1,addr2) (((UCell)((addr1)-(addr2)))<SPILLAGE)
179:
180: #define NEXTPAGE(addr) ((Address)((((UCell)(addr)-1)&-pagesize)+pagesize))
181:
182: static void segv_handler(int sig, siginfo_t *info, void *_)
183: {
184: int code=-9;
185: Address addr=info->si_addr;
186: ImageHeader *h=gforth_header;
187:
188: if (JUSTUNDER(addr, h->data_stack_base))
189: code=-3;
190: else if (JUSTOVER(addr, NEXTPAGE(h->data_stack_base+h->data_stack_size)))
191: code=-4;
192: else if (JUSTUNDER(addr, h->return_stack_base))
193: code=-5;
194: else if (JUSTOVER(addr, NEXTPAGE(h->return_stack_base+h->return_stack_size)))
195: code=-6;
196: else if (JUSTUNDER(addr, h->fp_stack_base))
197: code=-44;
198: else if (JUSTOVER(addr, NEXTPAGE(h->fp_stack_base+h->fp_stack_size)))
199: code=-45;
200: throw(code);
201: }
202:
203: #endif /* defined(SA_SIGINFO) */
204:
205: #ifdef SIGCONT
206: static void termprep(int sig)
207: {
208: bsd_signal(sig,termprep);
209: terminal_prepped=0;
210: }
211: #endif
212:
213: void get_winsize()
214: {
215: #ifdef TIOCGWINSZ
216: struct winsize size;
217: size.ws_row = size.ws_col = 0;
218:
219: if (ioctl (1, TIOCGWINSZ, (char *) &size) >= 0) {
220: rows = size.ws_row;
221: cols = size.ws_col;
222: }
223: #else
224: char *s;
225: if ((s=getenv("LINES"))) {
226: rows=atoi(s);
227: }
228: if ((s=getenv("COLUMNS"))) {
229: rows=atoi(s);
230: }
231: #endif
232: if (rows==0)
233: rows=DEFAULTROWS;
234: if (cols==0)
235: cols=DEFAULTCOLS;
236: }
237:
238: #ifdef SIGWINCH
239: static void change_winsize(int sig)
240: {
241: /* signal(sig,change_winsize); should not be necessary with bsd_signal */
242: #ifdef TIOCGWINSZ
243: get_winsize();
244: #endif
245: }
246: #endif
247:
248: void install_signal_handlers(void)
249: {
250:
251: #if 0
252: /* these signals are handled right by default, no need to handle them;
253: they are listed here just for fun */
254: static short sigs_to_default [] = {
255: #ifdef SIGCHLD
256: SIGCHLD,
257: #endif
258: #ifdef SIGINFO
259: SIGINFO,
260: #endif
261: #ifdef SIGIO
262: SIGIO,
263: #endif
264: #ifdef SIGLOST
265: SIGLOST,
266: #endif
267: #ifdef SIGKILL
268: SIGKILL,
269: #endif
270: #ifdef SIGSTOP
271: SIGSTOP,
272: #endif
273: #ifdef SIGPWR
274: SIGPWR,
275: #endif
276: #ifdef SIGMSG
277: SIGMSG,
278: #endif
279: #ifdef SIGDANGER
280: SIGDANGER,
281: #endif
282: #ifdef SIGMIGRATE
283: SIGMIGRATE,
284: #endif
285: #ifdef SIGPRE
286: SIGPRE,
287: #endif
288: #ifdef SIGVIRT
289: SIGVIRT,
290: #endif
291: #ifdef SIGGRANT
292: SIGGRANT,
293: #endif
294: #ifdef SIGRETRACT
295: SIGRETRACT,
296: #endif
297: #ifdef SIGSOUND
298: SIGSOUND,
299: #endif
300: #ifdef SIGSAK
301: SIGSAK,
302: #endif
303: #ifdef SIGTSTP
304: SIGTSTP,
305: #endif
306: #ifdef SIGTTIN
307: SIGTTIN,
308: #endif
309: #ifdef SIGTTOU
310: SIGTTOU,
311: #endif
312: #ifdef SIGSTKFLT
313: SIGSTKFLT,
314: #endif
315: #ifdef SIGUNUSED
316: SIGUNUSED,
317: #endif
318: };
319: #endif
320:
321: static short async_sigs_to_throw [] = {
322: #ifdef SIGINT
323: SIGINT,
324: #endif
325: #ifdef SIGALRM
326: SIGALRM,
327: #endif
328: #ifdef SIGPOLL
329: SIGPOLL,
330: #endif
331: #ifdef SIGPROF
332: SIGPROF,
333: #endif
334: #ifdef SIGURG
335: SIGURG,
336: #endif
337: #ifdef SIGPIPE
338: SIGPIPE,
339: #endif
340: #ifdef SIGUSR1
341: SIGUSR1,
342: #endif
343: #ifdef SIGUSR2
344: SIGUSR2,
345: #endif
346: #ifdef SIGVTALRM
347: SIGVTALRM,
348: #endif
349: #ifdef SIGXFSZ
350: SIGXFSZ,
351: #endif
352: };
353:
354: static short sigs_to_throw [] = {
355: #ifdef SIGBREAK
356: SIGBREAK,
357: #endif
358: #ifdef SIGILL
359: SIGILL,
360: #endif
361: #ifdef SIGEMT
362: SIGEMT,
363: #endif
364: #ifdef SIGFPE
365: SIGFPE,
366: #endif
367: #ifdef SIGIOT
368: SIGIOT,
369: #endif
370: #ifdef SIGSEGV
371: SIGSEGV,
372: #endif
373: #ifdef SIGBUS
374: SIGBUS,
375: #endif
376: #ifdef SIGSYS
377: SIGSYS,
378: #endif
379: #ifdef SIGTRAP
380: SIGTRAP,
381: #endif
382: };
383:
384: static short sigs_to_quit [] = {
385: #ifdef SIGQUIT
386: SIGQUIT,
387: #endif
388: #ifdef SIGHUP
389: SIGHUP,
390: #endif
391: #ifdef SIGABRT
392: SIGABRT,
393: #endif
394: #ifdef SIGTERM
395: SIGTERM,
396: #endif
397: #ifdef SIGXCPU
398: SIGXCPU,
399: #endif
400: };
401: int i;
402: void (*throw_handler)() = die_on_signal ? graceful_exit : signal_throw;
403: #ifdef SIGSTKSZ
404: stack_t sigstack;
405: int sas_retval=-1;
406:
407: sigstack.ss_size=SIGSTKSZ;
408: /* Actually the stack should only be ss_size large, and according to
409: SUSv2 ss_sp should point to the start of the stack, but
410: unfortunately Irix 6.5 (at least) expects ss_sp to point to the
411: end, so we work around this issue by accomodating everyone. */
412: if ((sigstack.ss_sp = gforth_alloc(sigstack.ss_size*2)) != NULL) {
413: sigstack.ss_sp += sigstack.ss_size;
414: sigstack.ss_flags=0;
415: sas_retval=sigaltstack(&sigstack,(stack_t *)0);
416: }
417: #if defined(HAS_FILE) || !defined(STANDALONE)
418: if (debug)
419: fprintf(stderr,"sigaltstack: %s\n",strerror(sas_retval));
420: #endif
421: #endif
422:
423: #define DIM(X) (sizeof (X) / sizeof *(X))
424: /*
425: for (i = 0; i < DIM (sigs_to_ignore); i++)
426: signal (sigs_to_ignore [i], SIG_IGN);
427: */
428: for (i = 0; i < DIM (sigs_to_throw); i++)
429: bsd_signal(sigs_to_throw[i], throw_handler);
430: for (i = 0; i < DIM (async_sigs_to_throw); i++)
431: bsd_signal(async_sigs_to_throw[i],
432: ignore_async_signals ? SIG_IGN : throw_handler);
433: for (i = 0; i < DIM (sigs_to_quit); i++)
434: bsd_signal(sigs_to_quit [i], graceful_exit);
435: #ifdef SA_SIGINFO
436: if (!die_on_signal) {
437: #ifdef SIGFPE
438: install_signal_handler(SIGFPE, fpe_handler);
439: #endif
440: #ifdef SIGSEGV
441: install_signal_handler(SIGSEGV, segv_handler);
442: #endif
443: /* use SA_ONSTACK for all signals that could come from executing
444: wrong code */
445: #ifdef SIGILL
446: install_signal_handler(SIGILL, sigaction_throw);
447: #endif
448: #ifdef SIGBUS
449: install_signal_handler(SIGBUS, sigaction_throw);
450: #endif
451: #ifdef SIGTRAP
452: install_signal_handler(SIGTRAP, sigaction_throw);
453: #endif
454: }
455: #endif /* defined(SA_SIGINFO) */
456: #ifdef SIGCONT
457: bsd_signal(SIGCONT, termprep);
458: #endif
459: #ifdef SIGWINCH
460: bsd_signal(SIGWINCH, change_winsize);
461: #endif
462: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>