*
* Copyright 2001-2003 Ximian, Inc.
* Copyright 2003-2008 Ximian, Inc.
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*
* See LICENSE for licensing information.
*/
#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 <mono/utils/mono-signal-handler.h>
#include "mini.h"
#include <string.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)
+{
+}
+
+pid_t
+mono_runtime_syscall_fork (void)
+{
+ g_assert_not_reached();
+ return 0;
+}
+
+void
+mono_gdb_render_native_backtraces (pid_t crashed_pid)
+{
+}
+
+#else
+
static GHashTable *mono_saved_signal_handlers = NULL;
static gpointer
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 {
return FALSE;
}
-static void
-SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
+SIG_HANDLER_FUNC (static, 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;
}
}
-static void
-SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
+SIG_HANDLER_FUNC (static, 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;
GET_CONTEXT;
- if (!thread || !domain)
+ if (!thread || !domain) {
/* The thread might not have started up yet */
/* FIXME: Specify the synchronization with start_wrapper () in threads.c */
+ mono_debugger_agent_thread_interrupt (ctx, NULL);
return;
+ }
+
+ if (thread->ignore_next_signal) {
+ thread->ignore_next_signal = FALSE;
+ return;
+ }
if (thread->thread_dump_requested) {
thread->thread_dump_requested = FALSE;
}
/*
- * 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__)
#define FULL_STAT_PROFILER_BACKTRACE 1
#define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
#if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
-static void
-SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
+SIG_HANDLER_FUNC (static, sigprof_signal_handler)
{
if (mono_chain_signal (SIG_HANDLER_PARAMS))
return;
#else
-static void
-SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
+SIG_HANDLER_FUNC (static, 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);
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);
#endif
-static void
-SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
+SIG_HANDLER_FUNC (static, sigquit_signal_handler)
{
gboolean res;
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);
}
-static void
-SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
+SIG_HANDLER_FUNC (static, sigusr2_signal_handler)
{
gboolean enabled = mono_trace_is_enabled ();
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);
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.
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 ()
+void
+mono_gdb_render_native_backtraces (pid_t crashed_pid)
{
const char *argv [9];
+ char template [] = "/tmp/mono-lldb-commands.XXXXXX";
char buf1 [128];
+ FILE *commands;
+ gboolean using_lldb = FALSE;
argv [0] = g_find_program_in_path ("gdb");
if (argv [0] == NULL) {
- return FALSE;
+ argv [0] = g_find_program_in_path ("lldb");
+ using_lldb = TRUE;
}
- 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;
+ if (argv [0] == NULL)
+ return;
+
+ if (using_lldb) {
+ if (mkstemp (template) == -1)
+ return;
+
+ commands = fopen (template, "w");
+
+ fprintf (commands, "process attach --pid %ld\n", (long) crashed_pid);
+ fprintf (commands, "script lldb.debugger.HandleCommand (\"thread list\")\n");
+ fprintf (commands, "script lldb.debugger.HandleCommand (\"thread backtrace all\")\n");
+ fprintf (commands, "detach\n");
+ fprintf (commands, "quit\n");
+
+ fflush (commands);
+ fclose (commands);
+
+ argv [1] = "--source";
+ argv [2] = template;
+ argv [3] = 0;
+ } else {
+ argv [1] = "-ex";
+ sprintf (buf1, "attach %ld", (long) crashed_pid);
+ 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;
+ if (using_lldb)
+ unlink (template);
+}
+#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