Avoid asserts in sdb if a single step operation is started immediately after the...
[mono.git] / mono / mini / mini-posix.c
index e6068657758a031c7388d0bdeb0ae065b9dafed9..674117f311c63231bacfdd6487b1e32285614ff8 100644 (file)
@@ -6,6 +6,7 @@
  *
  * Copyright 2001-2003 Ximian, Inc.
  * Copyright 2003-2008 Ximian, Inc.
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  *
  * See LICENSE for licensing information.
  */
@@ -21,6 +22,9 @@
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#endif
 
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/loader.h>
@@ -47,7 +51,7 @@
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
-#include <mono/utils/mono-logger.h>
+#include <mono/utils/mono-logger-internal.h>
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/dtrace.h>
 
 #include <ctype.h>
 #include "trace.h"
 #include "version.h"
+#include "debugger-agent.h"
 
 #include "jit-icalls.h"
 
+#if defined(__native_client__)
+
+void
+mono_runtime_setup_stat_profiler (void)
+{
+       printf("WARNING: mono_runtime_setup_stat_profiler() called!\n");
+}
+
+
+void
+mono_runtime_shutdown_stat_profiler (void)
+{
+}
+
+
+gboolean
+SIG_HANDLER_SIGNATURE (mono_chain_signal)
+{
+       return FALSE;
+}
+
+void
+mono_runtime_install_handlers (void)
+{
+}
+
+void
+mono_runtime_shutdown_handlers (void)
+{
+}
+
+void
+mono_runtime_cleanup_handlers (void)
+{
+}
+
+
+
+#else
+
 static GHashTable *mono_saved_signal_handlers = NULL;
 
 static gpointer
@@ -124,7 +169,7 @@ SIG_HANDLER_SIGNATURE (mono_chain_signal)
 
        GET_CONTEXT;
 
