2009-07-01 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-posix.c
1 /*
2  * mini-posix.c: POSIX signal handling support for Mono.
3  *
4  * Authors:
5  *   Mono Team (mono-list@lists.ximian.com)
6  *
7  * Copyright 2001-2003 Ximian, Inc.
8  * Copyright 2003-2008 Ximian, Inc.
9  *
10  * See LICENSE for licensing information.
11  */
12 #include <config.h>
13 #include <signal.h>
14 #ifdef HAVE_ALLOCA_H
15 #include <alloca.h>
16 #endif
17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20 #include <math.h>
21 #ifdef HAVE_SYS_TIME_H
22 #include <sys/time.h>
23 #endif
24 #ifdef HAVE_SYS_SYSCALL_H
25 #include <sys/syscall.h>
26 #endif
27
28 #include <mono/metadata/assembly.h>
29 #include <mono/metadata/loader.h>
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/class.h>
32 #include <mono/metadata/object.h>
33 #include <mono/metadata/tokentype.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/appdomain.h>
37 #include <mono/metadata/debug-helpers.h>
38 #include <mono/io-layer/io-layer.h>
39 #include "mono/metadata/profiler.h"
40 #include <mono/metadata/profiler-private.h>
41 #include <mono/metadata/mono-config.h>
42 #include <mono/metadata/environment.h>
43 #include <mono/metadata/mono-debug.h>
44 #include <mono/metadata/gc-internal.h>
45 #include <mono/metadata/threads-types.h>
46 #include <mono/metadata/verify.h>
47 #include <mono/metadata/verify-internals.h>
48 #include <mono/metadata/mempool-internals.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/utils/mono-math.h>
51 #include <mono/utils/mono-compiler.h>
52 #include <mono/utils/mono-counters.h>
53 #include <mono/utils/mono-logger.h>
54 #include <mono/utils/mono-mmap.h>
55 #include <mono/utils/dtrace.h>
56
57 #include "mini.h"
58 #include <string.h>
59 #include <ctype.h>
60 #include "trace.h"
61 #include "version.h"
62 #include "debugger-agent.h"
63
64 #include "jit-icalls.h"
65
66 static GHashTable *mono_saved_signal_handlers = NULL;
67
68 static gpointer
69 get_saved_signal_handler (int signo)
70 {
71         if (mono_saved_signal_handlers)
72                 /* The hash is only modified during startup, so no need for locking */
73                 return g_hash_table_lookup (mono_saved_signal_handlers, GINT_TO_POINTER (signo));
74         return NULL;
75 }
76
77 static void
78 save_old_signal_handler (int signo, struct sigaction *old_action)
79 {
80         struct sigaction *handler_to_save = g_malloc (sizeof (struct sigaction));
81
82         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_CONFIG,
83                                 "Saving old signal handler for signal %d.", signo);
84
85         if (! (old_action->sa_flags & SA_SIGINFO)) {
86                 handler_to_save->sa_handler = old_action->sa_handler;
87         } else {
88 #ifdef MONO_ARCH_USE_SIGACTION
89                 handler_to_save->sa_sigaction = old_action->sa_sigaction;
90 #endif /* MONO_ARCH_USE_SIGACTION */
91         }
92         handler_to_save->sa_mask = old_action->sa_mask;
93         handler_to_save->sa_flags = old_action->sa_flags;
94         
95         if (!mono_saved_signal_handlers)
96                 mono_saved_signal_handlers = g_hash_table_new (NULL, NULL);
97         g_hash_table_insert (mono_saved_signal_handlers, GINT_TO_POINTER (signo), handler_to_save);
98 }
99
100 static void
101 free_saved_sig_handler_func (gpointer key, gpointer value, gpointer user_data)
102 {
103         g_free (value);
104 }
105
106 static void
107 free_saved_signal_handlers (void)
108 {
109         if (mono_saved_signal_handlers) {
110                 g_hash_table_foreach (mono_saved_signal_handlers, free_saved_sig_handler_func, NULL);
111                 g_hash_table_destroy (mono_saved_signal_handlers);
112                 mono_saved_signal_handlers = NULL;
113         }
114 }
115
116 /*
117  * mono_chain_signal:
118  *
119  *   Call the original signal handler for the signal given by the arguments, which
120  * should be the same as for a signal handler. Returns TRUE if the original handler
121  * was called, false otherwise.
122  */
123 gboolean
124 SIG_HANDLER_SIGNATURE (mono_chain_signal)
125 {
126         int signal = _dummy;
127         struct sigaction *saved_handler = get_saved_signal_handler (signal);
128
129         GET_CONTEXT;
130
131         if (saved_handler) {
132                 if (!(saved_handler->sa_flags & SA_SIGINFO)) {
133                         saved_handler->sa_handler (signal);
134                 } else {
135 #ifdef MONO_ARCH_USE_SIGACTION
136                         saved_handler->sa_sigaction (signal, info, ctx);
137 #endif /* MONO_ARCH_USE_SIGACTION */
138                 }
139                 return TRUE;
140         }
141         return FALSE;
142 }
143
144 static void
145 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
146 {
147         MonoJitInfo *ji;
148         GET_CONTEXT;
149
150         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
151         if (!ji) {
152         if (mono_chain_signal (SIG_HANDLER_PARAMS))
153                         return;
154                 mono_handle_native_sigsegv (SIGABRT, ctx);
155         }
156 }
157
158 static void
159 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
160 {
161         gboolean running_managed;
162         MonoException *exc;
163         MonoInternalThread *thread = mono_thread_internal_current ();
164         MonoDomain *domain = mono_domain_get ();
165         void *ji;
166         
167         GET_CONTEXT;
168
169         if (!thread || !domain)
170                 /* The thread might not have started up yet */
171                 /* FIXME: Specify the synchronization with start_wrapper () in threads.c */
172                 return;
173
174         if (thread->thread_dump_requested) {
175                 thread->thread_dump_requested = FALSE;
176
177                 mono_print_thread_dump (ctx);
178         }
179
180         /*
181          * FIXME:
182          * This is an async signal, so the code below must not call anything which
183          * is not async safe. That includes the pthread locking functions. If we
184          * know that we interrupted managed code, then locking is safe.
185          */
186         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
187         running_managed = ji != NULL;
188
189         if (mono_debugger_agent_thread_interrupt (ji))
190                 return;
191         
192         exc = mono_thread_request_interruption (running_managed); 
193         if (!exc)
194                 return;
195
196         mono_arch_handle_exception (ctx, exc, FALSE);
197 }
198
199 #if defined(__i386__) || defined(__x86_64__)
200 #define FULL_STAT_PROFILER_BACKTRACE 1
201 #define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
202 #define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
203 #if MONO_ARCH_STACK_GROWS_UP
204 #define IS_BEFORE_ON_STACK <
205 #define IS_AFTER_ON_STACK >
206 #else
207 #define IS_BEFORE_ON_STACK >
208 #define IS_AFTER_ON_STACK <
209 #endif
210 #else
211 #define FULL_STAT_PROFILER_BACKTRACE 0
212 #endif
213
214 #if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
215
216 static void
217 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
218 {
219         if (mono_chain_signal (SIG_HANDLER_PARAMS))
220                 return;
221
222         NOT_IMPLEMENTED;
223 }
224
225 #else
226
227 static void
228 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
229 {
230         int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
231         MonoProfilerCallChainStrategy call_chain_strategy = mono_profiler_stat_get_call_chain_strategy ();
232         GET_CONTEXT;
233         
234         if (call_chain_depth == 0) {
235                 mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
236         } else {
237                 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
238                 int current_frame_index = 1;
239                 MonoContext mono_context;
240                 guchar *ips [call_chain_depth + 1];
241
242                 mono_arch_sigctx_to_monoctx (ctx, &mono_context);
243                 ips [0] = MONO_CONTEXT_GET_IP (&mono_context);
244                 
245                 if (jit_tls != NULL) {
246                         if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_NATIVE) {
247 #if FULL_STAT_PROFILER_BACKTRACE
248                         guchar *current_frame;
249                         guchar *stack_bottom;
250                         guchar *stack_top;
251                         
252                         stack_bottom = jit_tls->end_of_stack;
253                         stack_top = MONO_CONTEXT_GET_SP (&mono_context);
254                         current_frame = MONO_CONTEXT_GET_BP (&mono_context);
255                         
256                         while ((current_frame_index <= call_chain_depth) &&
257                                         (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) &&
258                                         ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) {
259                                 ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame);
260                                 current_frame_index ++;
261                                 stack_top = current_frame;
262                                 current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
263                         }
264 #else
265                                 call_chain_strategy = MONO_PROFILER_CALL_CHAIN_GLIBC;
266 #endif
267                         }
268                         
269                         if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_GLIBC) {
270 #if GLIBC_PROFILER_BACKTRACE
271                                 current_frame_index = backtrace ((void**) & ips [1], call_chain_depth);
272 #else
273                                 call_chain_strategy = MONO_PROFILER_CALL_CHAIN_MANAGED;
274 #endif
275                         }
276
277                         if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_MANAGED) {
278                                 MonoDomain *domain = mono_domain_get ();
279                                 if (domain != NULL) {
280                                         MonoLMF *lmf = NULL;
281                                         MonoJitInfo *ji;
282                                         MonoJitInfo res;
283                                         MonoContext new_mono_context;
284                                         int native_offset;
285                                         ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
286                                                         &new_mono_context, NULL, &lmf, &native_offset, NULL);
287                                         while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
288                                                 ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
289                                                 current_frame_index ++;
290                                                 mono_context = new_mono_context;
291                                                 ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
292                                                                 &new_mono_context, NULL, &lmf, &native_offset, NULL);
293                                         }
294                                 }
295                         }
296                 }
297                 
298                 mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
299         }
300
301         mono_chain_signal (SIG_HANDLER_PARAMS);
302 }
303
304 #endif
305
306 static void
307 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
308 {
309         gboolean res;
310
311         GET_CONTEXT;
312
313         /* We use this signal to start the attach agent too */
314         res = mono_attach_start ();
315         if (res)
316                 return;
317
318         printf ("Full thread dump:\n");
319
320         mono_threads_request_thread_dump ();
321
322         /*
323          * print_thread_dump () skips the current thread, since sending a signal
324          * to it would invoke the signal handler below the sigquit signal handler,
325          * and signal handlers don't create an lmf, so the stack walk could not
326          * be performed.
327          */
328         mono_print_thread_dump (ctx);
329
330         mono_chain_signal (SIG_HANDLER_PARAMS);
331 }
332
333 static void
334 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
335 {
336         gboolean enabled = mono_trace_is_enabled ();
337
338         mono_trace_enable (!enabled);
339
340         mono_chain_signal (SIG_HANDLER_PARAMS);
341 }
342
343 static void
344 add_signal_handler (int signo, gpointer handler)
345 {
346         struct sigaction sa;
347         struct sigaction previous_sa;
348
349 #ifdef MONO_ARCH_USE_SIGACTION
350         sa.sa_sigaction = handler;
351         sigemptyset (&sa.sa_mask);
352         sa.sa_flags = SA_SIGINFO;
353 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
354         if (signo == SIGSEGV) {
355                 sa.sa_flags |= SA_ONSTACK;
356
357                 /* 
358                  * libgc will crash when trying to do stack marking for threads which are on
359                  * an altstack, so delay the suspend signal after the signal handler has
360                  * executed.
361                  */
362                 if (mono_gc_get_suspend_signal () != -1)
363                         sigaddset (&sa.sa_mask, mono_gc_get_suspend_signal ());
364         }
365 #endif
366         if (signo == SIGSEGV) {
367                 /* 
368                  * Delay abort signals while handling SIGSEGVs since they could go unnoticed.
369                  */
370                 sigset_t block_mask;
371      
372                 sigemptyset (&block_mask);
373                 sigaddset (&sa.sa_mask, mono_thread_get_abort_signal ());
374         }
375 #else
376         sa.sa_handler = handler;
377         sigemptyset (&sa.sa_mask);
378         sa.sa_flags = 0;
379 #endif
380         g_assert (sigaction (signo, &sa, &previous_sa) != -1);
381
382         /* if there was already a handler in place for this signal, store it */
383         if (! (previous_sa.sa_flags & SA_SIGINFO) &&
384                         (SIG_DFL == previous_sa.sa_handler)) { 
385                 /* it there is no sa_sigaction function and the sa_handler is default, we can safely ignore this */
386         } else {
387                 if (mono_do_signal_chaining)
388                         save_old_signal_handler (signo, &previous_sa);
389         }
390 }
391
392 static void
393 remove_signal_handler (int signo)
394 {
395         struct sigaction sa;
396         struct sigaction *saved_action = get_saved_signal_handler (signo);
397
398         if (!saved_action) {
399                 sa.sa_handler = SIG_DFL;
400                 sigemptyset (&sa.sa_mask);
401                 sa.sa_flags = 0;
402
403                 sigaction (signo, &sa, NULL);
404         } else {
405                 g_assert (sigaction (signo, saved_action, NULL) != -1);
406         }
407 }
408
409 void
410 mono_runtime_posix_install_handlers (void)
411 {
412
413         sigset_t signal_set;
414
415         if (mini_get_debug_options ()->handle_sigint)
416                 add_signal_handler (SIGINT, mono_sigint_signal_handler);
417
418         add_signal_handler (SIGFPE, mono_sigfpe_signal_handler);
419         add_signal_handler (SIGQUIT, sigquit_signal_handler);
420         add_signal_handler (SIGILL, mono_sigill_signal_handler);
421         add_signal_handler (SIGBUS, mono_sigsegv_signal_handler);
422         if (mono_jit_trace_calls != NULL)
423                 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
424
425         add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
426         /* it seems to have become a common bug for some programs that run as parents
427          * of many processes to block signal delivery for real time signals.
428          * We try to detect and work around their breakage here.
429          */
430         sigemptyset (&signal_set);
431         sigaddset (&signal_set, mono_thread_get_abort_signal ());
432         sigprocmask (SIG_UNBLOCK, &signal_set, NULL);
433
434         signal (SIGPIPE, SIG_IGN);
435
436         add_signal_handler (SIGABRT, sigabrt_signal_handler);
437
438         /* catch SIGSEGV */
439         add_signal_handler (SIGSEGV, mono_sigsegv_signal_handler);
440 }
441
442 #ifndef PLATFORM_MACOSX
443 void
444 mono_runtime_install_handlers (void)
445 {
446         mono_runtime_posix_install_handlers ();
447 }
448 #endif
449
450 void
451 mono_runtime_cleanup_handlers (void)
452 {
453         if (mini_get_debug_options ()->handle_sigint)
454                 remove_signal_handler (SIGINT);
455
456         remove_signal_handler (SIGFPE);
457         remove_signal_handler (SIGQUIT);
458         remove_signal_handler (SIGILL);
459         remove_signal_handler (SIGBUS);
460         if (mono_jit_trace_calls != NULL)
461                 remove_signal_handler (SIGUSR2);
462
463         remove_signal_handler (mono_thread_get_abort_signal ());
464
465         remove_signal_handler (SIGABRT);
466
467         remove_signal_handler (SIGSEGV);
468
469         free_saved_signal_handlers ();
470 }
471
472 #ifdef HAVE_LINUX_RTC_H
473 #include <linux/rtc.h>
474 #include <sys/ioctl.h>
475 #include <fcntl.h>
476 static int rtc_fd = -1;
477
478 static int
479 enable_rtc_timer (gboolean enable)
480 {
481         int flags;
482         flags = fcntl (rtc_fd, F_GETFL);
483         if (flags < 0) {
484                 perror ("getflags");
485                 return 0;
486         }
487         if (enable)
488                 flags |= FASYNC;
489         else
490                 flags &= ~FASYNC;
491         if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
492                 perror ("setflags");
493                 return 0;
494         }
495         return 1;
496 }
497 #endif
498
499 void
500 mono_runtime_shutdown_stat_profiler (void)
501 {
502 #ifdef HAVE_LINUX_RTC_H
503         if (rtc_fd >= 0)
504                 enable_rtc_timer (FALSE);
505 #endif
506 }
507
508 void
509 mono_runtime_setup_stat_profiler (void)
510 {
511 #ifdef ITIMER_PROF
512         struct itimerval itval;
513         static int inited = 0;
514 #ifdef HAVE_LINUX_RTC_H
515         const char *rtc_freq;
516         if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
517                 int freq = 0;
518                 inited = 1;
519                 if (*rtc_freq)
520                         freq = atoi (rtc_freq);
521                 if (!freq)
522                         freq = 1024;
523                 rtc_fd = open ("/dev/rtc", O_RDONLY);
524                 if (rtc_fd == -1) {
525                         perror ("open /dev/rtc");
526                         return;
527                 }
528                 add_signal_handler (SIGPROF, sigprof_signal_handler);
529                 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
530                         perror ("set rtc freq");
531                         return;
532                 }
533                 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
534                         perror ("start rtc");
535                         return;
536                 }
537                 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
538                         perror ("setsig");
539                         return;
540                 }
541                 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
542                         perror ("setown");
543                         return;
544                 }
545                 enable_rtc_timer (TRUE);
546                 return;
547         }
548         if (rtc_fd >= 0)
549                 return;
550 #endif
551
552         itval.it_interval.tv_usec = 999;
553         itval.it_interval.tv_sec = 0;
554         itval.it_value = itval.it_interval;
555         setitimer (ITIMER_PROF, &itval, NULL);
556         if (inited)
557                 return;
558         inited = 1;
559         add_signal_handler (SIGPROF, sigprof_signal_handler);
560 #endif
561 }
562
563 #if !defined(__APPLE__)
564 pid_t
565 mono_runtime_syscall_fork ()
566 {
567 #if defined(SYS_fork)
568         return (pid_t) syscall (SYS_fork);
569 #else
570         g_assert_not_reached ();
571 #endif
572 }
573
574 gboolean
575 mono_gdb_render_native_backtraces ()
576 {
577         const char *argv [9];
578         char buf1 [128];
579
580         argv [0] = g_find_program_in_path ("gdb");
581         if (argv [0] == NULL) {
582                 return FALSE;
583         }
584
585         argv [1] = "-ex";
586         sprintf (buf1, "attach %ld", (long)getpid ());
587         argv [2] = buf1;
588         argv [3] = "--ex";
589         argv [4] = "info threads";
590         argv [5] = "--ex";
591         argv [6] = "thread apply all bt";
592         argv [7] = "--batch";
593         argv [8] = 0;
594
595         execv (argv [0], (char**)argv);
596
597         return TRUE;
598 }
599 #endif