#include "mini.h"
#include "mini-x86.h"
+#if defined(__FreeBSD__)
+#include <ucontext.h>
+#endif
+
#ifdef PLATFORM_WIN32
+static void (*restore_stack) (void *);
+
static MonoW32ExceptionHandler fpe_handler;
static MonoW32ExceptionHandler ill_handler;
static MonoW32ExceptionHandler segv_handler;
#define W32_SEH_HANDLE_EX(_ex) \
if (_ex##_handler) _ex##_handler((int)sctx)
+/*
+ * mono_win32_get_handle_stackoverflow (void):
+ *
+ * Returns a pointer to a method which restores the current context stack
+ * and calls handle_exceptions, when done restores the original stack.
+ */
+static gpointer
+mono_win32_get_handle_stackoverflow (void)
+{
+ static guint8 *start = NULL;
+ guint8 *code;
+
+ if (start)
+ return start;
+
+ /* restore_contect (void *sigctx) */
+ start = code = mono_global_codeman_reserve (128);
+
+ /* load context into ebx */
+ x86_mov_reg_membase (code, X86_EBX, X86_ESP, 4, 4);
+
+ /* move current stack into edi for later restore */
+ x86_mov_reg_reg (code, X86_EDI, X86_ESP, 4);
+
+ /* use the new freed stack from sigcontext */
+ x86_mov_reg_membase (code, X86_ESP, X86_EBX, G_STRUCT_OFFSET (struct sigcontext, esp), 4);
+
+ /* get the current domain */
+ x86_call_code (code, mono_domain_get);
+
+ /* get stack overflow exception from domain object */
+ x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoDomain, stack_overflow_ex), 4);
+
+ /* call mono_arch_handle_exception (sctx, stack_overflow_exception_obj, FALSE) */
+ x86_push_imm (code, 0);
+ x86_push_reg (code, X86_EAX);
+ x86_push_reg (code, X86_EBX);
+ x86_call_code (code, mono_arch_handle_exception);
+
+ /* restore the SEH handler stack */
+ x86_mov_reg_reg (code, X86_ESP, X86_EDI, 4);
+
+ /* return */
+ x86_ret (code);
+
+ return start;
+}
+
+/* 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 *ji, rji;
+ MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+ MonoLMF *lmf = jit_tls->lmf;
+ MonoContext initial_ctx;
+ MonoContext ctx;
+ guint32 free_stack = 0;
+
+ /* convert sigcontext to MonoContext (due to reuse of stack walking helpers */
+ mono_arch_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;
+
+ ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
+ if (!ji) {
+ g_warning ("Exception inside function without unwind info");
+ g_assert_not_reached ();
+ }
+
+ if (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 && ji != (gpointer) -1);
+
+ /* convert into sigcontext to be used in mono_arch_handle_exception */
+ mono_arch_monoctx_to_sigctx (&ctx, sctx);
+
+ /* todo: install new stack-guard page */
+
+ /* use the new stack and call mono_arch_handle_exception () */
+ restore_stack (sctx);
+}
+
/*
* Unhandled Exception Filter
* Top-level per-process exception handler.
sctx->eip = ctx->Eip;
switch (er->ExceptionCode) {
+ case EXCEPTION_STACK_OVERFLOW:
+ win32_handle_stack_overflow (ep, sctx);
+ break;
case EXCEPTION_ACCESS_VIOLATION:
W32_SEH_HANDLE_EX(segv);
break;
void win32_seh_init()
{
+ /* install restore stack helper */
+ if (!restore_stack)
+ restore_stack = mono_win32_get_handle_stackoverflow ();
+
old_handler = SetUnhandledExceptionFilter(seh_handler);
}
}
/* Pop EBP and the return address */
- new_ctx->esp = ctx->SC_EBP + (2 * sizeof (gpointer));
+ new_ctx->esp = ctx->ebp + (2 * sizeof (gpointer));
/* we substract 1, so that the IP points into the call instruction */
new_ctx->eip = *((int *)ctx->ebp + 1) - 1;
new_ctx->ebp = *((int *)ctx->ebp);
void
mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
{
+#ifdef MONO_ARCH_USE_SIGACTION
ucontext_t *ctx = (ucontext_t*)sigctx;
-#ifdef MONO_ARCH_USE_SIGACTION
+#if defined(__FreeBSD__)
+ mctx->eax = ctx->uc_mcontext.mc_eax;
+ mctx->ebx = ctx->uc_mcontext.mc_ebx;
+ mctx->ecx = ctx->uc_mcontext.mc_ecx;
+ mctx->edx = ctx->uc_mcontext.mc_edx;
+ mctx->ebp = ctx->uc_mcontext.mc_ebp;
+ mctx->esp = ctx->uc_mcontext.mc_esp;
+ mctx->esi = ctx->uc_mcontext.mc_esi;
+ mctx->edi = ctx->uc_mcontext.mc_edi;
+ mctx->eip = ctx->uc_mcontext.mc_eip;
+#else
mctx->eax = ctx->uc_mcontext.gregs [REG_EAX];
mctx->ebx = ctx->uc_mcontext.gregs [REG_EBX];
mctx->ecx = ctx->uc_mcontext.gregs [REG_ECX];
mctx->esi = ctx->uc_mcontext.gregs [REG_ESI];
mctx->edi = ctx->uc_mcontext.gregs [REG_EDI];
mctx->eip = ctx->uc_mcontext.gregs [REG_EIP];
-#else
- memcpy (mctx, sigctx, sizeof (MonoContext));
+#endif
+#else
+ struct sigcontext *ctx = (struct sigcontext *)sigctx;
+
+ mctx->eax = ctx->SC_EAX;
+ mctx->ebx = ctx->SC_EBX;
+ mctx->ecx = ctx->SC_ECX;
+ mctx->edx = ctx->SC_EDX;
+ mctx->ebp = ctx->SC_EBP;
+ mctx->esp = ctx->SC_ESP;
+ mctx->esi = ctx->SC_ESI;
+ mctx->edi = ctx->SC_EDI;
+ mctx->eip = ctx->SC_EIP;
#endif
}
void
mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
{
+#ifdef MONO_ARCH_USE_SIGACTION
ucontext_t *ctx = (ucontext_t*)sigctx;
-#ifdef MONO_ARCH_USE_SIGACTION
+#if defined(__FreeBSD__)
+ ctx->uc_mcontext.mc_eax = mctx->eax;
+ ctx->uc_mcontext.mc_ebx = mctx->ebx;
+ ctx->uc_mcontext.mc_ecx = mctx->ecx;
+ ctx->uc_mcontext.mc_edx = mctx->edx;
+ ctx->uc_mcontext.mc_ebp = mctx->ebp;
+ ctx->uc_mcontext.mc_esp = mctx->esp;
+ ctx->uc_mcontext.mc_esi = mctx->esi;
+ ctx->uc_mcontext.mc_edi = mctx->edi;
+ ctx->uc_mcontext.mc_eip = mctx->eip;
+
+#else
ctx->uc_mcontext.gregs [REG_EAX] = mctx->eax;
ctx->uc_mcontext.gregs [REG_EBX] = mctx->ebx;
ctx->uc_mcontext.gregs [REG_ECX] = mctx->ecx;
ctx->uc_mcontext.gregs [REG_ESI] = mctx->esi;
ctx->uc_mcontext.gregs [REG_EDI] = mctx->edi;
ctx->uc_mcontext.gregs [REG_EIP] = mctx->eip;
+#endif
#else
- memcpy (ctx, mctx, sizeof (MonoContext));
+ struct sigcontext *ctx = (struct sigcontext *)sigctx;
+
+ ctx->SC_EAX = mctx->eax;
+ ctx->SC_EBX = mctx->ebx;
+ ctx->SC_ECX = mctx->ecx;
+ ctx->SC_EDX = mctx->edx;
+ ctx->SC_EBP = mctx->ebp;
+ ctx->SC_ESP = mctx->esp;
+ ctx->SC_ESI = mctx->esi;
+ ctx->SC_EDI = mctx->edi;
+ ctx->SC_EIP = mctx->eip;
#endif
}
{
#ifdef MONO_ARCH_USE_SIGACTION
ucontext_t *ctx = (ucontext_t*)sigctx;
+#if defined(__FreeBSD__)
+ return (gpointer)ctx->uc_mcontext.mc_eip;
+#else
return (gpointer)ctx->uc_mcontext.gregs [REG_EIP];
+#endif
#else
struct sigcontext *ctx = sigctx;
return (gpointer)ctx->SC_EIP;