+
+static void
+restore_soft_guard_pages (void)
+{
+ MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+ if (jit_tls->stack_ovf_guard_base)
+ mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_NONE);
+}
+
+/*
+ * this function modifies mctx so that when it is restored, it
+ * won't execcute starting at mctx.eip, but in a function that
+ * will restore the protection on the soft-guard pages and return back to
+ * continue at mctx.eip.
+ */
+static void
+prepare_for_guard_pages (MonoContext *mctx)
+{
+ gpointer *sp;
+ sp = (gpointer)(mctx->esp);
+ sp -= 1;
+ /* the resturn addr */
+ sp [0] = (gpointer)(mctx->eip);
+ mctx->eip = (unsigned long)restore_soft_guard_pages;
+ mctx->esp = (unsigned long)sp;
+}
+
+static void
+altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf)
+{
+ void (*restore_context) (MonoContext *);
+ MonoContext mctx;
+
+ restore_context = mono_arch_get_restore_context ();
+ mono_arch_sigctx_to_monoctx (sigctx, &mctx);
+
+ if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) {
+ if (stack_ovf)
+ prepare_for_guard_pages (&mctx);
+ restore_context (&mctx);
+ }
+
+ mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, FALSE);
+ if (stack_ovf)
+ prepare_for_guard_pages (&mctx);
+ restore_context (&mctx);
+}
+
+void
+mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean stack_ovf)
+{
+#ifdef MONO_ARCH_USE_SIGACTION
+ MonoException *exc = NULL;
+ ucontext_t *ctx = (ucontext_t*)sigctx;
+ MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_EIP (ctx));
+ 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 = mono_jit_info_table_find (mono_domain_get (), (gpointer)sp [0]);
+ 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);
+ /* 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
+ */
+ frame_size = sizeof (ucontext_t) + 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;
+ /* may need to adjust pointers in the new struct copy, depending on the OS */
+ memcpy (sp + 4, ctx, sizeof (ucontext_t));
+ /* 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
+}
+
+#if MONO_SUPPORT_TASKLETS
+MonoContinuationRestore
+mono_tasklets_arch_restore (void)
+{
+ static guint8* saved = NULL;
+ guint8 *code, *start;
+
+ if (saved)
+ return (MonoContinuationRestore)saved;
+ code = start = mono_global_codeman_reserve (48);
+ /* the signature is: restore (MonoContinuation *cont, int state, MonoLMF **lmf_addr) */
+ /* put cont in edx */
+ x86_mov_reg_membase (code, X86_EDX, X86_ESP, 4, 4);
+ /* setup the copy of the stack */
+ x86_mov_reg_membase (code, X86_ECX, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, stack_used_size), 4);
+ x86_shift_reg_imm (code, X86_SHR, X86_ECX, 2);
+ x86_cld (code);
+ x86_mov_reg_membase (code, X86_ESI, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, saved_stack), 4);
+ x86_mov_reg_membase (code, X86_EDI, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, return_sp), 4);
+ x86_prefix (code, X86_REP_PREFIX);
+ x86_movsl (code);
+
+ /* now restore the registers from the LMF */
+ x86_mov_reg_membase (code, X86_ECX, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, lmf), 4);
+ x86_mov_reg_membase (code, X86_EBX, X86_ECX, G_STRUCT_OFFSET (MonoLMF, ebx), 4);
+ x86_mov_reg_membase (code, X86_EBP, X86_ECX, G_STRUCT_OFFSET (MonoLMF, ebp), 4);
+ x86_mov_reg_membase (code, X86_ESI, X86_ECX, G_STRUCT_OFFSET (MonoLMF, esi), 4);
+ x86_mov_reg_membase (code, X86_EDI, X86_ECX, G_STRUCT_OFFSET (MonoLMF, edi), 4);
+
+ /* restore the lmf chain */
+ /*x86_mov_reg_membase (code, X86_ECX, X86_ESP, 12, 4);
+ x86_mov_membase_reg (code, X86_ECX, 0, X86_EDX, 4);*/
+
+ /* state in eax, so it's setup as the return value */
+ x86_mov_reg_membase (code, X86_EAX, X86_ESP, 8, 4);
+ x86_jump_membase (code, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, return_ip));
+ g_assert ((code - start) <= 48);
+ saved = start;
+ return (MonoContinuationRestore)saved;
+}
+#endif
+