Beispiel #1
0
// FIX ME: This is not complete
void
mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
{
	uintptr_t sp = (uintptr_t) MONO_CONTEXT_GET_SP(ctx);
	sp -= PPC_MINIMAL_STACK_SIZE;
	*(unsigned long *)sp = MONO_CONTEXT_GET_SP(ctx);
	MONO_CONTEXT_SET_BP(ctx, sp);
	MONO_CONTEXT_SET_IP(ctx, (unsigned long) async_cb);
}
Beispiel #2
0
/*
 * mono_arch_setup_resume_sighandler_ctx:
 *
 *   Setup CTX so execution continues at FUNC.
 */
void
mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func)
{
	int align = (((gint32)MONO_CONTEXT_GET_SP (ctx)) % MONO_ARCH_FRAME_ALIGNMENT + 4);

	if (align != 0)
		MONO_CONTEXT_SET_SP (ctx, (gsize)MONO_CONTEXT_GET_SP (ctx) - align);

	MONO_CONTEXT_SET_IP (ctx, func);
}
Beispiel #3
0
// FIX ME: This is not complete
void
mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
{
	uintptr_t sp = (uintptr_t) MONO_CONTEXT_GET_SP(ctx);
	ctx->regs [PPC_FIRST_ARG_REG] = user_data;
	sp -= PPC_MINIMAL_STACK_SIZE;
	*(unsigned long *)sp = MONO_CONTEXT_GET_SP(ctx);
	MONO_CONTEXT_SET_BP(ctx, sp);
	mono_arch_setup_resume_sighandler_ctx(ctx, (unsigned long) async_cb);
}
Beispiel #4
0
/*
 * mono_arch_setup_resume_sighandler_ctx:
 *
 *   Setup CTX so execution continues at FUNC.
 */
void
mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func)
{
	/* 
	 * When resuming from a signal handler, the stack should be misaligned, just like right after
	 * a call.
	 */
	if ((((guint64)MONO_CONTEXT_GET_SP (ctx)) % 16) == 0)
		MONO_CONTEXT_SET_SP (ctx, (guint64)MONO_CONTEXT_GET_SP (ctx) - 8);
	MONO_CONTEXT_SET_IP (ctx, func);
}
Beispiel #5
0
static void
mono_native_state_add_ctx (MonoStateWriter *writer, MonoContext *ctx)
{
	// Context
	mono_state_writer_indent (writer);
	mono_state_writer_object_key (writer, "ctx");
	mono_state_writer_printf(writer, "{\n");
	writer->indent++;

	assert_has_space (writer);
	mono_state_writer_indent (writer);
	mono_state_writer_object_key (writer, "IP");
	mono_state_writer_printf(writer, "\"%p\",\n", (gpointer) MONO_CONTEXT_GET_IP (ctx));

	assert_has_space (writer);
	mono_state_writer_indent (writer);
	mono_state_writer_object_key (writer, "SP");
	mono_state_writer_printf(writer, "\"%p\",\n", (gpointer) MONO_CONTEXT_GET_SP (ctx));

	assert_has_space (writer);
	mono_state_writer_indent (writer);
	mono_state_writer_object_key (writer, "BP");
	mono_state_writer_printf(writer, "\"%p\"\n", (gpointer) MONO_CONTEXT_GET_BP (ctx));

	writer->indent--;
	mono_state_writer_indent (writer);
	mono_state_writer_printf(writer, "}");
}
Beispiel #6
0
void
mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
{
    mgreg_t sp = (mgreg_t)MONO_CONTEXT_GET_SP (ctx);

    // FIXME:
    g_assert (!user_data);

    /* Allocate a stack frame */
    sp -= 32;
    MONO_CONTEXT_SET_SP (ctx, sp);

    mono_arch_setup_resume_sighandler_ctx (ctx, async_cb);
}
Beispiel #7
0
void
mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
{
	mgreg_t sp = (mgreg_t)MONO_CONTEXT_GET_SP (ctx);

	// FIXME:
	g_assert (!user_data);

	/* Allocate a stack frame */
	sp -= 16;
	MONO_CONTEXT_SET_SP (ctx, sp);
	MONO_CONTEXT_SET_IP (ctx, async_cb);

	// FIXME: thumb/arm
}
Beispiel #8
0
/*
FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
*/
static gboolean
is_thread_in_critical_region (MonoThreadInfo *info)
{
	MonoMethod *method;
	MonoJitInfo *ji;
	gpointer stack_start;
	MonoThreadUnwindState *state;

	if (mono_threads_platform_in_critical_region (mono_thread_info_get_tid (info)))
		return TRUE;

	/* Are we inside a system critical region? */
	if (info->inside_critical_region)
		return TRUE;

	/* Are we inside a GC critical region? */
	if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) {
		return TRUE;
	}

	/* The target thread might be shutting down and the domain might be null, which means no managed code left to run. */
	state = mono_thread_info_get_suspend_state (info);
	if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
		return FALSE;

	stack_start = MONO_CONTEXT_GET_SP (&state->ctx);
	/* altstack signal handler, sgen can't handle them, so we treat them as critical */
	if (stack_start < info->stack_start_limit || stack_start >= info->stack_end)
		return TRUE;

	if (threads_callbacks.ip_in_critical_region)
		return threads_callbacks.ip_in_critical_region ((MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN], (char *) MONO_CONTEXT_GET_IP (&state->ctx));

	ji = mono_jit_info_table_find (
		(MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
		(char *) MONO_CONTEXT_GET_IP (&state->ctx));

	if (!ji)
		return FALSE;

	method = mono_jit_info_get_method (ji);

	return threads_callbacks.mono_method_is_critical (method);
}
Beispiel #9
0
static MonoException*
continuation_mark_frame (MonoContinuation *cont)
{
	MonoJitTlsData *jit_tls;
	MonoLMF *lmf;
	MonoContext ctx, new_ctx;
	MonoJitInfo *ji, rji;
	int endloop = FALSE;

	if (cont->domain)
		return mono_get_exception_argument ("cont", "Already marked");

	jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
	lmf = mono_get_lmf();
	cont->domain = mono_domain_get ();
	cont->thread_id = mono_native_thread_id_get ();

	/* get to the frame that called Mark () */
	memset (&rji, 0, sizeof (rji));
	memset (&ctx, 0, sizeof (ctx));
	do {
		ji = mono_find_jit_info (cont->domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
		if (!ji || ji == (gpointer)-1) {
			return mono_get_exception_not_supported ("Invalid stack frame");
		}
		ctx = new_ctx;
		if (endloop)
			break;
		if (!ji->is_trampoline && strcmp (jinfo_get_method (ji)->name, "Mark") == 0)
			endloop = TRUE;
	} while (1);

	cont->top_sp = MONO_CONTEXT_GET_SP (&ctx);
	/*g_print ("method: %s, sp: %p\n", jinfo_get_method (ji)->name, cont->top_sp);*/

	return NULL;
}
Beispiel #10
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);
}
Beispiel #11
0
/* 
 * mono_arch_find_jit_info:
 *
 * See exceptions-amd64.c for docs;
 */
