Example #1
0
/**
 * mono_arch_handle_exception:
 *
 * @ctx: saved processor state
 * @obj: the exception object
 */
gboolean
mono_arch_handle_exception (void *sigctx, gpointer obj)
{
#if defined(MONO_ARCH_USE_SIGACTION)
	MonoContext mctx;

	/*
	 * Handling the exception in the signal handler is problematic, since the original
	 * signal is disabled, and we could run arbitrary code though the debugger. So
	 * resume into the normal stack and do most work there if possible.
	 */
	MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);

	/* Pass the ctx parameter in TLS */
	mono_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);

	mctx = jit_tls->ex_ctx;
	mono_arch_setup_async_callback (&mctx, handle_signal_exception, obj);
	mono_monoctx_to_sigctx (&mctx, sigctx);

	return TRUE;
#else
	MonoContext mctx;

	mono_sigctx_to_monoctx (sigctx, &mctx);

	mono_handle_exception (&mctx, obj);

	mono_monoctx_to_sigctx (&mctx, sigctx);

	return TRUE;
#endif
}
Example #2
0
/*
 * This is the function called from the signal handler
 */
gboolean
mono_arch_handle_exception (void *ctx, gpointer obj)
{
#if defined(MONO_CROSS_COMPILE) || !defined(MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX)
	g_assert_not_reached ();
#elif defined(MONO_ARCH_USE_SIGACTION)
	arm_ucontext *sigctx = ctx;
	/*
	 * Handling the exception in the signal handler is problematic, since the original
	 * signal is disabled, and we could run arbitrary code though the debugger. So
	 * resume into the normal stack and do most work there if possible.
	 */
	MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
	guint64 sp = UCONTEXT_REG_SP (sigctx);

	/* Pass the ctx parameter in TLS */
	mono_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);
	/* The others in registers */
	UCONTEXT_REG_R0 (sigctx) = (gsize)obj;

	/* Allocate a stack frame */
	sp -= 16;
	UCONTEXT_REG_SP (sigctx) = sp;

	UCONTEXT_REG_PC (sigctx) = (gsize)get_handle_signal_exception_addr ();
#ifdef UCONTEXT_REG_CPSR
	if ((gsize)UCONTEXT_REG_PC (sigctx) & 1)
		/* Transition to thumb */
		UCONTEXT_REG_CPSR (sigctx) |= (1 << 5);
	else
		/* Transition to ARM */
		UCONTEXT_REG_CPSR (sigctx) &= ~(1 << 5);
#endif

	return TRUE;
#else
	MonoContext mctx;
	gboolean result;

	mono_sigctx_to_monoctx (ctx, &mctx);

	result = mono_handle_exception (&mctx, obj);
	/* restore the context so that returning from the signal handler will invoke
	 * the catch clause 
	 */
	mono_monoctx_to_sigctx (&mctx, ctx);
	return result;
#endif
}
Example #3
0
/*
 * This is the function called from the signal handler
 */
gboolean
mono_arch_handle_exception (void *ctx, gpointer obj)
{
#if defined(MONO_CROSS_COMPILE)
    g_assert_not_reached ();
#else
    MonoJitTlsData *jit_tls;
    void *sigctx = ctx;

    /*
     * Resume into the normal stack and handle the exception there.
     */
    jit_tls = mono_tls_get_jit_tls ();

    /* Pass the ctx parameter in TLS */
    mono_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);
    /* The others in registers */
    UCONTEXT_REG_R0 (sigctx) = (gsize)obj;

    UCONTEXT_REG_PC (sigctx) = (gsize)handle_signal_exception;
    UCONTEXT_REG_SP (sigctx) = UCONTEXT_REG_SP (sigctx) - MONO_ARCH_REDZONE_SIZE;
