*/
#include <config.h>
+
+#if _WIN32_WINNT < 0x0501
+/* Required for Vectored Exception Handling. */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif /* _WIN32_WINNT < 0x0501 */
+
#include <glib.h>
#include <signal.h>
#include <string.h>
#include "mini.h"
#include "mini-amd64.h"
#include "tasklets.h"
-#include "debug-mini.h"
#define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
static MonoW32ExceptionHandler segv_handler;
LPTOP_LEVEL_EXCEPTION_FILTER mono_old_win_toplevel_exception_filter;
-guint64 mono_win_chained_exception_filter_result;
-gboolean mono_win_chained_exception_filter_didrun;
+void *mono_win_vectored_exception_handle;
+extern gboolean mono_win_chained_exception_needs_run;
#define W32_SEH_HANDLE_EX(_ex) \
if (_ex##_handler) _ex##_handler(0, ep, sctx)
+static LONG CALLBACK seh_unhandled_exception_filter(EXCEPTION_POINTERS* ep)
+{
+#ifndef MONO_CROSS_COMPILE
+ if (mono_old_win_toplevel_exception_filter) {
+ return (*mono_old_win_toplevel_exception_filter)(ep);
+ }
+#endif
+
+ mono_handle_native_sigsegv (SIGSEGV, NULL);
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
/*
* Unhandled Exception Filter
* Top-level per-process exception handler.
*/
-LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
+static LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep)
{
EXCEPTION_RECORD* er;
CONTEXT* ctx;
MonoContext* sctx;
LONG res;
- mono_win_chained_exception_filter_didrun = FALSE;
+ mono_win_chained_exception_needs_run = FALSE;
res = EXCEPTION_CONTINUE_EXECUTION;
er = ep->ExceptionRecord;
break;
}
- /* Copy context back */
- /* Nonvolatile */
- ctx->Rsp = sctx->rsp;
- ctx->Rdi = sctx->rdi;
- ctx->Rsi = sctx->rsi;
- ctx->Rbx = sctx->rbx;
- ctx->Rbp = sctx->rbp;
- ctx->R12 = sctx->r12;
- ctx->R13 = sctx->r13;
- ctx->R14 = sctx->r14;
- ctx->R15 = sctx->r15;
- ctx->Rip = sctx->rip;
-
- /* Volatile But should not matter?*/
- ctx->Rax = sctx->rax;
- ctx->Rcx = sctx->rcx;
- ctx->Rdx = sctx->rdx;
-
- g_free (sctx);
-
- if (mono_win_chained_exception_filter_didrun)
- res = mono_win_chained_exception_filter_result;
+ if (mono_win_chained_exception_needs_run) {
+ /* Don't copy context back if we chained exception
+ * as the handler may have modfied the EXCEPTION_POINTERS
+ * directly. We don't pass sigcontext to chained handlers.
+ * Return continue search so the UnhandledExceptionFilter
+ * can correctly chain the exception.
+ */
+ res = EXCEPTION_CONTINUE_SEARCH;
+ } else {
+ /* Copy context back */
+ /* Nonvolatile */
+ ctx->Rsp = sctx->rsp;
+ ctx->Rdi = sctx->rdi;
+ ctx->Rsi = sctx->rsi;
+ ctx->Rbx = sctx->rbx;
+ ctx->Rbp = sctx->rbp;
+ ctx->R12 = sctx->r12;
+ ctx->R13 = sctx->r13;
+ ctx->R14 = sctx->r14;
+ ctx->R15 = sctx->r15;
+ ctx->Rip = sctx->rip;
+
+ /* Volatile But should not matter?*/
+ ctx->Rax = sctx->rax;
+ ctx->Rcx = sctx->rcx;
+ ctx->Rdx = sctx->rdx;
+ }
+
+ /* TODO: Find right place to free this in stack overflow case */
+ if (er->ExceptionCode != EXCEPTION_STACK_OVERFLOW)
+ g_free (sctx);
return res;
}
void win32_seh_init()
{
- mono_old_win_toplevel_exception_filter = SetUnhandledExceptionFilter(seh_handler);
+ mono_old_win_toplevel_exception_filter = SetUnhandledExceptionFilter(seh_unhandled_exception_filter);
+ mono_win_vectored_exception_handle = AddVectoredExceptionHandler (1, seh_vectored_exception_handler);
}
void win32_seh_cleanup()
{
+ guint32 ret = 0;
+
if (mono_old_win_toplevel_exception_filter) SetUnhandledExceptionFilter(mono_old_win_toplevel_exception_filter);
+
+ ret = RemoveVectoredExceptionHandler (mono_win_vectored_exception_handle);
+ g_assert (ret);
}
void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
amd64_mov_reg_membase (code, AMD64_R15, AMD64_R11, G_STRUCT_OFFSET (MonoContext, r15), 8);
#endif
- if (mono_running_on_valgrind ()) {
- /* Prevent 'Address 0x... is just below the stack ptr.' errors */
- amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rsp), 8);
- amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rip), 8);
- amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8);
- } else {
- amd64_mov_reg_membase (code, AMD64_RSP, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rsp), 8);
- /* get return address */
- amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rip), 8);
- }
+ /*
+ * The context resides on the stack, in the stack frame of the
+ * caller of this function. The stack pointer that we need to
+ * restore is potentially many stack frames higher up, so the
+ * distance between them can easily be more than the red zone
+ * size. Hence the stack pointer can be restored only after
+ * we have finished loading everything from the context.
+ */
+ amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rsp), 8);
+ amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rip), 8);
+ amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8);
/* jump to the saved IP */
amd64_jump_reg (code, AMD64_R11);
mono_arch_flush_icache (start, code - start);
if (info)
- *info = mono_tramp_info_create (g_strdup_printf ("restore_context"), start, code - start, ji, unwind_ops);
+ *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops);
return start;
}
mono_arch_flush_icache (start, code - start);
if (info)
- *info = mono_tramp_info_create (g_strdup_printf ("call_filter"), start, code - start, ji, unwind_ops);
+ *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops);
return start;
}
mgreg_t *regs, mgreg_t rip,
MonoObject *exc, gboolean rethrow)
{
- static void (*restore_context) (MonoContext *);
MonoContext ctx;
- if (!restore_context)
- restore_context = mono_get_restore_context ();
-
ctx.rsp = regs [AMD64_RSP];
ctx.rip = rip;
ctx.rbx = regs [AMD64_RBX];
mono_ex->stack_trace = NULL;
}
- if (mono_debug_using_mono_debugger ()) {
- guint8 buf [16];
-
- mono_breakpoint_clean_code (NULL, (gpointer)rip, 8, buf, sizeof (buf));
-
- if (buf [3] == 0xe8) {
- MonoContext ctx_cp = ctx;
- ctx_cp.rip = rip - 5;
-
- if (mono_debugger_handle_exception (&ctx_cp, exc)) {
- restore_context (&ctx_cp);
- g_assert_not_reached ();
- }
- }
- }
-
/* adjust eip so that it point into the call instruction */
ctx.rip -= 1;
mono_handle_exception (&ctx, exc);
- restore_context (&ctx);
-
+ mono_restore_context (&ctx);
g_assert_not_reached ();
}
nacl_global_codeman_validate(&start, kMaxCodeSize, &code);
if (info)
- *info = mono_tramp_info_create (g_strdup (tramp_name), start, code - start, ji, unwind_ops);
+ *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops);
return start;
}
frame->unwind_info = unwind_info;
frame->unwind_info_len = unwind_info_len;
+
+ /*
+ printf ("%s %p %p\n", ji->d.method->name, ji->code_start, ip);
+ mono_print_unwind_info (unwind_info, unwind_info_len);
+ */
regs [AMD64_RAX] = new_ctx->rax;
regs [AMD64_RBX] = new_ctx->rbx;
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);
+ *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~7);
}
#ifndef MONO_AMD64_NO_PUSHES
memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
- *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3);
+ *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~7);
frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
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;
+ if (((guint64)(*lmf)->previous_lmf) & 4) {
+ MonoLMFTramp *ext = (MonoLMFTramp*)(*lmf);
+
+ /* Trampoline frame */
+ new_ctx->rbx = ext->regs [AMD64_RBX];
+ new_ctx->r12 = ext->regs [AMD64_R12];
+ new_ctx->r13 = ext->regs [AMD64_R13];
+ new_ctx->r14 = ext->regs [AMD64_R14];
+ new_ctx->r15 = ext->regs [AMD64_R15];
#ifdef TARGET_WIN32
- new_ctx->rdi = (*lmf)->rdi;
- new_ctx->rsi = (*lmf)->rsi;
+ new_ctx->rdi = ext->regs [AMD64_RDI];
+ new_ctx->rsi = ext->regs [AMD64_RSI];
#endif
+ } else {
+ /*
+ * The registers saved in the LMF will be restored using the normal unwind info,
+ * when the wrapper frame is processed.
+ */
+ new_ctx->rbx = 0;
+ new_ctx->r12 = 0;
+ new_ctx->r13 = 0;
+ new_ctx->r14 = 0;
+ new_ctx->r15 = 0;
+#ifdef TARGET_WIN32
+ new_ctx->rdi = 0;
+ new_ctx->rsi = 0;
+#endif
+ }
- *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3);
+ *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~7);
return TRUE;
}
{
MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
MonoContext ctx;
- static void (*restore_context) (MonoContext *);
-
- if (!restore_context)
- restore_context = mono_get_restore_context ();
memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));
- if (mono_debugger_handle_exception (&ctx, (MonoObject *)obj))
- return;
-
mono_handle_exception (&ctx, obj);
- restore_context (&ctx);
+ mono_restore_context (&ctx);
}
void
/* The stack should be unaligned */
if ((sp % 16) == 0)
sp -= 8;
+#ifdef __linux__
+ /* Preserve the call chain to prevent crashes in the libgcc unwinder (#15969) */
+ *(guint64*)sp = ctx->rip;
+#endif
ctx->rsp = sp;
ctx->rip = (guint64)async_cb;
}
mono_arch_sigctx_to_monoctx (sigctx, &mctx);
- if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj))
- return TRUE;
-
mono_handle_exception (&mctx, obj);
mono_arch_monoctx_to_sigctx (&mctx, sigctx);
static void
altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf)
{
- void (*restore_context) (MonoContext *);
MonoContext mctx;
- restore_context = mono_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);
if (stack_ovf)
prepare_for_guard_pages (&mctx);
- restore_context (&mctx);
+ mono_restore_context (&mctx);
}
void
MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_RIP (sigctx), NULL);
gpointer *sp;
int frame_size;
+ ucontext_t *copied_ctx;
if (stack_ovf)
exc = mono_domain_get ()->stack_overflow_ex;
* 128 is the size of the red zone
*/
frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 4 + 128;
+#ifdef __APPLE__
+ frame_size += sizeof (*ctx->uc_mcontext);
+#endif
frame_size += 15;
frame_size &= ~15;
sp = (gpointer)(UCONTEXT_REG_RSP (sigctx) & ~15);
sp = (gpointer)((char*)sp - frame_size);
+ copied_ctx = (ucontext_t*)(sp + 4);
/* the arguments must be aligned */
sp [-1] = (gpointer)UCONTEXT_REG_RIP (sigctx);
/* may need to adjust pointers in the new struct copy, depending on the OS */
- memcpy (sp + 4, ctx, sizeof (ucontext_t));
+ memcpy (copied_ctx, ctx, sizeof (ucontext_t));
+#ifdef __APPLE__
+ {
+ guint8 * copied_mcontext = (guint8*)copied_ctx + sizeof (ucontext_t);
+ /* uc_mcontext is a pointer, so make a copy which is stored after the ctx */
+ memcpy (copied_mcontext, ctx->uc_mcontext, sizeof (*ctx->uc_mcontext));
+ copied_ctx->uc_mcontext = (void*)copied_mcontext;
+ }
+#endif
/* 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)(sp + 4);
+ UCONTEXT_REG_RDI (sigctx) = (unsigned long)(copied_ctx);
UCONTEXT_REG_RSI (sigctx) = (guint64)exc;
UCONTEXT_REG_RDX (sigctx) = stack_ovf;
#endif
nacl_global_codeman_validate(&start, kMaxCodeSize, &code);
if (info)
- *info = mono_tramp_info_create (g_strdup_printf ("throw_pending_exception"), start, code - start, ji, unwind_ops);
+ *info = mono_tramp_info_create ("throw_pending_exception", start, code - start, ji, unwind_ops);
return start;
}
MonoTrampInfo *info = l->data;
mono_register_jit_icall (info->code, g_strdup (info->name), NULL, TRUE);
- mono_save_trampoline_xdebug_info (info);
- mono_tramp_info_free (info);
+ mono_tramp_info_register (info);
}
g_slist_free (tramps);
}
(sizeof (UNWIND_CODE) * (MONO_MAX_UNWIND_CODES - unwindinfo->unwindInfo.CountOfCodes));
}
-PRUNTIME_FUNCTION
+static PRUNTIME_FUNCTION
MONO_GET_RUNTIME_FUNCTION_CALLBACK ( DWORD64 ControlPc, IN PVOID Context )
{
MonoJitInfo *ji;