gboolean
mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
							 MonoJitInfo *ji, MonoContext *ctx, 
							 MonoContext *new_ctx, MonoLMF **lmf,
							 mgreg_t **save_locations,
							 StackFrameInfo *frame)
{
	gpointer ip = MONO_CONTEXT_GET_IP (ctx);

	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;

	*new_ctx = *ctx;

	if (ji != NULL) {
		int i;
		gssize regs [MONO_MAX_IREGS + 1];
		guint8 *cfa;
		guint32 unwind_info_len;
		guint8 *unwind_info;

		frame->type = FRAME_TYPE_MANAGED;

		if (ji->from_aot)
			unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
		else
			unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);

		for (i = 0; i < 16; ++i)
			regs [i] = new_ctx->regs [i];

		mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
						   (guint8*)ji->code_start + ji->code_size,
						   ip, regs, MONO_MAX_IREGS,
						   save_locations, MONO_MAX_IREGS, &cfa);

		for (i = 0; i < 16; ++i)
			new_ctx->regs [i] = regs [i];
		new_ctx->pc = regs [ARMREG_LR];
		new_ctx->regs [ARMREG_SP] = (gsize)cfa;

		if (*lmf && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->sp)) {
			/* remove any unused lmf */
			*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
		}

		/* Clear thumb bit */
		new_ctx->pc &= ~1;

		/* we substract 1, so that the IP points into the call instruction */
		new_ctx->pc--;

		return TRUE;
	} else if (*lmf) {

		if (((gsize)(*lmf)->previous_lmf) & 2) {
			/* 
			 * This LMF entry is created by the soft debug code to mark transitions to
			 * managed code done during invokes.
			 */
			MonoLMFExt *ext = (MonoLMFExt*)(*lmf);

			g_assert (ext->debugger_invoke);

			memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));

			*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

			frame->type = FRAME_TYPE_DEBUGGER_INVOKE;

			return TRUE;
		}

		frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
		
		if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->ip, NULL))) {
			frame->ji = ji;
		} else {
			if (!(*lmf)->method)
				return FALSE;
			frame->method = (*lmf)->method;
		}

		/*
		 * The LMF is saved at the start of the method using:
		 * ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP)
		 * ARM_PUSH (code, 0x5ff0);
		 * So it stores the register state as it existed at the caller. We need to
		 * produce the register state which existed at the time of the call which
		 * transitioned to native call, so we save the sp/fp/ip in the LMF.
		 */
		memcpy (&new_ctx->regs [0], &(*lmf)->iregs [0], sizeof (mgreg_t) * 13);
		new_ctx->pc = (*lmf)->ip;
		new_ctx->regs [ARMREG_SP] = (*lmf)->sp;
		new_ctx->regs [ARMREG_FP] = (*lmf)->fp;

		/* Clear thumb bit */
		new_ctx->pc &= ~1;

		/* we substract 1, so that the IP points into the call instruction */
		new_ctx->pc--;

		*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

		return TRUE;
	}

	return FALSE;
}
Beispiel #12
0
/*
 * mono_arch_find_jit_info:
 *
 * This function is used to gather information from @ctx, and store it in @frame_info.
 * It unwinds one stack frame, and stores the resulting context into @new_ctx. @lmf
 * is modified if needed.
 * Returns TRUE on success, FALSE otherwise.
 */