-       if (saved_handler) {
+       if (saved_handler && saved_handler->sa_handler) {
                if (!(saved_handler->sa_flags & SA_SIGINFO)) {
                        saved_handler->sa_handler (signal);
                } else {
@@ -140,10 +185,11 @@ SIG_HANDLER_SIGNATURE (mono_chain_signal)
 static void
 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
 {
-       MonoJitInfo *ji;
+       MonoJitInfo *ji = NULL;
        GET_CONTEXT;
 
-       ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+       if (mono_thread_internal_current ())
+               ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
        if (!ji) {
         if (mono_chain_signal (SIG_HANDLER_PARAMS))
                        return;
@@ -156,7 +202,7 @@ SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
 {
        gboolean running_managed;
        MonoException *exc;
-       MonoThread *thread = mono_thread_current ();
+       MonoInternalThread *thread = mono_thread_internal_current ();
        MonoDomain *domain = mono_domain_get ();
        void *ji;
        
@@ -174,19 +220,48 @@ SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
        }
 
        /*
-        * FIXME:
         * This is an async signal, so the code below must not call anything which
         * is not async safe. That includes the pthread locking functions. If we
         * know that we interrupted managed code, then locking is safe.
         */
-       ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
-       running_managed = ji != NULL;
-       
+       /*
+        * On OpenBSD, ctx can be NULL if we are interrupting poll ().
+        */
+       if (ctx) {
+               ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+               running_managed = ji != NULL;
+
+               if (mono_debugger_agent_thread_interrupt (ctx, ji))
+                       return;
+       } else {
+               running_managed = FALSE;
+       }
+
+       /* We can't do handler block checking from metadata since it requires doing
+        * a stack walk with context.
+        *
+        * FIXME add full-aot support.
+        */
+#ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
+       if (!mono_aot_only && ctx) {
+               MonoThreadUnwindState unwind_state;
+               if (mono_thread_state_init_from_sigctx (&unwind_state, ctx)) {
+                       if (mono_install_handler_block_guard (&unwind_state)) {
+#ifndef HOST_WIN32
+                               /*Clear current thread from been wapi interrupted otherwise things can go south*/
+                               wapi_clear_interruption ();
+#endif
+                               return;
+                       }
+               }
+       }
+#endif
+
        exc = mono_thread_request_interruption (running_managed); 
        if (!exc)
                return;
 
-       mono_arch_handle_exception (ctx, exc, FALSE);
+       mono_arch_handle_exception (ctx, exc);
 }
 
 #if defined(__i386__) || defined(__x86_64__)
@@ -221,28 +296,27 @@ static void
 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
 {
        int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
+       MonoProfilerCallChainStrategy call_chain_strategy = mono_profiler_stat_get_call_chain_strategy ();
        GET_CONTEXT;
        
        if (call_chain_depth == 0) {
                mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
        } else {
-               MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+               MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
                int current_frame_index = 1;
                MonoContext mono_context;
-#if FULL_STAT_PROFILER_BACKTRACE
-               guchar *current_frame;
-               guchar *stack_bottom;
-               guchar *stack_top;
-#else
-               MonoDomain *domain;
-#endif
                guchar *ips [call_chain_depth + 1];
 
                mono_arch_sigctx_to_monoctx (ctx, &mono_context);
                ips [0] = MONO_CONTEXT_GET_IP (&mono_context);
                
                if (jit_tls != NULL) {
+                       if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_NATIVE) {
 #if FULL_STAT_PROFILER_BACKTRACE
+                       guchar *current_frame;
+                       guchar *stack_bottom;
+                       guchar *stack_top;
+                       
                        stack_bottom = jit_tls->end_of_stack;
                        stack_top = MONO_CONTEXT_GET_SP (&mono_context);
                        current_frame = MONO_CONTEXT_GET_BP (&mono_context);
@@ -256,24 +330,37 @@ SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
                                current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
                        }
 #else
-                       domain = mono_domain_get ();
-                       if (domain != NULL) {
-                               MonoLMF *lmf = NULL;
-                               MonoJitInfo *ji;
-                               MonoJitInfo res;
-                               MonoContext new_mono_context;
-                               int native_offset;
-                               ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
-                                               &new_mono_context, NULL, &lmf, &native_offset, NULL);
-                               while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
-                                       ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
-                                       current_frame_index ++;
-                                       mono_context = new_mono_context;
+                               call_chain_strategy = MONO_PROFILER_CALL_CHAIN_GLIBC;
+#endif
+                       }
+                       
+                       if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_GLIBC) {
+#if GLIBC_PROFILER_BACKTRACE
+                               current_frame_index = backtrace ((void**) & ips [1], call_chain_depth);
+#else
+                               call_chain_strategy = MONO_PROFILER_CALL_CHAIN_MANAGED;
+#endif
+                       }
+
+                       if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_MANAGED) {
+                               MonoDomain *domain = mono_domain_get ();
+                               if (domain != NULL) {
+                                       MonoLMF *lmf = NULL;
+                                       MonoJitInfo *ji;
+                                       MonoJitInfo res;
+                                       MonoContext new_mono_context;
+                                       int native_offset;
                                        ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
                                                        &new_mono_context, NULL, &lmf, &native_offset, NULL);
+                                       while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
+                                               ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
+                                               current_frame_index ++;
+                                               mono_context = new_mono_context;
+                                               ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
+                                                               &new_mono_context, NULL, &lmf, &native_offset, NULL);
+                                       }
                                }
                        }
-#endif
                }
                
                mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
@@ -296,17 +383,21 @@ SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
        if (res)
                return;
 