#endif

    return TRUE;
}
Example #4
0
gboolean
mono_setup_thread_context(DWORD thread_id, MonoContext *mono_context)
{
	HANDLE handle;
	CONTEXT context;

	g_assert (thread_id != GetCurrentThreadId ());

	handle = OpenThread (THREAD_ALL_ACCESS, FALSE, thread_id);
	g_assert (handle);

	context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;

	if (!GetThreadContext (handle, &context)) {
		CloseHandle (handle);
		return FALSE;
	}

	g_assert (context.ContextFlags & CONTEXT_INTEGER);
	g_assert (context.ContextFlags & CONTEXT_CONTROL);

	memset (mono_context, 0, sizeof (MonoContext));
	mono_sigctx_to_monoctx (&context, mono_context);

	CloseHandle (handle);
	return TRUE;
}
Example #5
0
gboolean
mono_arch_handle_exception (void *ctx, gpointer obj)
{
#if defined(MONO_ARCH_USE_SIGACTION) && defined(UCONTEXT_REG_Rn)
	/*
	 * Handling the exception in the signal handler is problematic, since the original
	 * signal is disabled, and we could run arbitrary code though the debugger. So
	 * resume into the normal stack and do most work there if possible.
	 */
	MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
	mgreg_t sp;
	void *sigctx = ctx;
	int frame_size;
	void *uc = sigctx;

	/* Pass the ctx parameter in TLS */
	mono_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);
	/* The others in registers */
	UCONTEXT_REG_Rn (sigctx, PPC_FIRST_ARG_REG) = (gsize)obj;

	/* Allocate a stack frame below the red zone */
	/* Similar to mono_arch_handle_altstack_exception () */
	frame_size = 224;
	frame_size += 15;
	frame_size &= ~15;
	sp = (mgreg_t)(UCONTEXT_REG_Rn(uc, 1) & ~15);
	sp = (mgreg_t)(sp - frame_size);
	UCONTEXT_REG_Rn(uc, 1) = (mgreg_t)sp;
	setup_ucontext_return (uc, handle_signal_exception);

	return TRUE;
#else
	MonoContext mctx;
	gboolean result;

	mono_sigctx_to_monoctx (ctx, &mctx);

	result = mono_handle_exception (&mctx, obj);
	/* restore the context so that returning from the signal handler will invoke
	 * the catch clause 
	 */
	mono_monoctx_to_sigctx (&mctx, ctx);
	return result;
#endif
}
Example #6
0
static void
altstack_handle_and_restore (void *sigctx, gpointer obj)
{
	MonoContext mctx;

	mono_sigctx_to_monoctx (sigctx, &mctx);
	mono_handle_exception (&mctx, obj);
	mono_restore_context (&mctx);
}
Example #7
0
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;
	guint32 domain_key, jit_key;
	MonoJitTlsData *jit_tls;
	void *domain;
#if defined (MONO_ARCH_ENABLE_MONO_LMF_VAR)
	guint32 lmf_key;
#endif

	/*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);

	domain_key = mono_domain_get_tls_offset ();
	jit_key = mono_get_jit_tls_key ();

	jit_tls = mono_mach_arch_get_tls_value_from_thread (thread_id, jit_key);
	domain = mono_mach_arch_get_tls_value_from_thread (thread_id, domain_key);

	/*Thread already started to cleanup, can no longer capture unwind state*/
	if (!jit_tls)
		return FALSE;
	g_assert (domain);

#if defined (MONO_ARCH_ENABLE_MONO_LMF_VAR)
	lmf_key =  mono_get_lmf_tls_offset ();
	tctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_mach_arch_get_tls_value_from_thread (thread_id, lmf_key);;
#else
	tctx->unwind_data [MONO_UNWIND_DATA_LMF] = jit_tls ? jit_tls->lmf : NULL;