gboolean
mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
							 MonoJitInfo *ji, MonoContext *ctx, 
							 MonoContext *new_ctx, MonoLMF **lmf,
							 mgreg_t **save_locations,
							 StackFrameInfo *frame)
{
	gpointer ip = MONO_CONTEXT_GET_IP (ctx);

	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;

	*new_ctx = *ctx;

	if (ji != NULL) {
		mgreg_t regs [MONO_MAX_IREGS + 1];
		guint8 *cfa;
		guint32 unwind_info_len;
		guint8 *unwind_info;

		frame->type = FRAME_TYPE_MANAGED;

		if (ji->from_aot)
			unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
		else
			unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);

		frame->unwind_info = unwind_info;
		frame->unwind_info_len = unwind_info_len;
 
		regs [AMD64_RAX] = new_ctx->rax;
		regs [AMD64_RBX] = new_ctx->rbx;
		regs [AMD64_RCX] = new_ctx->rcx;
		regs [AMD64_RDX] = new_ctx->rdx;
		regs [AMD64_RBP] = new_ctx->rbp;
		regs [AMD64_RSP] = new_ctx->rsp;
		regs [AMD64_RSI] = new_ctx->rsi;
		regs [AMD64_RDI] = new_ctx->rdi;
		regs [AMD64_RIP] = new_ctx->rip;
		regs [AMD64_R12] = new_ctx->r12;
		regs [AMD64_R13] = new_ctx->r13;
		regs [AMD64_R14] = new_ctx->r14;
		regs [AMD64_R15] = new_ctx->r15;

		mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
						   (guint8*)ji->code_start + ji->code_size,
						   ip, regs, MONO_MAX_IREGS + 1, 
						   save_locations, MONO_MAX_IREGS, &cfa);

		new_ctx->rax = regs [AMD64_RAX];
		new_ctx->rbx = regs [AMD64_RBX];
		new_ctx->rcx = regs [AMD64_RCX];
		new_ctx->rdx = regs [AMD64_RDX];
		new_ctx->rbp = regs [AMD64_RBP];
		new_ctx->rsp = regs [AMD64_RSP];
		new_ctx->rsi = regs [AMD64_RSI];
		new_ctx->rdi = regs [AMD64_RDI];
		new_ctx->rip = regs [AMD64_RIP];
		new_ctx->r12 = regs [AMD64_R12];
		new_ctx->r13 = regs [AMD64_R13];
		new_ctx->r14 = regs [AMD64_R14];
		new_ctx->r15 = regs [AMD64_R15];
 
		/* The CFA becomes the new SP value */
		new_ctx->rsp = (mgreg_t)cfa;

		/* Adjust IP */
		new_ctx->rip --;

		if (*lmf && ((*lmf) != jit_tls->first_lmf) && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->rsp)) {
			/* remove any unused lmf */
			*lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3);
		}

#ifndef MONO_AMD64_NO_PUSHES
		/* Pop arguments off the stack */
		if (ji->has_arch_eh_info)
			new_ctx->rsp += mono_jit_info_get_arch_eh_info (ji)->stack_size;
#endif

		return TRUE;
	} else if (*lmf) {
		guint64 rip;

		if (((guint64)(*lmf)->previous_lmf) & 2) {
			/* 
			 * This LMF entry is created by the soft debug code to mark transitions to
			 * managed code done during invokes.
			 */
			MonoLMFExt *ext = (MonoLMFExt*)(*lmf);

			g_assert (ext->debugger_invoke);

			memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));

			*lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3);

			frame->type = FRAME_TYPE_DEBUGGER_INVOKE;

			return TRUE;
		}

		if (((guint64)(*lmf)->previous_lmf) & 1) {
			/* This LMF has the rip field set */
			rip = (*lmf)->rip;
		} else if ((*lmf)->rsp == 0) {
			/* Top LMF entry */
			return FALSE;
		} else {
			/* 
			 * The rsp field is set just before the call which transitioned to native 
			 * code. Obtain the rip from the stack.
			 */
			rip = *(guint64*)((*lmf)->rsp - sizeof(mgreg_t));
		}

		ji = mini_jit_info_table_find (domain, (gpointer)rip, NULL);
		/*
		 * FIXME: ji == NULL can happen when a managed-to-native wrapper is interrupted
		 * in the soft debugger suspend code, since (*lmf)->rsp no longer points to the
		 * return address.
		 */
		//g_assert (ji);
		if (!ji)
			return FALSE;

		/* Adjust IP */
		rip --;

		frame->ji = ji;
		frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;

		new_ctx->rip = rip;
		new_ctx->rbp = (*lmf)->rbp;
		new_ctx->rsp = (*lmf)->rsp;

		new_ctx->rbx = (*lmf)->rbx;
		new_ctx->r12 = (*lmf)->r12;
		new_ctx->r13 = (*lmf)->r13;
		new_ctx->r14 = (*lmf)->r14;
		new_ctx->r15 = (*lmf)->r15;
#ifdef TARGET_WIN32
		new_ctx->rdi = (*lmf)->rdi;
		new_ctx->rsi = (*lmf)->rsi;
#endif

		*lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3);

		return TRUE;
	}

	return FALSE;
}
Beispiel #13
0
/*
 * mono_arch_unwind_frame:
 *
 * See exceptions-amd64.c for docs;
 */
