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