#include <mono/metadata/exception.h>
#include <mono/metadata/gc-internal.h>
#include <mono/metadata/mono-debug.h>
+#include <mono/utils/mono-mmap.h>
#include "mini.h"
#include "mini-x86.h"
do {
MonoContext new_ctx;
- ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
+ ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, &ctx, &new_ctx, &lmf, NULL);
if (!ji) {
g_warning ("Exception inside function without unwind info");
g_assert_not_reached ();
inited = 1;
code = start = mono_global_codeman_reserve (64);
- x86_push_membase (code, X86_ESP, 4); /* token */
+ x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4); /* token */
+ x86_alu_reg_imm (code, X86_ADD, X86_EAX, MONO_TOKEN_TYPE_DEF);
+ x86_push_reg (code, X86_EAX);
x86_push_imm (code, mono_defaults.exception_class->image);
x86_call_code (code, mono_exception_from_token);
x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
*/
MonoJitInfo *
mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
- MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
- gboolean *managed)
+ MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
{
MonoJitInfo *ji;
gpointer ip = MONO_CONTEXT_GET_IP (ctx);
if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
/* remove any unused lmf */
- *lmf = (*lmf)->previous_lmf;
+ *lmf = (gpointer)(((guint32)(*lmf)->previous_lmf) & ~1);
}
/* Pop EBP and the return address */
new_ctx->ebx = (*lmf)->ebx;
new_ctx->ebp = (*lmf)->ebp;
new_ctx->eip = (*lmf)->eip;
- /* 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 = (*lmf)->previous_lmf;
+ /* 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 ((*lmf)->method && (*lmf)->method != MONO_FAKE_IMT_METHOD && (*lmf)->method != MONO_FAKE_VTABLE_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 (mono_method_signature (method), mono_method_signature (method)->param_count, arg_info);
+ new_ctx->esp += stack_to_pop;
+ }
+ }
+ 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)(((guint32)(*lmf)->previous_lmf) & ~1);
return ji ? ji : res;
}
return TRUE;
}
+
+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);
+ 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
+}
+