gboolean
mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
                        MonoJitInfo *ji, MonoContext *ctx,
                        MonoContext *new_ctx, MonoLMF **lmf,
                        mgreg_t **save_locations,
                        StackFrameInfo *frame)
{
    gpointer ip = MONO_CONTEXT_GET_IP (ctx);

    memset (frame, 0, sizeof (StackFrameInfo));
    frame->ji = ji;

    *new_ctx = *ctx;

    if (ji != NULL) {
        mgreg_t regs [MONO_MAX_IREGS + 8 + 1];
        guint8 *cfa;
        guint32 unwind_info_len;
        guint8 *unwind_info;

        frame->type = FRAME_TYPE_MANAGED;

        unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len);

        memcpy (regs, &new_ctx->regs, sizeof (mgreg_t) * 32);
        /* v8..v15 are callee saved */
        memcpy (regs + MONO_MAX_IREGS, &(new_ctx->fregs [8]), sizeof (mgreg_t) * 8);

        mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start,
                           (guint8*)ji->code_start + ji->code_size,
                           ip, NULL, regs, MONO_MAX_IREGS + 8,
                           save_locations, MONO_MAX_IREGS, &cfa);

        memcpy (&new_ctx->regs, regs, sizeof (mgreg_t) * 32);
        memcpy (&(new_ctx->fregs [8]), regs + MONO_MAX_IREGS, sizeof (mgreg_t) * 8);

        new_ctx->pc = regs [ARMREG_LR];
        new_ctx->regs [ARMREG_SP] = (mgreg_t)cfa;

        if (*lmf && (*lmf)->gregs [MONO_ARCH_LMF_REG_SP] && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->gregs [MONO_ARCH_LMF_REG_SP])) {
            /* remove any unused lmf */
            *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
        }

        /* we substract 1, so that the IP points into the call instruction */
        new_ctx->pc--;

        return TRUE;
    } else if (*lmf) {
        if (((gsize)(*lmf)->previous_lmf) & 2) {
            /*
             * This LMF entry is created by the soft debug code to mark transitions to
             * managed code done during invokes.
             */
            MonoLMFExt *ext = (MonoLMFExt*)(*lmf);

            g_assert (ext->debugger_invoke);

            memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));

            *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

            frame->type = FRAME_TYPE_DEBUGGER_INVOKE;

            return TRUE;
        }

        frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;

        ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->pc, NULL);
        if (!ji)
            return FALSE;

        g_assert (MONO_ARCH_LMF_REGS == ((0x3ff << 19) | (1 << ARMREG_FP) | (1 << ARMREG_SP)));
        memcpy (&new_ctx->regs [ARMREG_R19], &(*lmf)->gregs [0], sizeof (mgreg_t) * 10);
        new_ctx->regs [ARMREG_FP] = (*lmf)->gregs [MONO_ARCH_LMF_REG_FP];
        new_ctx->regs [ARMREG_SP] = (*lmf)->gregs [MONO_ARCH_LMF_REG_SP];
        new_ctx->pc = (*lmf)->pc;

        /* we substract 1, so that the IP points into the call instruction */
        new_ctx->pc--;

        *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

        return TRUE;
    }

    return FALSE;
}
Beispiel #14
0
static void
sgen_unified_suspend_stop_world (void)
{
	int sleep_duration = -1;

	mono_threads_begin_global_suspend ();
	THREADS_STW_DEBUG ("[GC-STW-BEGIN][%p] *** BEGIN SUSPEND *** \n", mono_thread_info_get_tid (mono_thread_info_current ()));

	FOREACH_THREAD (info) {
		info->client_info.skip = FALSE;
		info->client_info.suspend_done = FALSE;

		int reason;
		if (!sgen_is_thread_in_current_stw (info, &reason)) {
			THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] IGNORE thread %p skip %s reason %d\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false", reason);
			continue;
		}

		info->client_info.skip = !mono_thread_info_begin_suspend (info);

		THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] SUSPEND thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
	} FOREACH_THREAD_END

	mono_thread_info_current ()->client_info.suspend_done = TRUE;
	mono_threads_wait_pending_operations ();

	for (;;) {
		gint restart_counter = 0;

		FOREACH_THREAD (info) {
			gint suspend_count;

			int reason = 0;
			if (info->client_info.suspend_done || !sgen_is_thread_in_current_stw (info, &reason)) {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE RESUME thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason);
				continue;
			}

			/*
			All threads that reach here are pristine suspended. This means the following:

			- We haven't accepted the previous suspend as good.
			- We haven't gave up on it for this STW (it's either bad or asked not to)
			*/
			if (!mono_thread_info_in_critical_location (info)) {
				info->client_info.suspend_done = TRUE;

				THREADS_STW_DEBUG ("[GC-STW-RESTART] DONE thread %p deemed fully suspended\n", mono_thread_info_get_tid (info));
				continue;
			}

			suspend_count = mono_thread_info_suspend_count (info);
			if (!(suspend_count == 1))
				g_error ("[%p] suspend_count = %d, but should be 1", mono_thread_info_get_tid (info), suspend_count);

			info->client_info.skip = !mono_thread_info_begin_resume (info);
			if (!info->client_info.skip)
				restart_counter += 1;

			THREADS_STW_DEBUG ("[GC-STW-RESTART] RESTART thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
		} FOREACH_THREAD_END

		mono_threads_wait_pending_operations ();

		if (restart_counter == 0)
			break;

		if (sleep_duration < 0) {
			mono_thread_info_yield ();
			sleep_duration = 0;
		} else {
			g_usleep (sleep_duration);
			sleep_duration += 10;
		}

		FOREACH_THREAD (info) {
			int reason = 0;
			if (info->client_info.suspend_done || !sgen_is_thread_in_current_stw (info, &reason)) {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE SUSPEND thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason);
				continue;
			}

			if (!mono_thread_info_is_running (info)) {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE SUSPEND thread %p not running\n", mono_thread_info_get_tid (info));
				continue;
			}

			info->client_info.skip = !mono_thread_info_begin_suspend (info);

			THREADS_STW_DEBUG ("[GC-STW-RESTART] SUSPEND thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
		} FOREACH_THREAD_END

		mono_threads_wait_pending_operations ();
	}

	FOREACH_THREAD (info) {
		gpointer stopped_ip;

		int reason = 0;
		if (!sgen_is_thread_in_current_stw (info, &reason)) {
			g_assert (!info->client_info.suspend_done || info == mono_thread_info_current ());

			THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is NOT suspended, reason %d\n", mono_thread_info_get_tid (info), reason);
			continue;
		}

		g_assert (info->client_info.suspend_done);

		info->client_info.ctx = mono_thread_info_get_suspend_state (info)->ctx;

		/* Once we remove the old suspend code, we should move sgen to directly access the state in MonoThread */
		info->client_info.stack_start = (gpointer) ((char*)MONO_CONTEXT_GET_SP (&info->client_info.ctx) - REDZONE_SIZE);

		/* altstack signal handler, sgen can't handle them, mono-threads should have handled this. */
		if (!info->client_info.stack_start
			 || info->client_info.stack_start < info->client_info.stack_start_limit
			 || info->client_info.stack_start >= info->client_info.stack_end) {
			g_error ("BAD STACK: stack_start = %p, stack_start_limit = %p, stack_end = %p",
				info->client_info.stack_start, info->client_info.stack_start_limit, info->client_info.stack_end);
		}

		stopped_ip = (gpointer) (MONO_CONTEXT_GET_IP (&info->client_info.ctx));

		binary_protocol_thread_suspend ((gpointer) mono_thread_info_get_tid (info), stopped_ip);

		THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is suspended, stopped_ip = %p, stack = %p -> %p\n",
			mono_thread_info_get_tid (info), stopped_ip, info->client_info.stack_start, info->client_info.stack_start ? info->client_info.stack_end : NULL);
	} FOREACH_THREAD_END
}
Beispiel #15
0
/*
 * mono_arch_unwind_frame:
 *
 * See exceptions-amd64.c for docs.
 */
