* Mono Team (mono-list@lists.ximian.com)
*
* Copyright 2001-2003 Ximian, Inc.
- * Copyright 2003-2008 Ximian, Inc.
+ * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*
* See LICENSE for licensing information.
*/
#include <sys/time.h>
#endif
-#ifdef HAVE_VALGRIND_MEMCHECK_H
-#include <valgrind/memcheck.h>
-#endif
-
#include <mono/metadata/assembly.h>
#include <mono/metadata/loader.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/mono-debug.h>
-#include <mono/metadata/gc-internal.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/verify.h>
#include <mono/metadata/verify-internals.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/attach.h>
+#include <mono/metadata/gc-internal.h>
#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 <mach/exception.h>
#include <mach/task.h>
#include <pthread.h>
+#include <dlfcn.h>
+#include <AvailabilityMacros.h>
+
+#if defined (TARGET_OSX) && (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_5)
+#define NEEDS_EXCEPTION_THREAD
+#endif
+
+#ifdef NEEDS_EXCEPTION_THREAD
/*
* This code disables the CrashReporter of MacOS X by installing
/* The exception port */
static mach_port_t mach_exception_port = VM_MAP_NULL;
+kern_return_t
+catch_exception_raise (
+ mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t code_count);
+
/*
* Implicitly called by exc_server. Must be public.
*
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
- g_assert (result == MACH_MSG_SUCCESS);
+ /*
+ If we try to abort the thread while delivering an exception. The port will be gone since the kernel
+ setup a send once port to deliver the resume message and thread_abort will consume it.
+ */
+ g_assert (result == MACH_MSG_SUCCESS || result == MACH_SEND_INVALID_DEST);
}
return NULL;
}
static void
-macosx_register_exception_handler ()
+macosx_register_exception_handler (void)
{
mach_port_t task;
pthread_attr_t attr;
mach_exception_port,
EXCEPTION_DEFAULT,
MACHINE_THREAD_STATE) == KERN_SUCCESS);
+
+ mono_gc_register_mach_exception_thread (thread);
}
+#endif
+
+/* This is #define'd by Boehm GC to _GC_dlopen. */
+#undef dlopen
+
+void* dlopen(const char* path, int mode);
+
void
mono_runtime_install_handlers (void)
{
+#ifdef NEEDS_EXCEPTION_THREAD
macosx_register_exception_handler ();
+#endif
mono_runtime_posix_install_handlers ();
+
+ /* Snow Leopard has a horrible bug: http://openradar.appspot.com/7209349
+ * This causes obscure SIGTRAP's for any application that comes across this built on
+ * Snow Leopard. This is a horrible hack to ensure that the private __CFInitialize
+ * is run on the main thread, so that we don't get SIGTRAPs later
+ */
+#if defined (__APPLE__) && (defined (__i386__) || defined (__x86_64__))
+ {
+ void *handle = dlopen ("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", RTLD_LAZY);
+ if (handle == NULL)
+ return;
+
+ dlclose (handle);
+ }
+#endif
+}
+
+pid_t
+mono_runtime_syscall_fork ()
+{
+ return (pid_t) fork ();
+}
+
+void
+mono_gdb_render_native_backtraces (pid_t crashed_pid)
+{
+ const char *argv [5];
+ char template [] = "/tmp/mono-gdb-commands.XXXXXX";
+ FILE *commands;
+ gboolean using_lldb = FALSE;
+
+ argv [0] = g_find_program_in_path ("gdb");
+ if (!argv [0]) {
+ argv [0] = g_find_program_in_path ("lldb");
+ using_lldb = TRUE;
+ }
+
+ if (argv [0] == NULL)
+ return;
+
+ if (mkstemp (template) == -1)
+ return;
+
+ commands = fopen (template, "w");
+ if (using_lldb) {
+ 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");
+ argv [1] = "--source";
+ argv [2] = template;
+ argv [3] = 0;
+
+ } else {
+ fprintf (commands, "attach %ld\n", (long) crashed_pid);
+ fprintf (commands, "info threads\n");
+ fprintf (commands, "thread apply all bt\n");
+ argv [1] = "-batch";
+ argv [2] = "-x";
+ argv [3] = template;
+ argv [4] = 0;
+ }
+ fflush (commands);
+ fclose (commands);
+
+ execv (argv [0], (char**)argv);
+ unlink (template);
+}
+
+gboolean
+mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoNativeThreadId thread_id, MonoNativeThreadHandle thread_handle)
+{
+ kern_return_t ret;
+ mach_msg_type_number_t num_state;
+ thread_state_t state;
+ ucontext_t ctx;
+ mcontext_t mctx;
+ MonoJitTlsData *jit_tls;
+ void *domain;
+ MonoLMF *lmf;
+ MonoThreadInfo *info;
+
+ /*Zero enough state to make sure the caller doesn't confuse itself*/
+ tctx->valid = FALSE;
+ tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = NULL;
+ tctx->unwind_data [MONO_UNWIND_DATA_LMF] = NULL;
+ tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL;
+
+ state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ());
+ mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ());
+
+ ret = mono_mach_arch_get_thread_state (thread_handle, state, &num_state);
+ if (ret != KERN_SUCCESS)
+ return FALSE;
+
+ mono_mach_arch_thread_state_to_mcontext (state, mctx);
+ ctx.uc_mcontext = mctx;
+
+ mono_sigctx_to_monoctx (&ctx, &tctx->ctx);
+
+ info = mono_thread_info_lookup (thread_id);
+
+ if (info) {
+ /* mono_set_jit_tls () sets this */
+ jit_tls = mono_thread_info_tls_get (info, TLS_KEY_JIT_TLS);
+ /* SET_APPDOMAIN () sets this */
+ domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
+ } else {
+ jit_tls = NULL;
+ domain = NULL;
+ }
+
+ /*Thread already started to cleanup, can no longer capture unwind state*/
+ if (!jit_tls || !domain)
+ return FALSE;
+
+ /*
+ * The current LMF address is kept in a separate TLS variable, and its hard to read its value without
+ * arch-specific code. But the address of the TLS variable is stored in another TLS variable which
+ * can be accessed through MonoThreadInfo.
+ */
+ lmf = NULL;
+ if (info) {
+ gpointer *addr;
+
+ /* mono_set_lmf_addr () sets this */
+ addr = mono_thread_info_tls_get (info, TLS_KEY_LMF_ADDR);
+ if (addr)
+ lmf = *addr;
+ }
+
+ tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain;
+ tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
+ tctx->unwind_data [MONO_UNWIND_DATA_LMF] = lmf;
+ tctx->valid = TRUE;
+
+ return TRUE;
}