1 /***********************************************************************/
5 /* Xavier Leroy, projet Gallium, INRIA Rocquencourt */
7 /* Copyright 2007 Institut National de Recherche en Informatique et */
8 /* en Automatique. All rights reserved. This file is distributed */
9 /* under the terms of the GNU Library General Public License, with */
10 /* the special exception on linking described in file ../LICENSE. */
12 /***********************************************************************/
14 /* $Id: signals_asm.c 8768 2008-01-11 16:13:18Z doligez $ */
16 /* Signal handling, code specific to the native-code compiler */
18 #if defined(TARGET_amd64) && defined (SYS_linux)
27 #include "signals_machdep.h"
28 #include "signals_osdep.h"
31 #ifdef HAS_STACK_OVERFLOW_DETECTION
33 #include <sys/resource.h>
40 typedef void (*signal_handler)(int signo);
43 extern signal_handler caml_win32_signal(int sig, signal_handler action);
44 #define signal(sig,act) caml_win32_signal(sig,act)
45 extern void caml_win32_overflow_detection();
48 extern char * caml_code_area_start, * caml_code_area_end;
50 #define Is_in_code_area(pc) \
51 ( ((char *)(pc) >= caml_code_area_start && \
52 (char *)(pc) <= caml_code_area_end) \
53 || (Classify_addr(pc) & In_code_area) )
55 /* This routine is the common entry point for garbage collection
56 and signal handling. It can trigger a callback to Caml code.
57 With system threads, this callback can cause a context switch.
58 Hence [caml_garbage_collection] must not be called from regular C code
59 (e.g. the [caml_alloc] function) because the context of the call
60 (e.g. [intern_val]) may not allow context switching.
61 Only generated assembly code can call [caml_garbage_collection],
62 via the caml_call_gc assembly stubs. */
64 void caml_garbage_collection(void)
66 caml_young_limit = caml_young_start;
67 if (caml_young_ptr < caml_young_start || caml_force_major_slice) {
68 caml_minor_collection();
70 caml_process_pending_signals();
73 DECLARE_SIGNAL_HANDLER(handle_signal)
75 #if !defined(POSIX_SIGNALS) && !defined(BSD_SIGNALS)
76 signal(sig, handle_signal);
78 if (sig < 0 || sig >= NSIG) return;
79 if (caml_try_leave_blocking_section_hook ()) {
80 caml_execute_signal(sig, 1);
81 caml_enter_blocking_section_hook();
83 caml_record_signal(sig);
84 /* Some ports cache [caml_young_limit] in a register.
85 Use the signal context to modify that register too, but only if
86 we are inside Caml code (not inside C code). */
87 #if defined(CONTEXT_PC) && defined(CONTEXT_YOUNG_LIMIT)
88 if (Is_in_code_area(CONTEXT_PC))
89 CONTEXT_YOUNG_LIMIT = (context_reg) caml_young_limit;
94 int caml_set_signal_action(int signo, int action)
96 signal_handler oldact;
98 struct sigaction sigact, oldsigact;
106 sigact.sa_handler = SIG_DFL;
110 sigact.sa_handler = SIG_IGN;
114 SET_SIGACT(sigact, handle_signal);
117 sigemptyset(&sigact.sa_mask);
118 if (sigaction(signo, &sigact, &oldsigact) == -1) return -1;
119 oldact = oldsigact.sa_handler;
122 case 0: act = SIG_DFL; break;
123 case 1: act = SIG_IGN; break;
124 default: act = handle_signal; break;
126 oldact = signal(signo, act);
127 if (oldact == SIG_ERR) return -1;
129 if (oldact == (signal_handler) handle_signal)
131 else if (oldact == SIG_IGN)
137 /* Machine- and OS-dependent handling of bound check trap */
139 #if defined(TARGET_power) || (defined(TARGET_sparc) && defined(SYS_solaris))
140 DECLARE_SIGNAL_HANDLER(trap_handler)
142 #if defined(SYS_solaris)
143 if (info->si_code != ILL_ILLTRP) {
144 /* Deactivate our exception handler and return. */
145 struct sigaction act;
146 act.sa_handler = SIG_DFL;
148 sigemptyset(&act.sa_mask);
149 sigaction(sig, &act, NULL);
153 #if defined(SYS_rhapsody)
154 /* Unblock SIGTRAP */
157 sigaddset(&mask, SIGTRAP);
158 sigprocmask(SIG_UNBLOCK, &mask, NULL);
161 caml_exception_pointer = (char *) CONTEXT_EXCEPTION_POINTER;
162 caml_young_ptr = (char *) CONTEXT_YOUNG_PTR;
163 #if defined(SYS_rhapsody)
164 caml_bottom_of_stack = (char *) CONTEXT_SP;
165 caml_last_return_address = (uintnat) CONTEXT_PC;
167 caml_array_bound_error();
171 /* Machine- and OS-dependent handling of stack overflow */
173 #ifdef HAS_STACK_OVERFLOW_DETECTION
175 static char * system_stack_top;
176 static char sig_alt_stack[SIGSTKSZ];
178 DECLARE_SIGNAL_HANDLER(segv_handler)
181 struct sigaction act;
185 - faulting address is word-aligned
186 - faulting address is within the stack
187 - we are in Caml code */
188 fault_addr = CONTEXT_FAULTING_ADDRESS;
189 if (((uintnat) fault_addr & (sizeof(intnat) - 1)) == 0
190 && getrlimit(RLIMIT_STACK, &limit) == 0
191 && fault_addr < system_stack_top
192 && fault_addr >= system_stack_top - limit.rlim_cur - 0x2000
194 && Is_in_code_area(CONTEXT_PC)
197 /* Turn this into a Stack_overflow exception */
198 #if defined(CONTEXT_YOUNG_PTR) && defined(CONTEXT_EXCEPTION_POINTER)
199 caml_exception_pointer = (char *) CONTEXT_EXCEPTION_POINTER;
200 caml_young_ptr = (char *) CONTEXT_YOUNG_PTR;
202 caml_raise_stack_overflow();
204 /* Otherwise, deactivate our exception handler and return,
205 causing fatal signal to be generated at point of error. */
206 act.sa_handler = SIG_DFL;
208 sigemptyset(&act.sa_mask);
209 sigaction(SIGSEGV, &act, NULL);
214 /* Initialization of signal stuff */
216 void caml_init_signals(void)
218 /* Bound-check trap handling */
219 #if defined(TARGET_sparc) && defined(SYS_solaris)
220 { struct sigaction act;
221 sigemptyset(&act.sa_mask);
222 SET_SIGACT(act, trap_handler);
223 act.sa_flags |= SA_NODEFER;
224 sigaction(SIGILL, &act, NULL);
228 #if defined(TARGET_power)
229 { struct sigaction act;
230 sigemptyset(&act.sa_mask);
231 SET_SIGACT(act, trap_handler);
232 #if !defined(SYS_rhapsody)
233 act.sa_flags |= SA_NODEFER;
235 sigaction(SIGTRAP, &act, NULL);
239 /* Stack overflow handling */
240 #ifdef HAS_STACK_OVERFLOW_DETECTION
243 struct sigaction act;
244 stk.ss_sp = sig_alt_stack;
245 stk.ss_size = SIGSTKSZ;
247 SET_SIGACT(act, segv_handler);
248 act.sa_flags |= SA_ONSTACK | SA_NODEFER;
249 sigemptyset(&act.sa_mask);
250 system_stack_top = (char *) &act;
251 if (sigaltstack(&stk, NULL) == 0) { sigaction(SIGSEGV, &act, NULL); }
254 #if defined(_WIN32) && !defined(_WIN64)
255 caml_win32_overflow_detection();