gboolean
mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, 
							 MonoJitInfo *ji, MonoContext *ctx, 
							 MonoContext *new_ctx, MonoLMF **lmf,
							 mgreg_t **save_locations,
							 StackFrameInfo *frame)
{
	gpointer ip = MONO_CONTEXT_GET_IP (ctx);
	MonoPPCStackFrame *sframe;

	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;

	*new_ctx = *ctx;
	setup_context (new_ctx);

	if (ji != NULL) {
		int i;
		mgreg_t regs [ppc_lr + 1];
		guint8 *cfa;
		guint32 unwind_info_len;
		guint8 *unwind_info;

		if (ji->is_trampoline)
			frame->type = FRAME_TYPE_TRAMPOLINE;
		else
			frame->type = FRAME_TYPE_MANAGED;

		unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len);

		sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx);
		MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
		if (!ji->is_trampoline && jinfo_get_method (ji)->save_lmf) {
			/* sframe->sp points just past the end of the LMF */
			guint8 *lmf_addr = (guint8*)sframe->sp - sizeof (MonoLMF);
			memcpy (&new_ctx->fregs [MONO_PPC_FIRST_SAVED_FREG], lmf_addr + G_STRUCT_OFFSET (MonoLMF, fregs), sizeof (double) * MONO_SAVED_FREGS);
			memcpy (&new_ctx->regs [MONO_PPC_FIRST_SAVED_GREG], lmf_addr + G_STRUCT_OFFSET (MonoLMF, iregs), sizeof (mgreg_t) * MONO_SAVED_GREGS);
			/* the calling IP is in the parent frame */
			sframe = (MonoPPCStackFrame*)sframe->sp;
			/* we substract 4, so that the IP points into the call instruction */
			MONO_CONTEXT_SET_IP (new_ctx, sframe->lr - 4);
		} else {
			regs [ppc_lr] = ctx->sc_ir;
			regs [ppc_sp] = ctx->sc_sp;
			for (i = MONO_PPC_FIRST_SAVED_GREG; i < MONO_MAX_IREGS; ++i)
				regs [i] = ctx->regs [i];

			mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
							   (guint8*)ji->code_start + ji->code_size,
							   ip, NULL, regs, ppc_lr + 1,
							   save_locations, MONO_MAX_IREGS, &cfa);

			/* we substract 4, so that the IP points into the call instruction */
			MONO_CONTEXT_SET_IP (new_ctx, regs [ppc_lr] - 4);
			MONO_CONTEXT_SET_BP (new_ctx, cfa);

			for (i = MONO_PPC_FIRST_SAVED_GREG; i < MONO_MAX_IREGS; ++i)
				new_ctx->regs [i] = regs [i];
		}

		return TRUE;
	} else if (*lmf) {
		
		if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) {
		} else {
			if (!(*lmf)->method)
				return FALSE;

			/* Trampoline lmf frame */
			frame->method = (*lmf)->method;
		}

		/*sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx);
		MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
		MONO_CONTEXT_SET_IP (new_ctx, sframe->lr);*/
		MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
		MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
		memcpy (&new_ctx->regs [MONO_PPC_FIRST_SAVED_GREG], (*lmf)->iregs, sizeof (mgreg_t) * MONO_SAVED_GREGS);
		memcpy (&new_ctx->fregs [MONO_PPC_FIRST_SAVED_FREG], (*lmf)->fregs, sizeof (double) * MONO_SAVED_FREGS);

		frame->ji = ji;
		frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;

		/* FIXME: what about trampoline LMF frames?  see exceptions-x86.c */

		*lmf = (*lmf)->previous_lmf;

		return TRUE;
	}

	return FALSE;
}
Beispiel #16
0
static void
sgen_unified_suspend_stop_world (void)
{
	int restart_counter;
	int sleep_duration = -1;

	mono_threads_begin_global_suspend ();
	THREADS_STW_DEBUG ("[GC-STW-BEGIN] *** BEGIN SUSPEND *** \n");

	FOREACH_THREAD (info) {
		int reason;
		info->client_info.skip = FALSE;
		info->client_info.suspend_done = FALSE;
		if (sgen_is_thread_in_current_stw (info, &reason)) {
			info->client_info.skip = !mono_thread_info_begin_suspend (info);
			THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] SUSPEND thread %p skip %d\n", mono_thread_info_get_tid (info), info->client_info.skip);
		} else {
			THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] IGNORE thread %p skip %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.skip, reason);
		}
	} FOREACH_THREAD_END

	mono_thread_info_current ()->client_info.suspend_done = TRUE;
	mono_threads_wait_pending_operations ();

	for (;;) {
		restart_counter = 0;
		FOREACH_THREAD (info) {
			int reason = 0;
			if (info->client_info.suspend_done || !sgen_is_thread_in_current_stw (info, &reason)) {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE RESUME thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason);
				continue;
			}

			/*
			All threads that reach here are pristine suspended. This means the following:

			- We haven't accepted the previous suspend as good.
			- We haven't gave up on it for this STW (it's either bad or asked not to)
			*/
			if (mono_thread_info_in_critical_location (info)) {
				gboolean res;
				gint suspend_count = mono_thread_info_suspend_count (info);
				if (!(suspend_count == 1))
					g_error ("[%p] suspend_count = %d, but should be 1", mono_thread_info_get_tid (info), suspend_count);
				res = mono_thread_info_begin_resume (info);
				THREADS_STW_DEBUG ("[GC-STW-RESTART] RESTART thread %p skip %d\n", mono_thread_info_get_tid (info), res);
				if (res)
					++restart_counter;
				else
					info->client_info.skip = TRUE;
			} else {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] DONE thread %p deemed fully suspended\n", mono_thread_info_get_tid (info));
				g_assert (!info->client_info.in_critical_region);
				info->client_info.suspend_done = TRUE;
			}
		} FOREACH_THREAD_END

		if (restart_counter == 0)
			break;
		mono_threads_wait_pending_operations ();

		if (sleep_duration < 0) {
			mono_thread_info_yield ();
			sleep_duration = 0;
		} else {
			g_usleep (sleep_duration);
			sleep_duration += 10;
		}

		FOREACH_THREAD (info) {
			int reason = 0;
			if (info->client_info.suspend_done || !sgen_is_thread_in_current_stw (info, &reason)) {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE SUSPEND thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason);
				continue;
			}

			if (mono_thread_info_is_running (info)) {
				gboolean res = mono_thread_info_begin_suspend (info);
				THREADS_STW_DEBUG ("[GC-STW-RESTART] SUSPEND thread %p skip %d\n", mono_thread_info_get_tid (info), res);
				if (!res)
					info->client_info.skip = TRUE;
			}
		} FOREACH_THREAD_END

		mono_threads_wait_pending_operations ();
	}

	FOREACH_THREAD (info) {
		int reason = 0;
		if (sgen_is_thread_in_current_stw (info, &reason)) {
			MonoThreadUnwindState *state;

			THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is suspended\n", mono_thread_info_get_tid (info));
			g_assert (info->client_info.suspend_done);

			state = mono_thread_info_get_suspend_state (info);

			info->client_info.ctx = state->ctx;

			if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !state->unwind_data [MONO_UNWIND_DATA_LMF]) {
				/* thread is starting or detaching, nothing to scan here */
				info->client_info.stopped_domain = NULL;
				info->client_info.stopped_ip = NULL;
				info->client_info.stack_start = NULL;
			} else {
				/* Once we remove the old suspend code, we should move sgen to directly access the state in MonoThread */
				info->client_info.stopped_domain = (MonoDomain*) mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
				info->client_info.stopped_ip = (gpointer) (MONO_CONTEXT_GET_IP (&info->client_info.ctx));
				info->client_info.stack_start = (gpointer) ((char*)MONO_CONTEXT_GET_SP (&info->client_info.ctx) - REDZONE_SIZE);

				/* altstack signal handler, sgen can't handle them, mono-threads should have handled this. */
				if (!info->client_info.stack_start
					 || info->client_info.stack_start < info->client_info.stack_start_limit
					 || info->client_info.stack_start >= info->client_info.stack_end) {
					g_error ("BAD STACK: stack_start = %p, stack_start_limit = %p, stack_end = %p",
						info->client_info.stack_start, info->client_info.stack_start_limit, info->client_info.stack_end);
				}
			}

			binary_protocol_thread_suspend ((gpointer) mono_thread_info_get_tid (info), info->client_info.stopped_ip);
		} else {
			THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is NOT suspended, reason %d\n", mono_thread_info_get_tid (info), reason);
			g_assert (!info->client_info.suspend_done || info == mono_thread_info_current ());
		}
	} FOREACH_THREAD_END
}
Beispiel #17
0
/*
 * mono_arch_find_jit_info:
 *
 * See exceptions-amd64.c for docs.
 */