#endif

	tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain;
	tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
	tctx->valid = TRUE;

	return TRUE;
}
Example #8
0
gboolean
sgen_suspend_thread (SgenThreadInfo *info)
{
	mach_msg_type_number_t num_state;
	thread_state_t state;
	kern_return_t ret;
	ucontext_t ctx;
	mcontext_t mctx;

	gpointer stack_start;

	state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ());
	mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ());

	do {
		ret = thread_suspend (info->client_info.info.native_handle);
	} while (ret == KERN_ABORTED);
	if (ret != KERN_SUCCESS)
		return FALSE;

	do {
		ret = mono_mach_arch_get_thread_state (info->client_info.info.native_handle, state, &num_state);
	} while (ret == KERN_ABORTED);
	if (ret != KERN_SUCCESS)
		return FALSE;

	mono_mach_arch_thread_state_to_mcontext (state, mctx);
	ctx.uc_mcontext = mctx;

	info->client_info.stopped_domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
	info->client_info.stopped_ip = (gpointer) mono_mach_arch_get_ip (state);
	info->client_info.stack_start = NULL;
	stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE;
	/* If stack_start is not within the limits, then don't set it in info and we will be restarted. */
	if (stack_start >= info->client_info.stack_start_limit && stack_start <= info->client_info.stack_end) {
		info->client_info.stack_start = stack_start;

#ifdef USE_MONO_CTX
		mono_sigctx_to_monoctx (&ctx, &info->client_info.ctx);
#else
		ARCH_COPY_SIGCTX_REGS (&info->client_info.regs, &ctx);
#endif
	} else {
		g_assert (!info->client_info.stack_start);
	}

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, &ctx, NULL);

	SGEN_LOG (2, "thread %p stopped at %p stack_start=%p", (void*)(gsize)info->client_info.info.native_handle, info->client_info.stopped_ip, info->client_info.stack_start);
	binary_protocol_thread_suspend ((gpointer)mono_thread_info_get_tid (info), info->client_info.stopped_ip);

	return TRUE;
}
Example #9
0
/*
 * This is the function called from the signal handler
 */
gboolean
mono_arch_handle_exception (void *ctx, gpointer obj)
{
#if defined(MONO_CROSS_COMPILE)
	g_assert_not_reached ();
#elif defined(MONO_ARCH_USE_SIGACTION)
	void *sigctx = ctx;

	/*
	 * Handling the exception in the signal handler is problematic, since the original
	 * signal is disabled, and we could run arbitrary code though the debugger. So
	 * resume into the normal stack and do most work there if possible.
	 */
	MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
	guint64 sp = UCONTEXT_GREGS (sigctx) [mips_sp];

	/* Pass the ctx parameter in TLS */
	mono_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);
	/* The others in registers */
	UCONTEXT_GREGS (sigctx)[mips_a0] = (gsize)obj;

	/* Allocate a stack frame */
	sp -= 256;
	UCONTEXT_GREGS (sigctx)[mips_sp] = sp;

	UCONTEXT_REG_PC (sigctx) = (gsize)handle_signal_exception;

	return TRUE;
#else
	MonoContext mctx;
	gboolean result;

	mono_sigctx_to_monoctx (ctx, &mctx);

	result = mono_handle_exception (&mctx, obj);
	/* restore the context so that returning from the signal handler will invoke
	 * the catch clause 
	 */
	mono_monoctx_to_sigctx (&mctx, ctx);
	return result;
#endif
}
Example #10
0
static void
dump_memory_around_ip (void *ctx)
{
#ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
	MonoContext mctx;
	mono_sigctx_to_monoctx (ctx, &mctx);
	gpointer native_ip = MONO_CONTEXT_GET_IP (&mctx);
	g_printerr ("Memory around native instruction pointer (%p):\n", native_ip);
	xxd_mem (((guint8 *) native_ip) - 0x10, 0x40);
#endif
}
Example #11
0
void
mono_arch_handle_altstack_exception (void *sigctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, gpointer fault_addr, gboolean stack_ovf)
{
#ifdef MONO_ARCH_USE_SIGACTION
	MonoException *exc = NULL;
	ucontext_t *ctx = (ucontext_t*)sigctx;
	MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_EIP (ctx), NULL);
	gpointer *sp;
	int frame_size;

	/* if we didn't find a managed method for the ip address and it matches the fault
	 * address, we assume we followed a broken pointer during an indirect call, so
	 * we try the lookup again with the return address pushed on the stack
	 */
	if (!ji && fault_addr == (gpointer)UCONTEXT_REG_EIP (ctx)) {
		glong *sp = (gpointer)UCONTEXT_REG_ESP (ctx);
		ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)sp [0], NULL);
		if (ji)
			UCONTEXT_REG_EIP (ctx) = sp [0];
	}
	if (stack_ovf)
		exc = mono_domain_get ()->stack_overflow_ex;
	if (!ji)
		mono_handle_native_sigsegv (SIGSEGV, sigctx, siginfo);
	/* setup a call frame on the real stack so that control is returned there
	 * and exception handling can continue.
	 * If this was a stack overflow the caller already ensured the stack pages
	 * needed have been unprotected.
	 * The frame looks like:
	 *   ucontext struct
	 *   test_only arg
	 *   exception arg
	 *   ctx arg
	 *   return ip
	 */
	// FIXME: test_only is no more.
 	frame_size = sizeof (MonoContext) + sizeof (gpointer) * 4;
	frame_size += 15;
	frame_size &= ~15;
	sp = (gpointer)(UCONTEXT_REG_ESP (ctx) & ~15);
	sp = (gpointer)((char*)sp - frame_size);
	/* the incoming arguments are aligned to 16 bytes boundaries, so the return address IP
	 * goes at sp [-1]
	 */
	sp [-1] = (gpointer)UCONTEXT_REG_EIP (ctx);
	sp [0] = sp + 4;
	sp [1] = exc;
	sp [2] = (gpointer)stack_ovf;
	mono_sigctx_to_monoctx (sigctx, (MonoContext*)(sp + 4));
	/* at the return form the signal handler execution starts in altstack_handle_and_restore() */
	UCONTEXT_REG_EIP (ctx) = (unsigned long)altstack_handle_and_restore;
	UCONTEXT_REG_ESP (ctx) = (unsigned long)(sp - 1);
