/*
- * exception.c: exception support
+ * exceptions-x86.c: exception support for x86
*
* Authors:
* Dietmar Maurer (dietmar@ximian.com)
#include <mono/metadata/threads.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/exception.h>
+#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/mono-debug.h>
#include "mini.h"
#include "mini-x86.h"
-#include "debug-private.h"
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
-# define SC_EAX sc_eax
-# define SC_EBX sc_ebx
-# define SC_ECX sc_ecx
-# define SC_EDX sc_edx
-# define SC_EBP sc_ebp
-# define SC_EIP sc_eip
-# define SC_ESP sc_esp
-# define SC_EDI sc_edi
-# define SC_ESI sc_esi
-#else
-# define SC_EAX eax
-# define SC_EBX ebx
-# define SC_ECX ecx
-# define SC_EDX edx
-# define SC_EBP ebp
-# define SC_EIP eip
-# define SC_ESP esp
-# define SC_EDI edi
-# define SC_ESI esi
-#endif
-
-typedef struct sigcontext MonoContext;
-
-#define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->SC_EIP = (long)ip; } while (0);
-#define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->SC_EBP = (long)bp; } while (0);
-
-#define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->SC_EIP))
-#define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->SC_EBP))
-#ifdef MONO_USE_EXC_TABLES
+#ifdef PLATFORM_WIN32
+static void (*restore_stack) (void *);
-/*************************************/
-/* STACK UNWINDING STUFF */
-/*************************************/
+static MonoW32ExceptionHandler fpe_handler;
+static MonoW32ExceptionHandler ill_handler;
+static MonoW32ExceptionHandler segv_handler;
-/* These definitions are from unwind-dw2.c in glibc 2.2.5 */
+static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
-/* For x86 */
-#define DWARF_FRAME_REGISTERS 17
+#define W32_SEH_HANDLE_EX(_ex) \
+ if (_ex##_handler) _ex##_handler((int)sctx)
-typedef struct frame_state
-{
- void *cfa;
- void *eh_ptr;
- long cfa_offset;
- long args_size;
- long reg_or_offset[DWARF_FRAME_REGISTERS+1];
- unsigned short cfa_reg;
- unsigned short retaddr_column;
- char saved[DWARF_FRAME_REGISTERS+1];
-} frame_state;
-
-static long
-get_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum)
+/*
+ * 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)
{
- switch (dwarf_regnum) {
- case X86_EAX:
- return ctx->eax;
- case X86_EBX:
- return ctx->ebx;
- case X86_ECX:
- return ctx->ecx;
- case X86_EDX:
- return ctx->edx;
- case X86_ESI:
- return ctx->esi;
- case X86_EDI:
- return ctx->edi;
- case X86_EBP:
- return ctx->ebp;
- case X86_ESP:
- return ctx->esp;
- default:
- g_assert_not_reached ();
- }
-
- return 0;
-}
+ static guint8 *start = NULL;
+ guint8 *code;
-static void
-set_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum, long value)
-{
- switch (dwarf_regnum) {
- case X86_EAX:
- ctx->eax = value;
- break;
- case X86_EBX:
- ctx->ebx = value;
- break;
- case X86_ECX:
- ctx->ecx = value;
- break;
- case X86_EDX:
- ctx->edx = value;
- break;
- case X86_ESI:
- ctx->esi = value;
- break;
- case X86_EDI:
- ctx->edi = value;
- break;
- case X86_EBP:
- ctx->ebp = value;
- break;
- case X86_ESP:
- ctx->esp = value;
- break;
- case 8:
- ctx->eip = value;
- break;
- default:
- g_assert_not_reached ();
- }
-}
+ if (start)
+ return start;
-typedef struct frame_state * (*framesf) (void *, struct frame_state *);
+ /* restore_contect (void *sigctx) */
+ start = code = mono_global_codeman_reserve (128);
-static framesf frame_state_for = NULL;
+ /* load context into ebx */
+ x86_mov_reg_membase (code, X86_EBX, X86_ESP, 4, 4);
-static gboolean inited = FALSE;
+ /* move current stack into edi for later restore */
+ x86_mov_reg_reg (code, X86_EDI, X86_ESP, 4);
-typedef char ** (*get_backtrace_symbols_type) (void *__const *__array, int __size);
+ /* use the new freed stack from sigcontext */
+ x86_mov_reg_membase (code, X86_ESP, X86_EBX, G_STRUCT_OFFSET (struct sigcontext, esp), 4);
-static get_backtrace_symbols_type get_backtrace_symbols = NULL;
+ /* get the current domain */
+ x86_call_code (code, mono_domain_get);
-static void
-init_frame_state_for (void)
-{
- GModule *module;
+ /* get stack overflow exception from domain object */
+ x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoDomain, stack_overflow_ex), 4);
- /*
- * There are two versions of __frame_state_for: one in libgcc.a and the
- * other in glibc.so. We need the version from glibc.
- * For more info, see this:
- * http://gcc.gnu.org/ml/gcc/2002-08/msg00192.html
- */
- if ((module = g_module_open ("libc.so.6", G_MODULE_BIND_LAZY))) {
-
- if (!g_module_symbol (module, "__frame_state_for", (gpointer*)&frame_state_for))
- frame_state_for = NULL;
+ /* 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);
- if (!g_module_symbol (module, "backtrace_symbols", (gpointer*)&get_backtrace_symbols)) {
- get_backtrace_symbols = NULL;
- frame_state_for = NULL;
- }
+ /* restore the SEH handler stack */
+ x86_mov_reg_reg (code, X86_ESP, X86_EDI, 4);
- g_module_close (module);
- }
+ /* return */
+ x86_ret (code);
- inited = TRUE;
+ return start;
}
-/* mono_arch_has_unwind_info:
+/* Special hack to workaround the fact that the
+ * when the SEH handler is called the stack is
+ * to small to recover.
*
- * Tests if a function has an DWARF exception table able to restore
- * all caller saved registers.
+ * 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
*/
-gboolean
-mono_arch_has_unwind_info (gconstpointer addr)
+static void
+win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx)
{
- struct frame_state state_in;
- struct frame_state *res;
+ 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;
- if (!inited)
- init_frame_state_for ();
+ /* convert sigcontext to MonoContext (due to reuse of stack walking helpers */
+ mono_arch_sigctx_to_monoctx (sctx, &ctx);
- if (!frame_state_for)
- return FALSE;
+ /* get our os page size */
+ GetSystemInfo(&si);
+ page_size = si.dwPageSize;
- g_assert (addr);
+ /* Let's walk the stack to recover
+ * the needed stack space (if possible)
+ */
+ memset (&rji, 0, sizeof (rji));
- memset (&state_in, 0, sizeof (state_in));
+ initial_ctx = ctx;
+ free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
- /* offset 10 is just a guess, but it works for all methods tested */
- if ((res = frame_state_for ((char *)addr + 10, &state_in))) {
+ /* try to free 64kb from our stack */
+ do {
+ MonoContext new_ctx;
- if (res->saved [X86_EBX] != 1 ||
- res->saved [X86_EDI] != 1 ||
- res->saved [X86_EBP] != 1 ||
- res->saved [X86_ESI] != 1) {
- return FALSE;
+ 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 ();
}
- return TRUE;
- } else {
- return FALSE;
- }
-}
-struct stack_frame
-{
- void *next;
- void *return_address;
-};
-
-static MonoJitInfo *
-x86_unwind_native_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, struct sigcontext *ctx,
- struct sigcontext *new_ctx, MonoLMF *lmf, char **trace)
-{
- struct stack_frame *frame;
- gpointer max_stack;
- MonoJitInfo *ji;
- struct frame_state state_in;
- struct frame_state *res;
-
- if (trace)
- *trace = NULL;
-
- if (!inited)
- init_frame_state_for ();
-
- if (!frame_state_for)
- return FALSE;
+ if (ji != (gpointer)-1) {
+ free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
+ }
- frame = MONO_CONTEXT_GET_BP (ctx);
+ /* todo: we should call abort if ji is -1 */
+ ctx = new_ctx;
+ } while (free_stack < 64 * 1024 && ji != (gpointer) -1);
- max_stack = lmf && lmf->method ? lmf : jit_tls->end_of_stack;
+ /* convert into sigcontext to be used in mono_arch_handle_exception */
+ mono_arch_monoctx_to_sigctx (&ctx, sctx);
- *new_ctx = *ctx;
+ /* todo: install new stack-guard page */
- memset (&state_in, 0, sizeof (state_in));
+ /* use the new stack and call mono_arch_handle_exception () */
+ restore_stack (sctx);
+}
- while ((gpointer)frame->next < (gpointer)max_stack) {
- gpointer ip, addr = frame->return_address;
- void *cfa;
- char *tmp, **symbols;
+/*
+ * Unhandled Exception Filter
+ * Top-level per-process exception handler.
+ */
+LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
+{
+ EXCEPTION_RECORD* er;
+ CONTEXT* ctx;
+ struct sigcontext* sctx;
+ LONG res;
+
+ res = EXCEPTION_CONTINUE_EXECUTION;
+
+ er = ep->ExceptionRecord;
+ ctx = ep->ContextRecord;
+ sctx = g_malloc(sizeof(struct sigcontext));
+
+ /* Copy Win32 context to UNIX style context */
+ sctx->eax = ctx->Eax;
+ sctx->ebx = ctx->Ebx;
+ sctx->ecx = ctx->Ecx;
+ sctx->edx = ctx->Edx;
+ sctx->ebp = ctx->Ebp;
+ sctx->esp = ctx->Esp;
+ sctx->esi = ctx->Esi;
+ sctx->edi = ctx->Edi;
+ 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;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ W32_SEH_HANDLE_EX(ill);
+ break;
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ case EXCEPTION_INT_OVERFLOW:
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_FLT_OVERFLOW:
+ case EXCEPTION_FLT_UNDERFLOW:
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ W32_SEH_HANDLE_EX(fpe);
+ break;
+ default:
+ break;
+ }
- if (trace) {
- ip = MONO_CONTEXT_GET_IP (new_ctx);
- symbols = get_backtrace_symbols (&ip, 1);
- if (*trace)
- tmp = g_strdup_printf ("%s\nin (unmanaged) %s", *trace, symbols [0]);
- else
- tmp = g_strdup_printf ("in (unmanaged) %s", symbols [0]);
+ /* Copy context back */
+ ctx->Eax = sctx->eax;
+ ctx->Ebx = sctx->ebx;
+ ctx->Ecx = sctx->ecx;
+ ctx->Edx = sctx->edx;
+ ctx->Ebp = sctx->ebp;
+ ctx->Esp = sctx->esp;
+ ctx->Esi = sctx->esi;
+ ctx->Edi = sctx->edi;
+ ctx->Eip = sctx->eip;
- free (symbols);
- g_free (*trace);
- *trace = tmp;
- }
+ return res;
+}
- if ((res = frame_state_for (addr, &state_in))) {
- int i;
-
- cfa = (gint8*) (get_sigcontext_reg (new_ctx, res->cfa_reg) + res->cfa_offset);
- frame = (struct stack_frame *)((gint8*)cfa - 8);
- for (i = 0; i < DWARF_FRAME_REGISTERS + 1; i++) {
- int how = res->saved[i];
- long val;
- g_assert ((how == 0) || (how == 1));
-
- if (how == 1) {
- val = * (long*) ((gint8*)cfa + res->reg_or_offset[i]);
- set_sigcontext_reg (new_ctx, i, val);
- }
- }
- new_ctx->esp = (long)cfa;
-
- if (res->saved [X86_EBX] == 1 &&
- res->saved [X86_EDI] == 1 &&
- res->saved [X86_EBP] == 1 &&
- res->saved [X86_ESI] == 1 &&
- (ji = mono_jit_info_table_find (domain, frame->return_address))) {
- //printf ("FRAME CFA %s\n", mono_method_full_name (ji->method, TRUE));
- return ji;
- }
+void win32_seh_init()
+{
+ /* install restore stack helper */
+ if (!restore_stack)
+ restore_stack = mono_win32_get_handle_stackoverflow ();
- } else {
- //printf ("FRAME %p %p %p\n", frame, MONO_CONTEXT_GET_IP (new_ctx), mono_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (new_ctx)));
-
- MONO_CONTEXT_SET_IP (new_ctx, frame->return_address);
- frame = frame->next;
- MONO_CONTEXT_SET_BP (new_ctx, frame);
-
- /* stop if !frame or when we detect an unexpected managed frame */
- if (!frame || mono_jit_info_table_find (domain, frame->return_address)) {
- if (trace) {
- g_free (*trace);
- *trace = NULL;
- }
- return NULL;
- }
- }
- }
+ old_handler = SetUnhandledExceptionFilter(seh_handler);
+}
- //if (!lmf)
- //g_assert_not_reached ();
+void win32_seh_cleanup()
+{
+ if (old_handler) SetUnhandledExceptionFilter(old_handler);
+}
- if (trace) {
- g_free (*trace);
- *trace = NULL;
+void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
+{
+ switch (type) {
+ case SIGFPE:
+ fpe_handler = handler;
+ break;
+ case SIGILL:
+ ill_handler = handler;
+ break;
+ case SIGSEGV:
+ segv_handler = handler;
+ break;
+ default:
+ break;
}
- return NULL;
}
-#endif
+#endif /* PLATFORM_WIN32 */
/*
- * arch_get_restore_context:
+ * mono_arch_get_restore_context:
*
* Returns a pointer to a method which restores a previously saved sigcontext.
*/
-static gpointer
-arch_get_restore_context (void)
+gpointer
+mono_arch_get_restore_context (void)
{
static guint8 *start = NULL;
guint8 *code;
if (start)
return start;
- /* restore_contect (struct sigcontext *ctx) */
+ /* restore_contect (MonoContext *ctx) */
/* we do not restore X86_EAX, X86_EDX */
- start = code = g_malloc (1024);
+ start = code = mono_global_codeman_reserve (128);
/* load ctx */
x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
/* get return address, stored in EDX */
- x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EIP), 4);
+ x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (MonoContext, eip), 4);
/* restore EBX */
- x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
+ x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebx), 4);
/* restore EDI */
- x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
+ x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (MonoContext, edi), 4);
/* restore ESI */
- x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
+ x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (MonoContext, esi), 4);
/* restore ESP */
- x86_mov_reg_membase (code, X86_ESP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESP), 4);
+ x86_mov_reg_membase (code, X86_ESP, X86_EAX, G_STRUCT_OFFSET (MonoContext, esp), 4);
/* restore EBP */
- x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
+ x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebp), 4);
/* jump to the saved IP */
x86_jump_reg (code, X86_EDX);
}
/*
- * arch_get_call_filter:
+ * mono_arch_get_call_filter:
*
* Returns a pointer to a method which calls an exception filter. We
* also use this function to call finally handlers (we pass NULL as
* @exc object in this case).
*/
-static gpointer
-arch_get_call_filter (void)
+gpointer
+mono_arch_get_call_filter (void)
{
- static guint8 start [64];
+ static guint8* start;
static int inited = 0;
guint8 *code;
return start;
inited = 1;
- /* call_filter (struct sigcontext *ctx, unsigned long eip, gpointer exc) */
- code = start;
+ /* call_filter (MonoContext *ctx, unsigned long eip) */
+ start = code = mono_global_codeman_reserve (64);
x86_push_reg (code, X86_EBP);
x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
/* save EBP */
x86_push_reg (code, X86_EBP);
- /* push exc */
- x86_push_membase (code, X86_EBP, 16);
+
/* set new EBP */
- x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
+ x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebp), 4);
/* restore registers used by global register allocation (EBX & ESI) */
- x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
- x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
- x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
- /* save the ESP - this is used by endfinally */
- x86_mov_membase_reg (code, X86_EBP, mono_exc_esp_offset, X86_ESP, 4);
+ x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebx), 4);
+ x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (MonoContext, esi), 4);
+ x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (MonoContext, edi), 4);
+
/* call the handler */
x86_call_reg (code, X86_ECX);
- x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+
/* restore EBP */
x86_pop_reg (code, X86_EBP);
+
/* restore saved regs */
x86_pop_reg (code, X86_ESI);
x86_pop_reg (code, X86_EDI);
static void
throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
- unsigned long eip, unsigned long esp)
+ unsigned long eip, unsigned long esp, gboolean rethrow)
{
- static void (*restore_context) (struct sigcontext *);
- struct sigcontext ctx;
+ static void (*restore_context) (MonoContext *);
+ MonoContext ctx;
if (!restore_context)
- restore_context = arch_get_restore_context ();
+ restore_context = mono_arch_get_restore_context ();
+
+ /* Pop argument and return address */
+ ctx.esp = esp + (2 * sizeof (gpointer));
+ ctx.eip = eip;
+ ctx.ebp = ebp;
+ ctx.edi = edi;
+ ctx.esi = esi;
+ ctx.ebx = ebx;
+ ctx.edx = edx;
+ ctx.ecx = ecx;
+ ctx.eax = eax;
+
+ if (mono_debugger_throw_exception ((gpointer)(eip - 5), (gpointer)esp, exc)) {
+ /*
+ * The debugger wants us to stop on the `throw' instruction.
+ * By the time we get here, it already inserted a breakpoint on
+ * eip - 5 (which is the address of the call).
+ */
+ ctx.eip = eip - 5;
+ ctx.esp = esp + sizeof (gpointer);
+ restore_context (&ctx);
+ g_assert_not_reached ();
+ }
/* adjust eip so that it point into the call instruction */
- eip -= 1;
-
- ctx.SC_ESP = esp;
- ctx.SC_EIP = eip;
- ctx.SC_EBP = ebp;
- ctx.SC_EDI = edi;
- ctx.SC_ESI = esi;
- ctx.SC_EBX = ebx;
- ctx.SC_EDX = edx;
- ctx.SC_ECX = ecx;
- ctx.SC_EAX = eax;
-
- mono_arch_handle_exception (&ctx, exc, FALSE);
+ ctx.eip -= 1;
+
+ if (mono_object_isinst (exc, mono_defaults.exception_class)) {
+ MonoException *mono_ex = (MonoException*)exc;
+ if (!rethrow)
+ mono_ex->stack_trace = NULL;
+ }
+ mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE);
restore_context (&ctx);
g_assert_not_reached ();
}
+static guint8*
+get_throw_exception (gboolean rethrow)
+{
+ guint8 *start, *code;
+
+ start = code = mono_global_codeman_reserve (64);
+
+ x86_push_reg (code, X86_ESP);
+ x86_push_membase (code, X86_ESP, 4); /* IP */
+ x86_push_membase (code, X86_ESP, 12); /* exception */
+ x86_push_reg (code, X86_EBP);
+ x86_push_reg (code, X86_EDI);
+ x86_push_reg (code, X86_ESI);
+ x86_push_reg (code, X86_EBX);
+ x86_push_reg (code, X86_EDX);
+ x86_push_reg (code, X86_ECX);
+ x86_push_reg (code, X86_EAX);
+ x86_call_code (code, throw_exception);
+ /* we should never reach this breakpoint */
+ x86_breakpoint (code);
+
+ g_assert ((code - start) < 64);
+
+ return start;
+}
+
/**
- * arch_get_throw_exception:
+ * mono_arch_get_throw_exception:
*
* Returns a function pointer which can be used to raise
* exceptions. The returned function has the following
gpointer
mono_arch_get_throw_exception (void)
{
- static guint8 start [24];
+ static guint8 *start;
static int inited = 0;
- guint8 *code;
if (inited)
return start;
+ start = get_throw_exception (FALSE);
+
inited = 1;
- code = start;
- x86_push_reg (code, X86_ESP);
- x86_push_membase (code, X86_ESP, 4); /* IP */
- x86_push_membase (code, X86_ESP, 12); /* exception */
- x86_push_reg (code, X86_EBP);
- x86_push_reg (code, X86_EDI);
- x86_push_reg (code, X86_ESI);
- x86_push_reg (code, X86_EBX);
- x86_push_reg (code, X86_EDX);
- x86_push_reg (code, X86_ECX);
- x86_push_reg (code, X86_EAX);
- x86_call_code (code, throw_exception);
- /* we should never reach this breakpoint */
- x86_breakpoint (code);
+ return start;
+}
+
+gpointer
+mono_arch_get_rethrow_exception (void)
+{
+ static guint8 *start;
+ static int inited = 0;
+
+ if (inited)
+ return start;
+
+ start = get_throw_exception (TRUE);
+
+ inited = 1;
- g_assert ((code - start) < 24);
return start;
}
/**
- * arch_get_throw_exception_by_name:
+ * mono_arch_get_throw_exception_by_name:
*
* Returns a function pointer which can be used to raise
* corlib exceptions. The returned function has the following
- * signature: void (*func) (char *exc_name);
+ * signature: void (*func) (gpointer ip, char *exc_name);
* For example to raise an arithmetic exception you can use:
*
* x86_push_imm (code, "ArithmeticException");
- * x86_call_code (code, arch_get_throw_exception_by_name ());
+ * x86_push_imm (code, <IP>)
+ * x86_jump_code (code, arch_get_throw_exception_by_name ());
*
*/
gpointer
mono_arch_get_throw_exception_by_name (void)
{
- static guint8 start [32];
+ static guint8* start;
static int inited = 0;
guint8 *code;
return start;
inited = 1;
- code = start;
+ code = start = mono_global_codeman_reserve (32);
x86_push_membase (code, X86_ESP, 4); /* exception name */
x86_push_imm (code, "System");
g_assert ((code - start) < 32);
return start;
-}
+}
-static MonoArray *
-glist_to_array (GList *list)
+/**
+ * mono_arch_get_throw_corlib_exception:
+ *
+ * Returns a function pointer which can be used to raise
+ * corlib exceptions. The returned function has the following
+ * signature: void (*func) (guint32 ex_token, guint32 offset);
+ * Here, offset is the offset which needs to be substracted from the caller IP
+ * to get the IP of the throw. Passing the offset has the advantage that it
+ * needs no relocations in the caller.
+ */
+gpointer
+mono_arch_get_throw_corlib_exception (void)
{
- MonoDomain *domain = mono_domain_get ();
- MonoArray *res;
- int len, i;
+ static guint8* start;
+ static int inited = 0;
+ guint8 *code;
- if (!list)
- return NULL;
+ if (inited)
+ return start;
- len = g_list_length (list);
- res = mono_array_new (domain, mono_defaults.int_class, len);
+ inited = 1;
+ code = start = mono_global_codeman_reserve (64);
- for (i = 0; list; list = list->next, i++)
- mono_array_set (res, gpointer, i, list->data);
+ x86_push_membase (code, X86_ESP, 4); /* token */
+ 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);
+ /* Compute caller ip */
+ x86_pop_reg (code, X86_ECX);
+ /* Pop token */
+ x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+ x86_pop_reg (code, X86_EDX);
+ x86_alu_reg_reg (code, X86_SUB, X86_ECX, X86_EDX);
+ /* Push exception object */
+ x86_push_reg (code, X86_EAX);
+ /* Push throw IP */
+ x86_push_reg (code, X86_ECX);
+ x86_jump_code (code, mono_arch_get_throw_exception ());
- return res;
+ g_assert ((code - start) < 64);
+
+ return start;
}
/* mono_arch_find_jit_info:
* the @lmf if necessary. @native_offset return the IP offset from the
* start of the function or -1 if that info is not available.
*/
-static MonoJitInfo *
-mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoContext *ctx,
+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)
{
MonoJitInfo *ji;
gpointer ip = MONO_CONTEXT_GET_IP (ctx);
- ji = mono_jit_info_table_find (domain, ip);
-
- if (trace)
- *trace = NULL;
-
- if (native_offset)
- *native_offset = -1;
+ /* Avoid costly table lookup during stack overflow */
+ if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
+ ji = prev_ji;
+ else
+ ji = mono_jit_info_table_find (domain, ip);
if (managed)
*managed = FALSE;
if (ji != NULL) {
- char *source_location, *tmpaddr, *fname;
- gint32 address, iloffset;
int offset;
*new_ctx = *ctx;
- if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
- /* remove any unused lmf */
- *lmf = (*lmf)->previous_lmf;
- }
-
- address = (char *)ip - (char *)ji->code_start;
-
- if (native_offset)
- *native_offset = address;
-
if (managed)
if (!ji->method->wrapper_type)
*managed = TRUE;
- if (trace) {
- if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
- mono_debug_make_symbols ();
+ /*
+ * Some managed methods like pinvoke wrappers might have save_lmf set.
+ * In this case, register save/restore code is not generated by the
+ * JIT, so we have to restore callee saved registers from the lmf.
+ */
+ if (ji->method->save_lmf) {
+ /*
+ * We only need to do this if the exception was raised in managed
+ * code, since otherwise the lmf was already popped of the stack.
+ */
+ if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
+ new_ctx->esi = (*lmf)->esi;
+ new_ctx->edi = (*lmf)->edi;
+ new_ctx->ebx = (*lmf)->ebx;
+ }
+ }
+ else {
+ offset = -1;
+ /* restore caller saved registers */
+ if (ji->used_regs & X86_EBX_MASK) {
+ new_ctx->ebx = *((int *)ctx->ebp + offset);
+ offset--;
+ }
+ if (ji->used_regs & X86_EDI_MASK) {
+ new_ctx->edi = *((int *)ctx->ebp + offset);
+ offset--;
+ }
+ if (ji->used_regs & X86_ESI_MASK) {
+ new_ctx->esi = *((int *)ctx->ebp + offset);
+ }
+ }
- source_location = mono_debug_source_location_from_address (ji->method, address, NULL);
- iloffset = mono_debug_il_offset_from_address (ji->method, address);
- source_location = NULL;
- iloffset = -1;
+ if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
+ /* remove any unused lmf */
+ *lmf = (*lmf)->previous_lmf;
+ }
- if (iloffset < 0)
- tmpaddr = g_strdup_printf ("<0x%05x>", address);
- else
- tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
-
- fname = mono_method_full_name (ji->method, TRUE);
+ /* Pop EBP and the return address */
+ 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);
- if (source_location)
- *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
- else
- *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
+ /* Pop arguments off the stack */
+ {
+ MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1);
- g_free (fname);
- g_free (source_location);
- g_free (tmpaddr);
- }
-
- offset = -1;
- /* restore caller saved registers */
- if (ji->used_regs & X86_EBX_MASK) {
- new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
- offset--;
- }
- if (ji->used_regs & X86_EDI_MASK) {
- new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
- offset--;
- }
- if (ji->used_regs & X86_ESI_MASK) {
- new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
+ guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info);
+ new_ctx->esp += stack_to_pop;
}
- new_ctx->SC_ESP = ctx->SC_EBP;
- /* we substract 1, so that the IP points into the call instruction */
- new_ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 1;
- new_ctx->SC_EBP = *((int *)ctx->SC_EBP);
-
- *res = *ji;
- return res;
-#ifdef MONO_USE_EXC_TABLES
- } else if ((ji = x86_unwind_native_frame (domain, jit_tls, ctx, new_ctx, *lmf, trace))) {
- *res = *ji;
- return res;
-#endif
+ return ji;
} else if (*lmf) {
*new_ctx = *ctx;
if (!(*lmf)->method)
return (gpointer)-1;
- if (trace)
- *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
-
if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
- *res = *ji;
} else {
memset (res, 0, sizeof (MonoJitInfo));
res->method = (*lmf)->method;
}
- new_ctx->SC_ESI = (*lmf)->esi;
- new_ctx->SC_EDI = (*lmf)->edi;
- new_ctx->SC_EBX = (*lmf)->ebx;
- new_ctx->SC_EBP = (*lmf)->ebp;
- new_ctx->SC_EIP = (*lmf)->eip;
+ 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;
/* 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->SC_ESP = (unsigned long)&((*lmf)->eip);
+ new_ctx->esp = (unsigned long)&((*lmf)->eip);
*lmf = (*lmf)->previous_lmf;
- return res;
-
+ return ji ? ji : res;
}
return NULL;
}
-MonoArray *
-ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
-{
- MonoDomain *domain = mono_domain_get ();
- MonoArray *res;
- MonoArray *ta = exc->trace_ips;
- int i, len;
+#ifdef __sun
+#define REG_EAX EAX
+#define REG_EBX EBX
+#define REG_ECX ECX
+#define REG_EDX EDX
+#define REG_EBP EBP
+#define REG_ESP ESP
+#define REG_ESI ESI
+#define REG_EDI EDI
+#define REG_EIP EIP
+#endif
- if (ta == NULL) {
- /* Exception is not thrown yet */
- return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
- }
+void
+mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
+{
+#ifdef MONO_ARCH_USE_SIGACTION
+ ucontext_t *ctx = (ucontext_t*)sigctx;
- len = mono_array_length (ta);
-
- res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
-
- for (i = skip; i < len; i++) {
- MonoJitInfo *ji;
- MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
- gpointer ip = mono_array_get (ta, gpointer, i);
-
- ji = mono_jit_info_table_find (domain, ip);
- if (ji == NULL) {
- /* Unmanaged frame */
- mono_array_set (res, gpointer, i, sf);
- continue;
- }
-
- g_assert (ji != NULL);
-
- sf->method = mono_method_get_object (domain, ji->method, NULL);
- sf->native_offset = (char *)ip - (char *)ji->code_start;
-
- sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset);
- sf->il_offset = -1;
-
- if (need_file_info) {
- gchar *filename;
-
- filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line);
- filename = NULL;
-
- sf->filename = filename? mono_string_new (domain, filename): NULL;
- sf->column = 0;
-
- g_free (filename);
- }
-
- mono_array_set (res, gpointer, i, sf);
- }
-
- return res;
+ mctx->eax = UCONTEXT_REG_EAX (ctx);
+ mctx->ebx = UCONTEXT_REG_EBX (ctx);
+ mctx->ecx = UCONTEXT_REG_ECX (ctx);
+ mctx->edx = UCONTEXT_REG_EDX (ctx);
+ mctx->ebp = UCONTEXT_REG_EBP (ctx);
+ mctx->esp = UCONTEXT_REG_ESP (ctx);
+ mctx->esi = UCONTEXT_REG_ESI (ctx);
+ mctx->edi = UCONTEXT_REG_EDI (ctx);
+ mctx->eip = UCONTEXT_REG_EIP (ctx);
+#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_jit_walk_stack (MonoStackWalk func, gpointer user_data) {
- MonoDomain *domain = mono_domain_get ();
- MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
- MonoLMF *lmf = jit_tls->lmf;
- MonoJitInfo *ji, rji;
- gint native_offset, il_offset;
- gboolean managed;
-
- MonoContext ctx, new_ctx;
-
- MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
- MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
-
- while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
-
- ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
- g_assert (ji);
-
- if (ji == (gpointer)-1)
- return;
-
- il_offset = mono_debug_il_offset_from_address (ji->method, native_offset);
-
- if (func (ji->method, native_offset, il_offset, managed, user_data))
- return;
-
- ctx = new_ctx;
- }
-}
-
-MonoBoolean
-ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
- MonoReflectionMethod **method,
- gint32 *iloffset, gint32 *native_offset,
- MonoString **file, gint32 *line, gint32 *column)
+mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
{
- MonoDomain *domain = mono_domain_get ();
- MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
- MonoLMF *lmf = jit_tls->lmf;
- MonoJitInfo *ji, rji;
- MonoContext ctx, new_ctx;
-
- MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
- MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
-
- skip++;
-
- do {
- ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
-
- ctx = new_ctx;
-
- if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
- return FALSE;
-
- if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)
- continue;
-
- skip--;
-
- } while (skip >= 0);
-
- *method = mono_method_get_object (domain, ji->method, NULL);
- *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset);
- *iloffset = -1;
-
- if (need_file_info) {
- gchar *filename;
-
- filename = mono_debug_source_location_from_address (ji->method, *native_offset, line);
- filename = NULL;
-
- *file = filename? mono_string_new (domain, filename): NULL;
- *column = 0;
-
- g_free (filename);
- }
+#ifdef MONO_ARCH_USE_SIGACTION
+ ucontext_t *ctx = (ucontext_t*)sigctx;
+
+ UCONTEXT_REG_EAX (ctx) = mctx->eax;
+ UCONTEXT_REG_EBX (ctx) = mctx->ebx;
+ UCONTEXT_REG_ECX (ctx) = mctx->ecx;
+ UCONTEXT_REG_EDX (ctx) = mctx->edx;
+ UCONTEXT_REG_EBP (ctx) = mctx->ebp;
+ UCONTEXT_REG_ESP (ctx) = mctx->esp;
+ UCONTEXT_REG_ESI (ctx) = mctx->esi;
+ UCONTEXT_REG_EDI (ctx) = mctx->edi;
+ UCONTEXT_REG_EIP (ctx) = mctx->eip;
+#else
+ 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
+}
- return TRUE;
+gpointer
+mono_arch_ip_from_context (void *sigctx)
+{
+#ifdef MONO_ARCH_USE_SIGACTION
+ ucontext_t *ctx = (ucontext_t*)sigctx;
+ return (gpointer)UCONTEXT_REG_EIP (ctx);
+#else
+ struct sigcontext *ctx = sigctx;
+ return (gpointer)ctx->SC_EIP;
+#endif
}
-/**
- * arch_handle_exception:
- * @ctx: saved processor state
- * @obj: the exception object
- * @test_only: only test if the exception is caught, but dont call handlers
- *
- *
- */
gboolean
-mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
+mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
{
- MonoDomain *domain = mono_domain_get ();
- MonoJitInfo *ji, rji;
- static int (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
- MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
- MonoLMF *lmf = jit_tls->lmf;
- GList *trace_ips = NULL;
-
- g_assert (ctx != NULL);
- if (!obj) {
- MonoException *ex = mono_get_exception_null_reference ();
- ex->message = mono_string_new (domain,
- "Object reference not set to an instance of an object");
- obj = (MonoObject *)ex;
- }
-
- g_assert (mono_object_isinst (obj, mono_defaults.exception_class));
-
- if (!call_filter)
- call_filter = arch_get_call_filter ();
-
- g_assert (jit_tls->end_of_stack);
- g_assert (jit_tls->abort_func);
-
- if (!test_only) {
- MonoContext ctx_cp = *ctx;
- if (mono_jit_trace_calls)
- g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
- if (!mono_arch_handle_exception (&ctx_cp, obj, TRUE)) {
- if (mono_break_on_exc) {
- if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
- mono_debug_make_symbols ();
- G_BREAKPOINT ();
- }
- mono_unhandled_exception (obj);
- }
- }
-
- while (1) {
- MonoContext new_ctx;
- char *trace = NULL;
-
- ji = mono_arch_find_jit_info (domain, jit_tls, &rji, ctx, &new_ctx,
- test_only ? &trace : NULL, &lmf, NULL, NULL);
- if (!ji) {
- g_warning ("Exception inside function without unwind info");
- g_assert_not_reached ();
- }
-
- if (ji != (gpointer)-1) {
-
- if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
- char *tmp, *strace;
-
- trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
+ MonoContext mctx;
- if (!((MonoException*)obj)->stack_trace)
- strace = g_strdup ("");
- else
- strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
-
- tmp = g_strdup_printf ("%s%s\n", strace, trace);
- g_free (strace);
+ mono_arch_sigctx_to_monoctx (sigctx, &mctx);
- ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
+ mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only);
- g_free (tmp);
- }
+ mono_arch_monoctx_to_sigctx (&mctx, sigctx);
- if (ji->num_clauses) {
- int i;
-
- g_assert (ji->clauses);
-
- for (i = 0; i < ji->num_clauses; i++) {
- MonoJitExceptionInfo *ei = &ji->clauses [i];
-
- if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
- MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
- /* catch block */
- if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
- mono_object_isinst (obj, mono_class_get (ji->method->klass->image, ei->data.token))) ||
- ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
- call_filter (ctx, ei->data.filter, obj)))) {
- if (test_only) {
- ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
- g_list_free (trace_ips);
- return TRUE;
- }
- if (mono_jit_trace_calls)
- g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
- MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
- *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
- jit_tls->lmf = lmf;
- return 0;
- }
- if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
- MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
- (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
- if (mono_jit_trace_calls)
- g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
- call_filter (ctx, ei->handler_start, NULL);
- }
-
- }
- }
- }
- }
-
- g_free (trace);
-
- *ctx = new_ctx;
-
- if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
- if (!test_only) {
- jit_tls->lmf = lmf;
- jit_tls->abort_func (obj);
- g_assert_not_reached ();
- } else {
- ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
- g_list_free (trace_ips);
- return FALSE;
- }
- }
- }
-
- g_assert_not_reached ();
+ return TRUE;
}
-
-