gboolean
mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
							 MonoJitInfo *ji, MonoContext *ctx, 
							 MonoContext *new_ctx, MonoLMF **lmf,
							 mgreg_t **save_locations,
							 StackFrameInfo *frame)
{
	gpointer ip = MONO_CONTEXT_GET_IP (ctx);

	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;

	*new_ctx = *ctx;

	if (ji != NULL) {
		gssize regs [MONO_MAX_IREGS + 1];
		guint8 *cfa;
		guint32 unwind_info_len;
		guint8 *unwind_info;

		frame->type = FRAME_TYPE_MANAGED;

		if (ji->from_aot)
			unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
		else
			unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);

		regs [X86_EAX] = new_ctx->eax;
		regs [X86_EBX] = new_ctx->ebx;
		regs [X86_ECX] = new_ctx->ecx;
		regs [X86_EDX] = new_ctx->edx;
		regs [X86_ESP] = new_ctx->esp;
		regs [X86_EBP] = new_ctx->ebp;
		regs [X86_ESI] = new_ctx->esi;
		regs [X86_EDI] = new_ctx->edi;
		regs [X86_NREG] = new_ctx->eip;

		mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
						   (guint8*)ji->code_start + ji->code_size,
						   ip, regs, MONO_MAX_IREGS + 1,
						   save_locations, MONO_MAX_IREGS, &cfa);

		new_ctx->eax = regs [X86_EAX];
		new_ctx->ebx = regs [X86_EBX];
		new_ctx->ecx = regs [X86_ECX];
		new_ctx->edx = regs [X86_EDX];
		new_ctx->esp = regs [X86_ESP];
		new_ctx->ebp = regs [X86_EBP];
		new_ctx->esi = regs [X86_ESI];
		new_ctx->edi = regs [X86_EDI];
		new_ctx->eip = regs [X86_NREG];

 		/* The CFA becomes the new SP value */
		new_ctx->esp = (gssize)cfa;

		/* Adjust IP */
		new_ctx->eip --;

		if (*lmf && ((*lmf) != jit_tls->first_lmf)) {
			gboolean is_tramp = ((guint32)((*lmf)->previous_lmf) & 1);
			gpointer lmf_esp;

			if (is_tramp)
				/* lmf->esp is only set in trampoline frames */
				lmf_esp = (gpointer)(*lmf)->esp;
			else
				/* In non-trampoline frames, ebp is the frame pointer */
				lmf_esp = (gpointer)(*lmf)->ebp;
			if (MONO_CONTEXT_GET_SP (ctx) >= lmf_esp)
				/* remove any unused lmf */
				*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
		}

		/* Pop arguments off the stack */
		/* 
		 * FIXME: LLVM doesn't push these, we can't use ji->from_llvm as it describes
		 * the callee.
		 */
