* mini-exceptions.c: New file.
* mini.c mini-exceptions.c mini-x86.h exceptions-x86.c Makefile.am:
Move some parts of the x86 exception handling code to an
arch-independent file so it can be shared with other ports.
svn path=/trunk/mono/; revision=26126
+2004-04-28 Zoltan Varga <vargaz@freemail.hu>
+
+ * mini-exceptions.c: New file.
+
+ * mini.c mini-exceptions.c mini-x86.h exceptions-x86.c Makefile.am:
+ Move some parts of the x86 exception handling code to an
+ arch-independent file so it can be shared with other ports.
Tue Apr 27 12:15:59 CEST 2004 Paolo Molaro <lupus@ximian.com>
$(GMODULE_LIBS)
x86_sources = \
+ mini-exceptions.c \
mini-x86.c \
mini-x86.h \
exceptions-x86.c \
$(MCS) /unsafe $< /r:TestDriver.dll
%.exe: %.il
- ilasm /OUTPUT=$*.exe $<
+ ilasm /output=$*.exe $<
TestDriver.dll: TestDriver.cs
$(MCS) /out:TestDriver.dll /target:library TestDriver.cs
for i in $(regtests); do $(RUNTIME) $$i; done
rcheck: mono $(regtests)
- ./mono --verbose --regression $(regtests)
+ ./mono --regression $(regtests)
aotcheck: mono $(regtests)
for i in $(regtests); do ./mono --aot $$i; done
#include "mini.h"
#include "mini-x86.h"
-#define IS_ON_SIGALTSTACK(jit_tls) ((jit_tls) && ((guint8*)&(jit_tls) > (guint8*)(jit_tls)->signal_stack) && ((guint8*)&(jit_tls) < ((guint8*)(jit_tls)->signal_stack + (jit_tls)->signal_stack_size)))
-
#ifdef PLATFORM_WIN32
#include <windows.h>
#endif /* PLATFORM_WIN32 */
-#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
-
-gboolean mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
-
-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
#endif
/*
- * 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;
}
/*
- * 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 int inited = 0;
struct sigcontext ctx;
if (!restore_context)
- restore_context = arch_get_restore_context ();
+ restore_context = mono_arch_get_restore_context ();
/* adjust eip so that it point into the call instruction */
eip -= 1;
}
/**
- * 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
}
/**
- * 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
g_assert ((code - start) < 32);
return start;
-}
-
-static MonoArray *
-glist_to_array (GList *list)
-{
- MonoDomain *domain = mono_domain_get ();
- MonoArray *res;
- int len, i;
-
- if (!list)
- return NULL;
-
- len = g_list_length (list);
- res = mono_array_new (domain, mono_defaults.int_class, len);
-
- for (i = 0; list; list = list->next, i++)
- mono_array_set (res, gpointer, i, list->data);
-
- return res;
}
/* 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 *
+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)
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;
-
- if (ta == NULL) {
- /* Exception is not thrown yet */
- return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
- }
-
- 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, domain);
-
- if (need_file_info) {
- gchar *filename;
-
- filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
-
- sf->filename = filename? mono_string_new (domain, filename): NULL;
- sf->column = 0;
-
- g_free (filename);
- }
-
- mono_array_set (res, gpointer, i, sf);
- }
-
- return res;
-}
-
-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, NULL, &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, domain);
-
- 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)
-{
- 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, NULL, &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;
-
- /* skip all wrappers ??*/
- if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
- ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
- ji->method->wrapper_type == MONO_WRAPPER_REMOTING_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, domain);
-
- if (need_file_info) {
- gchar *filename;
-
- filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
-
- *file = filename? mono_string_new (domain, filename): NULL;
- *column = 0;
-
- g_free (filename);
- }
-
- return TRUE;
-}
-
/**
- * arch_handle_exception:
+ * mono_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) = NULL;
- static void (*restore_context) (struct sigcontext *);
- MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
- MonoLMF *lmf = jit_tls->lmf;
- GList *trace_ips = NULL;
- MonoException *mono_ex;
- gboolean stack_overflow = FALSE;
- MonoContext initial_ctx;
- int frame_count = 0;
- gboolean gc_disabled = FALSE;
- MonoString *initial_stack_trace;
-
- /*
- * This function might execute on an alternate signal stack, and Boehm GC
- * can't handle that.
- * Also, since the altstack is small, stack space intensive operations like
- * JIT compilation should be avoided.
- */
- if (IS_ON_SIGALTSTACK (jit_tls)) {
- /*
- * FIXME: disabling/enabling GC while already on a signal stack might
- * not be safe either.
- */
- /* Have to reenable it later */
- gc_disabled = TRUE;
- mono_gc_disable ();
- }
-
- 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;
- }
-
- /*
- * Allocate a new exception object instead of the preconstructed ones.
- * We can't do this in sigsegv_signal_handler, since GC is not yet
- * disabled.
- */
- if (obj == domain->stack_overflow_ex) {
- obj = mono_get_exception_stack_overflow ();
- }
- else if (obj == domain->null_reference_ex) {
- obj = mono_get_exception_null_reference ();
- }
-
- if (mono_object_isinst (obj, mono_defaults.exception_class)) {
- mono_ex = (MonoException*)obj;
- initial_stack_trace = mono_ex->stack_trace;
- } else {
- mono_ex = NULL;
- }
-
- if (obj == domain->stack_overflow_ex)
- stack_overflow = TRUE;
-
- if (!call_filter)
- call_filter = arch_get_call_filter ();
-
- if (!restore_context)
- restore_context = arch_get_restore_context ();
-
- 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 != NULL)
- 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)
- G_BREAKPOINT ();
- mono_unhandled_exception (obj);
- }
- }
-
- initial_ctx = *ctx;
- memset (&rji, 0, sizeof (rji));
-
- while (1) {
- MonoContext new_ctx;
- char *trace = NULL;
- gboolean need_trace = FALSE;
- guint32 free_stack;
-
- if (test_only && (frame_count < 1000))
- need_trace = TRUE;
-
- ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx,
- need_trace ? &trace : NULL, &lmf, NULL, NULL);
- if (!ji) {
- g_warning ("Exception inside function without unwind info");
- g_assert_not_reached ();
- }
-
- if (ji != (gpointer)-1) {
- frame_count ++;
- //printf ("M: %s %p %p %d.\n", mono_method_full_name (ji->method, TRUE), jit_tls->end_of_stack, ctx->ebp, count);
-
- if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
- char *tmp, *strace;
-
- /*
- * Avoid overwriting the stack trace if the exception is
- * rethrown. Also avoid giant stack traces during a stack
- * overflow.
- */
- if (!initial_stack_trace && (frame_count < 1000)) {
- trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
-
- if (!mono_ex->stack_trace)
- strace = g_strdup ("");
- else
- strace = mono_string_to_utf8 (mono_ex->stack_trace);
-
- tmp = g_strdup_printf ("%s%s\n", strace, trace);
- g_free (strace);
-
- mono_ex->stack_trace = mono_string_new (domain, tmp);
-
- g_free (tmp);
- }
- }
-
- if (stack_overflow)
- free_stack = (guint8*)(MONO_CONTEXT_GET_BP (ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
- else
- free_stack = 0xffffff;
-
- /*
- * During stack overflow, wait till the unwinding frees some stack
- * space before running handlers/finalizers.
- */
- if ((free_stack > (64 * 1024)) && 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) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
- /* store the exception object int cfg->excvar */
- g_assert (ji->exvar_offset);
- *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
- }
-
- 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)))) {
- if (test_only) {
- if (mono_ex)
- mono_ex->trace_ips = glist_to_array (trace_ips);
- g_list_free (trace_ips);
- g_free (trace);
-
- if (gc_disabled)
- mono_gc_enable ();
- return TRUE;
- }
- if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
- 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);
- jit_tls->lmf = lmf;
- g_free (trace);
-
- if (gc_disabled)
- mono_gc_enable ();
- 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 != NULL && mono_trace_eval (ji->method))
- g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
- call_filter (ctx, ei->handler_start);
- }
-
- }
- }
- }
- }
-
- g_free (trace);
-
- *ctx = new_ctx;
-
- if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
- if (gc_disabled)
- mono_gc_enable ();
-
- if (!test_only) {
- jit_tls->lmf = lmf;
-
- if (IS_ON_SIGALTSTACK (jit_tls)) {
- /* Switch back to normal stack */
- if (stack_overflow)
- /* Free up some stack space */
- initial_ctx.SC_ESP += (64 * 1024);
- initial_ctx.SC_EIP = (unsigned int)jit_tls->abort_func;
- restore_context (&initial_ctx);
- }
- else
- jit_tls->abort_func (obj);
- g_assert_not_reached ();
- } else {
- if (mono_ex)
- mono_ex->trace_ips = glist_to_array (trace_ips);
- g_list_free (trace_ips);
- return FALSE;
- }
- }
- }
-
- g_assert_not_reached ();
+ return mono_handle_exception (sigctx, obj, test_only);
}
-
-
--- /dev/null
+/*
+ * mini-exceptions.c: generic exception support
+ *
+ * Authors:
+ * Dietmar Maurer (dietmar@ximian.com)
+ *
+ * (C) 2001 Ximian, Inc.
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <signal.h>
+#include <string.h>
+
+#include <mono/metadata/appdomain.h>
+#include <mono/metadata/tabledefs.h>
+#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"
+
+#define IS_ON_SIGALTSTACK(jit_tls) ((jit_tls) && ((guint8*)&(jit_tls) > (guint8*)(jit_tls)->signal_stack) && ((guint8*)&(jit_tls) < ((guint8*)(jit_tls)->signal_stack + (jit_tls)->signal_stack_size)))
+
+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;
+
+ if (ta == NULL) {
+ /* Exception is not thrown yet */
+ return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
+ }
+
+ 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, domain);
+
+ if (need_file_info) {
+ gchar *filename;
+
+ filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
+
+ sf->filename = filename? mono_string_new (domain, filename): NULL;
+ sf->column = 0;
+
+ g_free (filename);
+ }
+
+ mono_array_set (res, gpointer, i, sf);
+ }
+
+ return res;
+}
+
+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, NULL, &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, domain);
+
+ 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)
+{
+ 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, NULL, &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;
+
+ /* skip all wrappers ??*/
+ if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
+ ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
+ ji->method->wrapper_type == MONO_WRAPPER_REMOTING_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, domain);
+
+ if (need_file_info) {
+ gchar *filename;
+
+ filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
+
+ *file = filename? mono_string_new (domain, filename): NULL;
+ *column = 0;
+
+ g_free (filename);
+ }
+
+ return TRUE;
+}
+
+static MonoArray *
+glist_to_array (GList *list)
+{
+ MonoDomain *domain = mono_domain_get ();
+ MonoArray *res;
+ int len, i;
+
+ if (!list)
+ return NULL;
+
+ len = g_list_length (list);
+ res = mono_array_new (domain, mono_defaults.int_class, len);
+
+ for (i = 0; list; list = list->next, i++)
+ mono_array_set (res, gpointer, i, list->data);
+
+ return res;
+}
+
+/**
+ * mono_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_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
+{
+ MonoDomain *domain = mono_domain_get ();
+ MonoJitInfo *ji, rji;
+ static int (*call_filter) (MonoContext *, gpointer) = NULL;
+ static void (*restore_context) (struct sigcontext *);
+ MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+ MonoLMF *lmf = jit_tls->lmf;
+ GList *trace_ips = NULL;
+ MonoException *mono_ex;
+ gboolean stack_overflow = FALSE;
+ MonoContext initial_ctx;
+ int frame_count = 0;
+ gboolean gc_disabled = FALSE;
+ MonoString *initial_stack_trace;
+
+ /*
+ * This function might execute on an alternate signal stack, and Boehm GC
+ * can't handle that.
+ * Also, since the altstack is small, stack space intensive operations like
+ * JIT compilation should be avoided.
+ */
+ if (IS_ON_SIGALTSTACK (jit_tls)) {
+ /*
+ * FIXME: disabling/enabling GC while already on a signal stack might
+ * not be safe either.
+ */
+ /* Have to reenable it later */
+ gc_disabled = TRUE;
+ mono_gc_disable ();
+ }
+
+ 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;
+ }
+
+ /*
+ * Allocate a new exception object instead of the preconstructed ones.
+ * We can't do this in sigsegv_signal_handler, since GC is not yet
+ * disabled.
+ */
+ if (obj == domain->stack_overflow_ex) {
+ obj = mono_get_exception_stack_overflow ();
+ }
+ else if (obj == domain->null_reference_ex) {
+ obj = mono_get_exception_null_reference ();
+ }
+
+ if (mono_object_isinst (obj, mono_defaults.exception_class)) {
+ mono_ex = (MonoException*)obj;
+ initial_stack_trace = mono_ex->stack_trace;
+ } else {
+ mono_ex = NULL;
+ }
+
+ if (obj == domain->stack_overflow_ex)
+ stack_overflow = TRUE;
+
+ if (!call_filter)
+ call_filter = mono_arch_get_call_filter ();
+
+ if (!restore_context)
+ restore_context = mono_arch_get_restore_context ();
+
+ 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 != NULL)
+ g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
+ if (!mono_handle_exception (&ctx_cp, obj, TRUE)) {
+ if (mono_break_on_exc)
+ G_BREAKPOINT ();
+ mono_unhandled_exception (obj);
+ }
+ }
+
+ initial_ctx = *ctx;
+ memset (&rji, 0, sizeof (rji));
+
+ while (1) {
+ MonoContext new_ctx;
+ char *trace = NULL;
+ gboolean need_trace = FALSE;
+ guint32 free_stack;
+
+ if (test_only && (frame_count < 1000))
+ need_trace = TRUE;
+
+ ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx,
+ need_trace ? &trace : NULL, &lmf, NULL, NULL);
+ if (!ji) {
+ g_warning ("Exception inside function without unwind info");
+ g_assert_not_reached ();
+ }
+
+ if (ji != (gpointer)-1) {
+ frame_count ++;
+ //printf ("M: %s %p %p %d.\n", mono_method_full_name (ji->method, TRUE), jit_tls->end_of_stack, ctx->ebp, count);
+
+ if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
+ char *tmp, *strace;
+
+ /*
+ * Avoid overwriting the stack trace if the exception is
+ * rethrown. Also avoid giant stack traces during a stack
+ * overflow.
+ */
+ if (!initial_stack_trace && (frame_count < 1000)) {
+ trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
+
+ if (!mono_ex->stack_trace)
+ strace = g_strdup ("");
+ else
+ strace = mono_string_to_utf8 (mono_ex->stack_trace);
+
+ tmp = g_strdup_printf ("%s%s\n", strace, trace);
+ g_free (strace);
+
+ mono_ex->stack_trace = mono_string_new (domain, tmp);
+
+ g_free (tmp);
+ }
+ }
+
+ if (stack_overflow)
+ free_stack = (guint8*)(MONO_CONTEXT_GET_BP (ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
+ else
+ free_stack = 0xffffff;
+
+ /*
+ * During stack overflow, wait till the unwinding frees some stack
+ * space before running handlers/finalizers.
+ */
+ if ((free_stack > (64 * 1024)) && 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) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
+ /* store the exception object int cfg->excvar */
+ g_assert (ji->exvar_offset);
+ *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
+ }
+
+ 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)))) {
+ if (test_only) {
+ if (mono_ex)
+ mono_ex->trace_ips = glist_to_array (trace_ips);
+ g_list_free (trace_ips);
+ g_free (trace);
+
+ if (gc_disabled)
+ mono_gc_enable ();
+ return TRUE;
+ }
+ if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
+ 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);
+ jit_tls->lmf = lmf;
+ g_free (trace);
+
+ if (gc_disabled)
+ mono_gc_enable ();
+ 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 != NULL && mono_trace_eval (ji->method))
+ g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
+ call_filter (ctx, ei->handler_start);
+ }
+
+ }
+ }
+ }
+ }
+
+ g_free (trace);
+
+ *ctx = new_ctx;
+
+ if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
+ if (gc_disabled)
+ mono_gc_enable ();
+
+ if (!test_only) {
+ jit_tls->lmf = lmf;
+
+ if (IS_ON_SIGALTSTACK (jit_tls)) {
+ /* Switch back to normal stack */
+ if (stack_overflow)
+ /* Free up some stack space */
+ initial_ctx.SC_ESP += (64 * 1024);
+ initial_ctx.SC_EIP = (unsigned int)jit_tls->abort_func;
+ restore_context (&initial_ctx);
+ }
+ else
+ jit_tls->abort_func (obj);
+ g_assert_not_reached ();
+ } else {
+ if (mono_ex)
+ mono_ex->trace_ips = glist_to_array (trace_ips);
+ g_list_free (trace_ips);
+ return FALSE;
+ }
+ }
+ }
+
+ g_assert_not_reached ();
+}
typedef struct MonoCompileArch {
} MonoCompileArch;
+#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))
+
#ifndef PLATFORM_WIN32
#ifdef HAVE_WORKING_SIGALTSTACK
#define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
-gboolean mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
gboolean mono_arch_print_tree(MonoInst *tree, int arity);
static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
static gpointer mono_jit_compile_method (MonoMethod *method);
void mono_arch_allocate_vars (MonoCompile *m);
int mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info);
gboolean mono_arch_print_tree (MonoInst *tree, int arity);
+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);
+gpointer mono_arch_get_call_filter (void);
+gpointer mono_arch_get_restore_context (void);
+gboolean mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only);
+
+/* Exception handling */
+gboolean mono_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only);
void mono_jit_walk_stack (MonoStackWalk func, gpointer user_data);
MonoArray *ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info);
MonoBoolean ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,