#endif
}
Example #12
0
/* Special hack to workaround the fact that the
 * when the SEH handler is called the stack is
 * to small to recover.
 *
 * Stack walking part of this method is from mono_handle_exception
 *
 * The idea is simple; 
 *  - walk the stack to free some space (64k)
 *  - set esp to new stack location
 *  - call mono_arch_handle_exception with stack overflow exception
 *  - set esp to SEH handlers stack
 *  - done
 */
static void 
win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) 
{
	SYSTEM_INFO si;
	DWORD page_size;
	MonoDomain *domain = mono_domain_get ();
	MonoJitInfo rji;
	MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
	MonoLMF *lmf = jit_tls->lmf;		
	MonoContext initial_ctx;
	MonoContext ctx;
	guint32 free_stack = 0;
	StackFrameInfo frame;

	mono_sigctx_to_monoctx (sctx, &ctx);
	
	/* get our os page size */
	GetSystemInfo(&si);
	page_size = si.dwPageSize;

	/* Let's walk the stack to recover
	 * the needed stack space (if possible)
	 */
	memset (&rji, 0, sizeof (rji));

	initial_ctx = ctx;
	free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));

	/* try to free 64kb from our stack */
	do {
		MonoContext new_ctx;

		mono_arch_unwind_frame (domain, jit_tls, &rji, &ctx, &new_ctx, &lmf, NULL, &frame);
		if (!frame.ji) {
			g_warning ("Exception inside function without unwind info");
			g_assert_not_reached ();
		}

		if (frame.ji != (gpointer)-1) {
			free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
		}

		/* todo: we should call abort if ji is -1 */
		ctx = new_ctx;
	} while (free_stack < 64 * 1024 && frame.ji != (gpointer) -1);

	mono_monoctx_to_sigctx (&ctx, sctx);

	/* todo: install new stack-guard page */

	/* use the new stack and call mono_arch_handle_exception () */
	restore_stack (sctx);
}
Example #13
0
gboolean
mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info, void *sigctx)
{
	MonoJitTlsData *jit_tls;
	void *domain;
	MonoLMF *lmf = NULL;
	gpointer *addr;

	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;

	if (sigctx == NULL) {
		DWORD id = mono_thread_info_get_tid (info);
		mono_setup_thread_context (id, &tctx->ctx);
	} else {
		g_assert (((CONTEXT *)sigctx)->ContextFlags & CONTEXT_INTEGER);
		g_assert (((CONTEXT *)sigctx)->ContextFlags & CONTEXT_CONTROL);
		mono_sigctx_to_monoctx (sigctx, &tctx->ctx);
	}

	/* 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);

	/*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.
	 */
	/* 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;
}
Example #14
0
gboolean
mono_sgen_suspend_thread (SgenThreadInfo *info)
{
	mach_msg_type_number_t num_state;
	thread_state_t state;
	kern_return_t ret;
	ucontext_t ctx;
	mcontext_t mctx;

	gpointer stack_start;

	state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ());
	mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ());

	ret = thread_suspend (info->mach_port);
	if (ret != KERN_SUCCESS)
		return FALSE;

	ret = mono_mach_arch_get_thread_state (info->mach_port, state, &num_state);
	if (ret != KERN_SUCCESS)
		return FALSE;

	mono_mach_arch_thread_state_to_mcontext (state, mctx);
	ctx.uc_mcontext = mctx;

	info->stopped_domain = mono_mach_arch_get_tls_value_from_thread ((pthread_t)info->id, mono_domain_get_tls_offset ());
	info->stopped_ip = (gpointer) mono_mach_arch_get_ip (state);
	stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE;
	/* If stack_start is not within the limits, then don't set it in info and we will be restarted. */
	if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
		info->stack_start = stack_start;

#ifdef USE_MONO_CTX
		mono_sigctx_to_monoctx (&ctx, &info->ctx);
		info->monoctx = &info->ctx;
#else
		ARCH_COPY_SIGCTX_REGS (&info->regs, &ctx);
		info->stopped_regs = &info->regs;
#endif
	} else {
		g_assert (!info->stack_start);
	}

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx);
	return TRUE;
}
Example #15
0
MONO_SIG_HANDLER_FUNC (static, sigterm_signal_handler)
{
	MONO_SIG_HANDLER_GET_CONTEXT;

	// Note: this function only returns for a single thread
	// When it's invoked on other threads once the dump begins,
	// those threads perform their dumps and then sleep until we
	// die. The dump ends with the exit(1) below
	MonoContext mctx;
	gchar *output = NULL;
	mono_sigctx_to_monoctx (ctx, &mctx);
	if (!mono_threads_summarize (&mctx, &output, NULL))
		g_assert_not_reached ();

	// Only the dumping-supervisor thread exits mono_thread_summarize
	MOSTLY_ASYNC_SAFE_PRINTF("Unhandled exception dump: \n######\n%s\n######\n", output);

	mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
	exit (1);
}
Example #16
0
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;
	guint32 domain_key, jit_key;
	MonoJitTlsData *jit_tls;
	void *domain;

	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);

	domain_key = mono_domain_get_tls_offset ();
	jit_key = mono_pthread_key_for_tls (mono_get_jit_tls_key ());
	jit_tls = mono_mach_arch_get_tls_value_from_thread (thread_id, jit_key);
	domain = mono_mach_arch_get_tls_value_from_thread (thread_id, domain_key);

	/*Thread already started to cleanup, can no longer capture unwind state*/
	if (!jit_tls)
		return FALSE;
	g_assert (domain);

	tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain;
	tctx->unwind_data [MONO_UNWIND_DATA_LMF] = jit_tls ? jit_tls->lmf : NULL;
	tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
	tctx->valid = TRUE;

	return TRUE;
}
Example #17
0
void
mono_arch_handle_altstack_exception (void *sigctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, gpointer fault_addr, gboolean stack_ovf)
{
#if defined(MONO_ARCH_USE_SIGACTION)
	MonoException *exc = NULL;
	MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (char *)UCONTEXT_REG_RIP (sigctx), NULL);
	gpointer *sp;
	int frame_size;
	MonoContext *copied_ctx;

	if (stack_ovf)
		exc = mono_domain_get ()->stack_overflow_ex;
	if (!ji)
		mono_handle_native_sigsegv (SIGSEGV, sigctx, siginfo);

	/* setup a call frame on the real stack so that control is returned there
	 * and exception handling can continue.
	 * The frame looks like:
	 *   ucontext struct
	 *   ...
	 *   return ip
	 * 128 is the size of the red zone
	 */
	frame_size = sizeof (MonoContext) + sizeof (gpointer) * 4 + 128;
	frame_size += 15;
	frame_size &= ~15;
	sp = (gpointer *)(UCONTEXT_REG_RSP (sigctx) & ~15);
	sp = (gpointer *)((char*)sp - frame_size);
	copied_ctx = (MonoContext*)(sp + 4);
	/* the arguments must be aligned */
	sp [-1] = (gpointer)UCONTEXT_REG_RIP (sigctx);
	mono_sigctx_to_monoctx (sigctx, copied_ctx);
	/* at the return form the signal handler execution starts in altstack_handle_and_restore() */
	UCONTEXT_REG_RIP (sigctx) = (unsigned long)altstack_handle_and_restore;
	UCONTEXT_REG_RSP (sigctx) = (unsigned long)(sp - 1);
	UCONTEXT_REG_RDI (sigctx) = (unsigned long)(copied_ctx);
	UCONTEXT_REG_RSI (sigctx) = (guint64)exc;
	UCONTEXT_REG_RDX (sigctx) = stack_ovf;