#ifndef ENABLE_LLVM
		if (ji->has_arch_eh_info)
			new_ctx->esp += mono_jit_info_get_arch_eh_info (ji)->stack_size;
#endif

		return TRUE;
	} else if (*lmf) {

		if (((guint64)(*lmf)->previous_lmf) & 2) {
			/* 
			 * This LMF entry is created by the soft debug code to mark transitions to
			 * managed code done during invokes.
			 */
			MonoLMFExt *ext = (MonoLMFExt*)(*lmf);

			g_assert (ext->debugger_invoke);

			memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));

			*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

			frame->type = FRAME_TYPE_DEBUGGER_INVOKE;

			return TRUE;
		}
		
		if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) {
		} else {
			if (!((guint32)((*lmf)->previous_lmf) & 1))
				/* Top LMF entry */
				return FALSE;
			g_assert_not_reached ();
			/* Trampoline lmf frame */
			frame->method = (*lmf)->method;
		}

		new_ctx->esi = (*lmf)->esi;
		new_ctx->edi = (*lmf)->edi;
		new_ctx->ebx = (*lmf)->ebx;
		new_ctx->ebp = (*lmf)->ebp;
		new_ctx->eip = (*lmf)->eip;

		/* Adjust IP */
		new_ctx->eip --;

		frame->ji = ji;
		frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;

		/* Check if we are in a trampoline LMF frame */
		if ((guint32)((*lmf)->previous_lmf) & 1) {
			/* lmf->esp is set by the trampoline code */
			new_ctx->esp = (*lmf)->esp;

			/* Pop arguments off the stack */
			/* FIXME: Handle the delegate case too ((*lmf)->method == NULL) */
			/* FIXME: Handle the IMT/vtable case too */
#if 0
#ifndef ENABLE_LLVM
			if ((*lmf)->method) {
				MonoMethod *method = (*lmf)->method;
				MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (method)->param_count + 1);

				guint32 stack_to_pop = mono_arch_get_argument_info (NULL, mono_method_signature (method), mono_method_signature (method)->param_count, arg_info);
				new_ctx->esp += stack_to_pop;
			}
