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