-       printf ("Full thread dump:\n");
+       if (mono_thread_info_new_interrupt_enabled ()) {
+               mono_threads_request_thread_dump ();
+       } else {
+               printf ("Full thread dump:\n");
 
-       mono_threads_request_thread_dump ();
+               mono_threads_request_thread_dump ();
 
-       /*
-        * print_thread_dump () skips the current thread, since sending a signal
-        * to it would invoke the signal handler below the sigquit signal handler,
-        * and signal handlers don't create an lmf, so the stack walk could not
-        * be performed.
-        */
-       mono_print_thread_dump (ctx);
+               /*
+                * print_thread_dump () skips the current thread, since sending a signal
+                * to it would invoke the signal handler below the sigquit signal handler,
+                * and signal handlers don't create an lmf, so the stack walk could not
+                * be performed.
+                */
+               mono_print_thread_dump (ctx);
+       }
 
        mono_chain_signal (SIG_HANDLER_PARAMS);
 }
@@ -332,9 +423,33 @@ add_signal_handler (int signo, gpointer handler)
        sigemptyset (&sa.sa_mask);
        sa.sa_flags = SA_SIGINFO;
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
-       if (signo == SIGSEGV)
+
+/*Apple likes to deliver SIGBUS for *0 */
+#ifdef __APPLE__
+       if (signo == SIGSEGV || signo == SIGBUS) {
+#else
+       if (signo == SIGSEGV) {
+#endif
                sa.sa_flags |= SA_ONSTACK;
+
+               /* 
+                * libgc will crash when trying to do stack marking for threads which are on
+                * an altstack, so delay the suspend signal after the signal handler has
+                * executed.
+                */
+               if (mono_gc_get_suspend_signal () != -1)
+                       sigaddset (&sa.sa_mask, mono_gc_get_suspend_signal ());
+       }
 #endif
+       if (signo == SIGSEGV) {
+               /* 
+                * Delay abort signals while handling SIGSEGVs since they could go unnoticed.
+                */
+               sigset_t block_mask;
+     
+               sigemptyset (&block_mask);
+               sigaddset (&sa.sa_mask, mono_thread_get_abort_signal ());
+       }
 #else
        sa.sa_handler = handler;
        sigemptyset (&sa.sa_mask);
@@ -385,7 +500,8 @@ mono_runtime_posix_install_handlers (void)
        if (mono_jit_trace_calls != NULL)
                add_signal_handler (SIGUSR2, sigusr2_signal_handler);
 
-       add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
+       if (!mono_thread_info_new_interrupt_enabled ())
+               add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
        /* it seems to have become a common bug for some programs that run as parents
         * of many processes to block signal delivery for real time signals.
         * We try to detect and work around their breakage here.
@@ -522,3 +638,54 @@ mono_runtime_setup_stat_profiler (void)
        add_signal_handler (SIGPROF, sigprof_signal_handler);
 #endif
 }
+
+#if !defined(__APPLE__)
+pid_t
+mono_runtime_syscall_fork ()
+{
+#if defined(SYS_fork)
+       return (pid_t) syscall (SYS_fork);
+#else
+       g_assert_not_reached ();
+       return 0;
+#endif
+}
+
+gboolean
+mono_gdb_render_native_backtraces ()
+{
+       const char *argv [9];
+       char buf1 [128];
+
+       argv [0] = g_find_program_in_path ("gdb");
+       if (argv [0] == NULL) {
+               return FALSE;
+       }
+
+       argv [1] = "-ex";
+       sprintf (buf1, "attach %ld", (long)getpid ());
+       argv [2] = buf1;
+       argv [3] = "--ex";
+       argv [4] = "info threads";
+       argv [5] = "--ex";
+       argv [6] = "thread apply all bt";
+       argv [7] = "--batch";
+       argv [8] = 0;
+
+       execv (argv [0], (char**)argv);
+
+       return TRUE;
+}
+#endif
+#endif /* __native_client__ */
+
+#if !defined (__MACH__)
+
+gboolean
+mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoNativeThreadId thread_id, MonoNativeThreadHandle thread_handle)
+{
+       g_error ("Posix systems don't support mono_thread_state_init_from_handle");
+       return FALSE;
+}
+
+#endif