#endif
#endif
		}
		else
			/* the lmf is always stored on the stack, so the following
			 * expression points to a stack location which can be used as ESP */
			new_ctx->esp = (unsigned long)&((*lmf)->eip);

		*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

		return TRUE;
	}

	return FALSE;
}
Beispiel #18
0
/*
 * mono_arch_find_jit_info:
 *
 * This function is used to gather information from @ctx, and store it in @frame_info.
 * It unwinds one stack frame, and stores the resulting context into @new_ctx. @lmf
 * is modified if needed.
 * Returns TRUE on success, FALSE otherwise.
 */
gboolean
mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
							 MonoJitInfo *ji, MonoContext *ctx, 
							 MonoContext *new_ctx, MonoLMF **lmf, 
							 mgreg_t **save_locations,
							 StackFrameInfo *frame)
{
	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;

	*new_ctx = *ctx;

	if (ji != NULL) {
		int i;
		gpointer ip = MONO_CONTEXT_GET_IP (ctx);
		mgreg_t regs [MONO_MAX_IREGS + 1];
		guint8 *cfa;
		guint32 unwind_info_len;
		guint8 *unwind_info;

		frame->type = FRAME_TYPE_MANAGED;

		unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len);

		for (i = 0; i < MONO_MAX_IREGS; ++i)
			regs [i] = new_ctx->sc_regs [i];

		mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
						   (guint8*)ji->code_start + ji->code_size,
						   ip, NULL, regs, MONO_MAX_IREGS,
						   save_locations, MONO_MAX_IREGS, &cfa);

		for (i = 0; i < MONO_MAX_IREGS; ++i)
			new_ctx->sc_regs [i] = regs [i];
		new_ctx->sc_pc = regs [mips_ra];
		new_ctx->sc_regs [mips_sp] = (mgreg_t)cfa;

		/* we substract 8, so that the IP points into the call instruction */
		MONO_CONTEXT_SET_IP (new_ctx, new_ctx->sc_pc - 8);

		/* Sanity check -- we should have made progress here */
		g_assert (MONO_CONTEXT_GET_SP (new_ctx) != MONO_CONTEXT_GET_SP (ctx));
		return TRUE;
	} else if (*lmf) {

		if (((mgreg_t)(*lmf)->previous_lmf) & 2) {
			/* 
			 * This LMF entry is created by the soft debug code to mark transitions to
			 * managed code done during invokes.
			 */
			MonoLMFExt *ext = (MonoLMFExt*)(*lmf);

			g_assert (ext->debugger_invoke);

			memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));

			*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

			frame->type = FRAME_TYPE_DEBUGGER_INVOKE;

			return TRUE;
		}

		if (!(*lmf)->method) {
#ifdef DEBUG_EXCEPTIONS
			g_print ("mono_arch_find_jit_info: bad lmf @ %p\n", (void *) *lmf);
#endif
			return FALSE;
		}
		g_assert (((*lmf)->magic == MIPS_LMF_MAGIC1) || ((*lmf)->magic == MIPS_LMF_MAGIC2));

		ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL);
		if (!ji) {
			// FIXME: This can happen with multiple appdomains (bug #444383)
			return FALSE;
		}

		frame->ji = ji;
		frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;

		memcpy (&new_ctx->sc_regs, (*lmf)->iregs, sizeof (gulong) * MONO_SAVED_GREGS);
		memcpy (&new_ctx->sc_fpregs, (*lmf)->fregs, sizeof (float) * MONO_SAVED_FREGS);
		MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
		/* ensure that we've made progress */
		g_assert (new_ctx->sc_pc != ctx->sc_pc);

		*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

		return TRUE;
	}

	return FALSE;
}
Beispiel #19
0
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 = mono_native_tls_get_value (mono_jit_tls_id);
		int current_frame_index = 1;
		MonoContext mono_context;
		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);
			
			while ((current_frame_index <= call_chain_depth) &&
					(stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) &&
					((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) {
				ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame);
				current_frame_index ++;
				stack_top = current_frame;
				current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
			}
#else
				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);
					}
				}
			}
		}
		
		mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
	}

	mono_chain_signal (SIG_HANDLER_PARAMS);
}