#endif
}
Example #18
0
static void
dump_native_stacktrace (const char *signal, void *ctx)
{
#ifdef HAVE_BACKTRACE_SYMBOLS
	void *array [256];
	char **names;
	int i, size;

	mono_runtime_printf_err ("\nNative stacktrace:\n");

	size = backtrace (array, 256);
	names = backtrace_symbols (array, size);
	for (i = 0; i < size; ++i) {
		mono_runtime_printf_err ("\t%s", names [i]);
	}
	g_free (names);

	/* Try to get more meaningful information using gdb */
	char *debugger_log = mono_debugger_state_str ();
	if (debugger_log) {
		fprintf (stderr, "\n\tDebugger session state:\n%s\n", debugger_log);
	}

#if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && (defined(SYS_fork) || HAVE_FORK)
	if (!mini_get_debug_options ()->no_gdb_backtrace) {
		/* From g_spawn_command_line_sync () in eglib */
		pid_t pid;
		int status;
		pid_t crashed_pid = getpid ();

#if defined(TARGET_OSX)
		MonoStackHash hashes;
#endif
		gchar *output = NULL;
		MonoContext mctx;
		if (ctx) {
			gboolean leave = FALSE;
			gboolean dump_for_merp = FALSE;
#if defined(TARGET_OSX)
			dump_for_merp = mono_merp_enabled ();
#endif

			if (!dump_for_merp) {
#ifdef DISABLE_STRUCTURED_CRASH
				leave = TRUE;
#elif defined(TARGET_OSX)
				mini_register_sigterm_handler ();
#endif
			}

#ifdef TARGET_OSX
			if (!leave) {
				mono_sigctx_to_monoctx (ctx, &mctx);
				// Do before forking
				if (!mono_threads_summarize (&mctx, &output, &hashes))
					g_assert_not_reached ();
			}

			// We want our crash, and don't have telemetry
			// So we dump to disk
			if (!leave && !dump_for_merp)
				mono_crash_dump (output);
#endif
		}

		/*
		* glibc fork acquires some locks, so if the crash happened inside malloc/free,
		* it will deadlock. Call the syscall directly instead.
		*/
#if defined(HOST_ANDROID)
		/* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
		g_assert_not_reached ();
#elif !defined(HOST_DARWIN) && defined(SYS_fork)
		pid = (pid_t) syscall (SYS_fork);
#elif HAVE_FORK
		pid = (pid_t) fork ();
#else
		g_assert_not_reached ();
#endif

#if defined (HAVE_PRCTL) && defined(PR_SET_PTRACER)
		if (pid > 0) {
			// Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to
			// a value other than 0 (the most permissive ptrace scope). Most modern Linux
			// distributions set the scope to 1 which allows attaching only to direct children of
			// the current process
			prctl (PR_SET_PTRACER, pid, 0, 0, 0);
		}
#endif

#if defined(TARGET_OSX)
		if (mono_merp_enabled ()) {
			if (pid == 0) {
				if (!ctx) {
					mono_runtime_printf_err ("\nMust always pass non-null context when using merp.\n");
					exit (1);
				}

				char *full_version = mono_get_runtime_build_info ();

				mono_merp_invoke (crashed_pid, signal, output, &hashes, full_version);

				exit (1);
			}
		}
#endif

		if (pid == 0) {
			dup2 (STDERR_FILENO, STDOUT_FILENO);

			mono_gdb_render_native_backtraces (crashed_pid);
			exit (1);
		}

		mono_runtime_printf_err ("\nDebug info from gdb:\n");
		waitpid (pid, &status, 0);
	}
#endif
#else
#ifdef HOST_ANDROID
	/* set DUMPABLE for this process so debuggerd can attach with ptrace(2), see:
	* https://android.googlesource.com/platform/bionic/+/151da681000c07da3c24cd30a3279b1ca017f452/linker/debugger.cpp#206
	* this has changed on later versions of Android.  Also, we don't want to
	* set this on start-up as DUMPABLE has security implications. */
	prctl (PR_SET_DUMPABLE, 1);

	mono_runtime_printf_err ("\nNo native Android stacktrace (see debuggerd output).\n");
#endif
#endif
}
Example #19
0
gboolean
mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info)
{
	DWORD id = mono_thread_info_get_tid (info);
	HANDLE handle;
	CONTEXT context;
	DWORD result;
	MonoContext *ctx;
	MonoJitTlsData *jit_tls;
	void *domain;
	MonoLMF *lmf = NULL;
	gpointer *addr;

	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;

	g_assert (id != GetCurrentThreadId ());

	handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
	g_assert (handle);

	context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;

	if (!GetThreadContext (handle, &context)) {
		CloseHandle (handle);
		return FALSE;
	}

	g_assert (context.ContextFlags & CONTEXT_INTEGER);
	g_assert (context.ContextFlags & CONTEXT_CONTROL);

	ctx = &tctx->ctx;

	memset (ctx, 0, sizeof (MonoContext));
	mono_sigctx_to_monoctx (&context, ctx);

	/* 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);

	/*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.
	 */
	/* 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;
}
Example #20
0
static void
suspend_thread (SgenThreadInfo *info, void *context)
{
	int stop_count;
#ifdef USE_MONO_CTX
	MonoContext monoctx;
#else
	gpointer regs [ARCH_NUM_REGS];
#endif
	gpointer stack_start;

	g_assert (info->doing_handshake);

	info->stopped_domain = mono_domain_get ();
	info->stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
	stop_count = sgen_global_stop_count;
	/* duplicate signal */
	if (0 && info->stop_count == stop_count)
		return;

	sgen_fill_thread_info_for_suspend (info);

	stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
	/* If stack_start is not within the limits, then don't set it
	   in info and we will be restarted. */
	if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
		info->stack_start = stack_start;

#ifdef USE_MONO_CTX
		if (context) {
			mono_sigctx_to_monoctx (context, &monoctx);
			info->monoctx = &monoctx;
		} else {
			info->monoctx = NULL;
		}
#else
		if (context) {
			ARCH_COPY_SIGCTX_REGS (regs, context);
			info->stopped_regs = regs;
		} else {
			info->stopped_regs = NULL;
		}
#endif
	} else {
		g_assert (!info->stack_start);
	}

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, context);

	DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for suspend from %p %p\n", info, (gpointer)mono_native_thread_id_get ()));

	/*
	Block the restart signal. 
	We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend,
	which might miss the signal and get stuck.
	*/
	pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL);

	/* notify the waiting thread */
	MONO_SEM_POST (suspend_ack_semaphore_ptr);
	info->stop_count = stop_count;

	/* wait until we receive the restart signal */
	do {
		info->signal = 0;
		sigsuspend (&suspend_signal_mask);
	} while (info->signal != restart_signal_num && info->doing_handshake);

	/* Unblock the restart signal. */
	pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);

	DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
	/* notify the waiting thread */
	MONO_SEM_POST (suspend_ack_semaphore_ptr);
}
Example #21
0
static void
suspend_thread (SgenThreadInfo *info, void *context)
{
	int stop_count;
#ifndef USE_MONO_CTX
	gpointer regs [ARCH_NUM_REGS];
#endif
	MonoContext ctx;
	gpointer stack_start;

	info->client_info.stopped_domain = mono_domain_get ();
	info->client_info.signal = 0;
	stop_count = sgen_global_stop_count;
	/* duplicate signal */
	if (0 && info->client_info.stop_count == stop_count)
		return;

#ifdef USE_MONO_CTX
	if (context) {
		mono_sigctx_to_monoctx (context, &ctx);
		info->client_info.stopped_ip = MONO_CONTEXT_GET_IP (&ctx);
		stack_start = (((guint8 *) MONO_CONTEXT_GET_SP (&ctx)) - REDZONE_SIZE);
	} else {
		info->client_info.stopped_ip = NULL;
		stack_start = NULL;
	}
#else
	info->client_info.stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
	stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
#endif

	/* If stack_start is not within the limits, then don't set it
	   in info and we will be restarted. */
	if (stack_start >= info->client_info.stack_start_limit && stack_start <= info->client_info.stack_end) {
		info->client_info.stack_start = stack_start;

#ifdef USE_MONO_CTX
		if (context) {
			memcpy (&info->client_info.ctx, &ctx, sizeof (MonoContext));
		} else {
			memset (&info->client_info.ctx, 0, sizeof (MonoContext));
		}
#else
		if (context) {
			ARCH_COPY_SIGCTX_REGS (regs, context);
			memcpy (&info->client_info.regs, regs, sizeof (info->client_info.regs));
		} else {
			memset (&info->client_info.regs, 0, sizeof (info->client_info.regs));
		}
#endif
	} else {
		g_assert (!info->client_info.stack_start);
	}

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, context, NULL);

	SGEN_LOG (4, "Posting suspend_ack_semaphore for suspend from %p %p", info, (gpointer) (gsize) mono_native_thread_id_get ());

	/*
	Block the restart signal. 
	We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend,
	which might miss the signal and get stuck.
	*/
	pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL);

	/* notify the waiting thread */
	SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr);
	info->client_info.stop_count = stop_count;

	/* wait until we receive the restart signal */
	do {
		info->client_info.signal = 0;
		sigsuspend (&suspend_signal_mask);
	} while (info->client_info.signal != restart_signal_num);

	/* Unblock the restart signal. */
	pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);

	SGEN_LOG (4, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer) (gsize) mono_native_thread_id_get ());
	/* notify the waiting thread */
	SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr);
}
Example #22
0
void
mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
{
	mono_sigctx_to_monoctx (sigctx, mctx);
}
Example #23
0
int
mono_sgen_thread_handshake (int signum)
{
	SgenThreadInfo *cur_thread = mono_sgen_thread_info_current ();
	mach_msg_type_number_t num_state;
	thread_state_t state;
	kern_return_t ret;
	ucontext_t ctx;
	mcontext_t mctx;

	SgenThreadInfo *info;
	gpointer stack_start;

	int count = 0;

	state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ());
	mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ());

	FOREACH_THREAD (info) {
		if (info == cur_thread || mono_sgen_is_worker_thread (info->id))
			continue;

		if (signum == suspend_signal_num) {
			ret = thread_suspend (info->mach_port);
			if (ret != KERN_SUCCESS)
				continue;

			ret = mono_mach_arch_get_thread_state (info->mach_port, state, &num_state);
			if (ret != KERN_SUCCESS)
				continue;

			mono_mach_arch_thread_state_to_mcontext (state, mctx);
			ctx.uc_mcontext = mctx;

			info->stopped_domain = mono_mach_arch_get_tls_value_from_thread ((pthread_t)info->id, mono_pthread_key_for_tls (mono_domain_get_tls_key ()));
			info->stopped_ip = (gpointer) mono_mach_arch_get_ip (state);
			stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE;
			/* If stack_start is not within the limits, then don't set it in info and we will be restarted. */
			if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
				info->stack_start = stack_start;

#ifdef USE_MONO_CTX
				mono_sigctx_to_monoctx (&ctx, &info->ctx);
				info->monoctx = &info->ctx;
#else
				ARCH_COPY_SIGCTX_REGS (&info->regs, &ctx);
				info->stopped_regs = &info->regs;
#endif
			} else {
				g_assert (!info->stack_start);
			}

			/* Notify the JIT */
			if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
				mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx);
		} else {
			ret = thread_resume (info->mach_port);
			if (ret != KERN_SUCCESS)
				continue;
		}
		count ++;
	} END_FOREACH_THREAD
	return count;
}