Implement the runtime side of disabling performance counters.
[mono-project.git] / mono / mini / mini-exceptions.c
blob2ef291da1ae91165fd20c91a6a652708d72f2db4
1 /*
2 * mini-exceptions.c: generic exception support
4 * Authors:
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Mono Team (mono-list@lists.ximian.com)
8 * Copyright 2001-2003 Ximian, Inc.
9 * Copyright 2003-2008 Novell, Inc.
10 * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
13 #include <config.h>
14 #include <glib.h>
15 #include <signal.h>
16 #include <string.h>
18 #ifdef HAVE_EXECINFO_H
19 #include <execinfo.h>
20 #endif
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
26 #ifdef HAVE_SYS_WAIT_H
27 #include <sys/wait.h>
28 #endif
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
34 #ifdef HAVE_SYS_SYSCALL_H
35 #include <sys/syscall.h>
36 #endif
38 #include <mono/metadata/appdomain.h>
39 #include <mono/metadata/tabledefs.h>
40 #include <mono/metadata/threads.h>
41 #include <mono/metadata/threads-types.h>
42 #include <mono/metadata/debug-helpers.h>
43 #include <mono/metadata/exception.h>
44 #include <mono/metadata/gc-internal.h>
45 #include <mono/metadata/mono-debug.h>
46 #include <mono/metadata/profiler.h>
47 #include <mono/metadata/mono-endian.h>
48 #include <mono/metadata/environment.h>
49 #include <mono/utils/mono-mmap.h>
51 #include "mini.h"
52 #include "debug-mini.h"
53 #include "trace.h"
54 #include "debugger-agent.h"
56 #ifndef MONO_ARCH_CONTEXT_DEF
57 #define MONO_ARCH_CONTEXT_DEF
58 #endif
60 static gpointer restore_context_func, call_filter_func;
61 static gpointer throw_exception_func, rethrow_exception_func;
62 static gpointer throw_corlib_exception_func;
64 static gpointer try_more_restore_tramp = NULL;
65 static gpointer restore_stack_protection_tramp = NULL;
67 static MonoUnhandledExceptionFunc unhandled_exception_hook = NULL;
68 static gpointer unhandled_exception_hook_data = NULL;
70 static void try_more_restore (void);
71 static void restore_stack_protection (void);
72 static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data);
73 static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx);
74 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
76 void
77 mono_exceptions_init (void)
79 MonoRuntimeExceptionHandlingCallbacks cbs;
80 if (mono_aot_only) {
81 restore_context_func = mono_aot_get_trampoline ("restore_context");
82 call_filter_func = mono_aot_get_trampoline ("call_filter");
83 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
84 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
85 } else {
86 MonoTrampInfo *info;
88 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
89 if (info) {
90 mono_save_trampoline_xdebug_info (info);
91 mono_tramp_info_free (info);
93 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
94 if (info) {
95 mono_save_trampoline_xdebug_info (info);
96 mono_tramp_info_free (info);
98 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
99 if (info) {
100 mono_save_trampoline_xdebug_info (info);
101 mono_tramp_info_free (info);
103 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
104 if (info) {
105 mono_save_trampoline_xdebug_info (info);
106 mono_tramp_info_free (info);
109 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
110 try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
111 restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
112 #endif
114 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
115 mono_arch_exceptions_init ();
116 #endif
117 cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
118 cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
119 cbs.mono_raise_exception = mono_get_throw_exception ();
120 cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
121 cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
122 mono_install_eh_callbacks (&cbs);
125 gpointer
126 mono_get_throw_exception (void)
128 g_assert (throw_exception_func);
129 return throw_exception_func;
132 gpointer
133 mono_get_rethrow_exception (void)
135 g_assert (rethrow_exception_func);
136 return rethrow_exception_func;
139 gpointer
140 mono_get_call_filter (void)
142 g_assert (call_filter_func);
143 return call_filter_func;
146 gpointer
147 mono_get_restore_context (void)
149 g_assert (restore_context_func);
150 return restore_context_func;
153 gpointer
154 mono_get_throw_corlib_exception (void)
156 gpointer code = NULL;
157 MonoTrampInfo *info;
159 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
160 if (throw_corlib_exception_func)
161 return throw_corlib_exception_func;
163 if (mono_aot_only)
164 code = mono_aot_get_trampoline ("throw_corlib_exception");
165 else {
166 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
167 if (info) {
168 mono_save_trampoline_xdebug_info (info);
169 mono_tramp_info_free (info);
173 mono_memory_barrier ();
175 throw_corlib_exception_func = code;
177 return throw_corlib_exception_func;
180 static gboolean
181 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
183 MonoTryBlockHoleTableJitInfo *table;
184 int i;
185 guint32 offset;
186 guint16 clause;
188 if (ei->try_start > ip || ip >= ei->try_end)
189 return FALSE;
191 if (!ji->has_try_block_holes)
192 return TRUE;
194 table = mono_jit_info_get_try_block_hole_table_info (ji);
195 offset = (guint32)((char*)ip - (char*)ji->code_start);
196 clause = (guint16)(ei - ji->clauses);
197 g_assert (clause < ji->num_clauses);
199 for (i = 0; i < table->num_holes; ++i) {
200 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
201 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
202 return FALSE;
204 return TRUE;
208 * find_jit_info:
210 * Translate between the mono_arch_find_jit_info function and the old API.
212 static MonoJitInfo *
213 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
214 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
216 StackFrameInfo frame;
217 MonoJitInfo *ji;
218 gboolean err;
219 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
221 /* Avoid costly table lookup during stack overflow */
222 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
223 ji = prev_ji;
224 else
225 ji = mini_jit_info_table_find (domain, ip, NULL);
227 if (managed)
228 *managed = FALSE;
230 err = mono_arch_find_jit_info (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
231 if (!err)
232 return (gpointer)-1;
234 /* Convert between the new and the old APIs */
235 switch (frame.type) {
236 case FRAME_TYPE_MANAGED:
237 if (managed)
238 *managed = TRUE;
239 return frame.ji;
240 case FRAME_TYPE_MANAGED_TO_NATIVE:
241 if (frame.ji)
242 return frame.ji;
243 else {
244 memset (res, 0, sizeof (MonoJitInfo));
245 res->method = frame.method;
246 return res;
248 case FRAME_TYPE_DEBUGGER_INVOKE: {
249 MonoContext tmp_ctx;
252 * The normal exception handling code can't handle this frame, so just
253 * skip it.
255 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
256 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
257 return ji;
259 default:
260 g_assert_not_reached ();
261 return NULL;
265 /* mono_find_jit_info:
267 * This function is used to gather information from @ctx. It return the
268 * MonoJitInfo of the corresponding function, unwinds one stack frame and
269 * stores the resulting context into @new_ctx. It also stores a string
270 * describing the stack location into @trace (if not NULL), and modifies
271 * the @lmf if necessary. @native_offset return the IP offset from the
272 * start of the function or -1 if that info is not available.
274 MonoJitInfo *
275 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
276 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
277 gboolean *managed)
279 gboolean managed2;
280 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
281 MonoJitInfo *ji;
283 if (trace)
284 *trace = NULL;
286 if (native_offset)
287 *native_offset = -1;
289 if (managed)
290 *managed = FALSE;
292 ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
294 if (ji == (gpointer)-1)
295 return ji;
297 if (managed2 || (ji && ji->method->wrapper_type)) {
298 const char *real_ip, *start;
299 gint32 offset;
301 start = (const char *)ji->code_start;
302 if (!managed2)
303 /* ctx->ip points into native code */
304 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
305 else
306 real_ip = (const char*)ip;
308 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
309 offset = real_ip - start;
310 else
311 offset = -1;
313 if (native_offset)
314 *native_offset = offset;
316 if (managed)
317 if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
318 *managed = TRUE;
320 if (trace)
321 *trace = mono_debug_print_stack_frame (ji->method, offset, domain);
322 } else {
323 if (trace) {
324 char *fname = mono_method_full_name (res->method, TRUE);
325 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
326 g_free (fname);
330 return ji;
334 * mono_find_jit_info_ext:
336 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
337 * structure.
338 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
339 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
340 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
341 * to obtain the last managed frame.
342 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
343 * On return, it will be filled with the locations where callee saved registers are saved
344 * by the current frame. This is returned outside of StackFrameInfo because it can be
345 * quite large on some platforms.
347 gboolean
348 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
349 MonoJitInfo *prev_ji, MonoContext *ctx,
350 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
351 mgreg_t **save_locations,
352 StackFrameInfo *frame)
354 gboolean err;
355 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
356 MonoJitInfo *ji;
357 MonoDomain *target_domain;
359 if (trace)
360 *trace = NULL;
362 /* Avoid costly table lookup during stack overflow */
363 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
364 ji = prev_ji;
365 else
366 ji = mini_jit_info_table_find (domain, ip, &target_domain);
368 if (!target_domain)
369 target_domain = domain;
371 if (save_locations)
372 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (mgreg_t*));
374 err = mono_arch_find_jit_info (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
375 if (!err)
376 return FALSE;
378 if (frame->type == FRAME_TYPE_MANAGED) {
379 if (!frame->ji->method->wrapper_type || frame->ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
380 frame->managed = TRUE;
383 if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
385 * This type of frame is just a marker, the caller should unwind once more to get the
386 * last managed frame.
388 frame->ji = NULL;
389 frame->method = NULL;
392 frame->native_offset = -1;
393 frame->domain = target_domain;
395 ji = frame->ji;
397 if (frame->type == FRAME_TYPE_MANAGED)
398 frame->method = ji->method;
400 if (ji && (frame->managed || ji->method->wrapper_type)) {
401 const char *real_ip, *start;
403 start = (const char *)ji->code_start;
404 if (!frame->managed)
405 /* ctx->ip points into native code */
406 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
407 else
408 real_ip = (const char*)ip;
410 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
411 frame->native_offset = real_ip - start;
412 else
413 frame->native_offset = -1;
415 if (trace)
416 *trace = mono_debug_print_stack_frame (ji->method, frame->native_offset, domain);
417 } else {
418 if (trace && frame->method) {
419 char *fname = mono_method_full_name (frame->method, TRUE);
420 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
421 g_free (fname);
425 return TRUE;
428 static gpointer
429 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
431 MonoGenericJitInfo *gi;
432 gpointer info;
434 if (!ji->has_generic_jit_info)
435 return NULL;
436 gi = mono_jit_info_get_generic_jit_info (ji);
437 if (!gi->has_this)
438 return NULL;
440 info = NULL;
442 * Search location list if available, it contains the precise location of the
443 * argument for every pc offset, even if the method was interrupted while it was in
444 * its prolog.
446 if (gi->nlocs) {
447 int offset = (mgreg_t)MONO_CONTEXT_GET_IP (ctx) - (mgreg_t)ji->code_start;
448 int i;
450 for (i = 0; i < gi->nlocs; ++i) {
451 MonoDwarfLocListEntry *entry = &gi->locations [i];
453 if (offset >= entry->from && (offset < entry->to || entry->to == 0)) {
454 if (entry->is_reg)
455 info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg);
456 else
457 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset);
458 break;
461 g_assert (i < gi->nlocs);
462 } else {
463 if (gi->this_in_reg)
464 info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg);
465 else
466 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
467 gi->this_offset);
470 if (mono_method_get_context (ji->method)->method_inst) {
471 return info;
472 } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
473 return info;
474 } else {
475 /* Avoid returning a managed object */
476 MonoObject *this_obj = info;
478 return this_obj->vtable->klass;
482 static MonoGenericContext
483 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
485 MonoGenericContext context = { NULL, NULL };
486 MonoClass *class, *method_container_class;
488 g_assert (generic_info);
490 g_assert (ji->method->is_inflated);
491 if (mono_method_get_context (ji->method)->method_inst) {
492 MonoMethodRuntimeGenericContext *mrgctx = generic_info;
494 class = mrgctx->class_vtable->klass;
495 context.method_inst = mrgctx->method_inst;
496 g_assert (context.method_inst);
497 } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
498 MonoVTable *vtable = generic_info;
500 class = vtable->klass;
501 } else {
502 class = generic_info;
505 //g_assert (!ji->method->klass->generic_container);
506 if (ji->method->klass->generic_class)
507 method_container_class = ji->method->klass->generic_class->container_class;
508 else
509 method_container_class = ji->method->klass;
511 /* class might refer to a subclass of ji->method's class */
512 while (!(class == ji->method->klass || (class->generic_class && class->generic_class->container_class == method_container_class))) {
513 class = class->parent;
514 g_assert (class);
517 if (class->generic_class || class->generic_container)
518 context.class_inst = mini_class_get_context (class)->class_inst;
520 if (class->generic_class)
521 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class->container_class, method_container_class));
522 else
523 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class));
525 return context;
528 static MonoMethod*
529 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
531 MonoGenericContext context;
532 MonoMethod *method;
534 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
535 return ji->method;
536 context = get_generic_context_from_stack_frame (ji, generic_info);
538 method = mono_method_get_declaring_generic_method (ji->method);
539 method = mono_class_inflate_generic_method (method, &context);
541 return method;
544 MonoString *
545 ves_icall_System_Exception_get_trace (MonoException *ex)
547 MonoDomain *domain = mono_domain_get ();
548 MonoString *res;
549 MonoArray *ta = ex->trace_ips;
550 int i, len;
551 GString *trace_str;
553 if (ta == NULL)
554 /* Exception is not thrown yet */
555 return NULL;
557 len = mono_array_length (ta) >> 1;
558 trace_str = g_string_new ("");
559 for (i = 0; i < len; i++) {
560 MonoJitInfo *ji;
561 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
562 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
564 ji = mono_jit_info_table_find (domain, ip);
565 if (ji == NULL) {
566 /* Unmanaged frame */
567 g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
568 } else {
569 gchar *location;
570 gint32 address;
571 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
573 address = (char *)ip - (char *)ji->code_start;
574 location = mono_debug_print_stack_frame (
575 method, address, ex->object.vtable->domain);
577 g_string_append_printf (trace_str, "%s\n", location);
578 g_free (location);
582 res = mono_string_new (ex->object.vtable->domain, trace_str->str);
583 g_string_free (trace_str, TRUE);
585 return res;
588 MonoArray *
589 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
591 MonoDomain *domain = mono_domain_get ();
592 MonoArray *res;
593 MonoArray *ta = exc->trace_ips;
594 MonoDebugSourceLocation *location;
595 int i, len;
597 if (ta == NULL) {
598 /* Exception is not thrown yet */
599 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
602 len = mono_array_length (ta) >> 1;
604 res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
606 for (i = skip; i < len; i++) {
607 MonoJitInfo *ji;
608 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
609 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
610 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
611 MonoMethod *method;
613 ji = mono_jit_info_table_find (domain, ip);
614 if (ji == NULL) {
615 /* Unmanaged frame */
616 mono_array_setref (res, i, sf);
617 continue;
620 g_assert (ji != NULL);
622 method = get_method_from_stack_frame (ji, generic_info);
623 if (ji->method->wrapper_type) {
624 char *s;
626 sf->method = NULL;
627 s = mono_method_full_name (method, TRUE);
628 MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
629 g_free (s);
631 else
632 MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
633 sf->native_offset = (char *)ip - (char *)ji->code_start;
636 * mono_debug_lookup_source_location() returns both the file / line number information
637 * and the IL offset. Note that computing the IL offset is already an expensive
638 * operation, so we shouldn't call this method twice.
640 location = mono_debug_lookup_source_location (ji->method, sf->native_offset, domain);
641 if (location)
642 sf->il_offset = location->il_offset;
643 else
644 sf->il_offset = 0;
646 if (need_file_info) {
647 if (location && location->source_file) {
648 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
649 sf->line = location->row;
650 sf->column = location->column;
651 } else {
652 sf->line = sf->column = 0;
653 sf->filename = NULL;
657 mono_debug_free_source_location (location);
658 mono_array_setref (res, i, sf);
661 return res;
664 static void
665 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
667 if (!start_ctx) {
668 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
669 if (jit_tls && jit_tls->orig_ex_ctx_set)
670 start_ctx = &jit_tls->orig_ex_ctx;
672 mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
675 * mono_walk_stack_with_ctx:
677 * Unwind the current thread starting at @start_ctx.
679 * If @start_ctx is null, we capture the current context.
681 void
682 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
684 MonoContext extra_ctx;
685 MonoInternalThread *thread = mono_thread_internal_current ();
686 MONO_ARCH_CONTEXT_DEF
688 if (!thread || !thread->jit_data)
689 return;
691 if (!start_ctx) {
692 mono_arch_flush_register_windows ();
694 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
695 MONO_INIT_CONTEXT_FROM_CURRENT (&extra_ctx);
696 #else
697 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
698 #endif
699 start_ctx = &extra_ctx;
702 mono_walk_stack_full (func, start_ctx, mono_domain_get (), thread->jit_data, mono_get_lmf (), unwind_options, user_data);
706 * mono_walk_stack_with_state:
708 * Unwind a thread described by @state.
710 * State must be valid (state->valid == TRUE).
712 * If you are using this function to unwind another thread, make sure it is suspended.
714 * If @state is null, we capture the current context.
716 void
717 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
719 MonoThreadUnwindState extra_state;
720 if (!state) {
721 if (!mono_thread_state_init_from_current (&extra_state))
722 return;
723 state = &extra_state;
726 g_assert (state->valid);
728 mono_walk_stack_full (func,
729 &state->ctx,
730 state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
731 state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
732 state->unwind_data [MONO_UNWIND_DATA_LMF],
733 unwind_options, user_data);
736 void
737 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
739 MonoThreadUnwindState state;
740 if (!mono_thread_state_init_from_current (&state))
741 return;
742 mono_walk_stack_with_state (func, &state, options, user_data);
746 * mono_walk_stack_full:
747 * @func: callback to call for each stack frame
748 * @domain: starting appdomain, can be NULL to use the current domain
749 * @unwind_options: what extra information the unwinder should gather
750 * @start_ctx: starting state of the stack walk, can be NULL.
751 * @thread: the thread whose stack to walk, can be NULL to use the current thread
752 * @lmf: the LMF of @thread, can be NULL to use the LMF of the current thread
753 * @user_data: data passed to the callback
755 * This function walks the stack of a thread, starting from the state
756 * represented by start_ctx. For each frame the callback
757 * function is called with the relevant info. The walk ends when no more
758 * managed stack frames are found or when the callback returns a TRUE value.
760 static void
761 mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data)
763 gint il_offset, i;
764 MonoContext ctx, new_ctx;
765 StackFrameInfo frame;
766 gboolean res;
767 mgreg_t *reg_locations [MONO_MAX_IREGS];
768 mgreg_t *new_reg_locations [MONO_MAX_IREGS];
769 gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
771 g_assert (start_ctx);
772 g_assert (domain);
773 g_assert (jit_tls);
774 /*The LMF will be null if the target have no managed frames.*/
775 /* g_assert (lmf); */
777 memcpy (&ctx, start_ctx, sizeof (MonoContext));
778 memset (reg_locations, 0, sizeof (reg_locations));
780 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
781 frame.lmf = lmf;
782 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
783 if (!res)
784 return;
786 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) {
787 MonoDebugSourceLocation *source;
789 source = mono_debug_lookup_source_location (frame.ji->method, frame.native_offset, domain);
790 il_offset = source ? source->il_offset : -1;
791 mono_debug_free_source_location (source);
792 } else
793 il_offset = -1;
795 frame.il_offset = il_offset;
797 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) {
798 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
799 } else {
800 frame.actual_method = frame.method;
803 if (get_reg_locations)
804 frame.reg_locations = reg_locations;
806 if (func (&frame, &ctx, user_data))
807 return;
809 if (get_reg_locations) {
810 for (i = 0; i < MONO_MAX_IREGS; ++i)
811 if (new_reg_locations [i])
812 reg_locations [i] = new_reg_locations [i];
815 ctx = new_ctx;
819 MonoBoolean
820 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
821 MonoReflectionMethod **method,
822 gint32 *iloffset, gint32 *native_offset,
823 MonoString **file, gint32 *line, gint32 *column)
825 MonoDomain *domain = mono_domain_get ();
826 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
827 MonoLMF *lmf = mono_get_lmf ();
828 MonoJitInfo *ji = NULL;
829 MonoContext ctx, new_ctx;
830 MonoDebugSourceLocation *location;
831 MonoMethod *actual_method;
832 StackFrameInfo frame;
833 gboolean res;
835 MONO_ARCH_CONTEXT_DEF;
837 mono_arch_flush_register_windows ();
839 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
840 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
841 #else
842 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
843 #endif
845 new_ctx = ctx;
846 do {
847 ctx = new_ctx;
848 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
849 if (!res)
850 return FALSE;
852 if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || frame.type == FRAME_TYPE_DEBUGGER_INVOKE)
853 continue;
855 ji = frame.ji;
856 *native_offset = frame.native_offset;
858 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
859 if (ji->method->wrapper_type != MONO_WRAPPER_NONE && ji->method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && ji->method->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
860 continue;
861 skip--;
862 } while (skip >= 0);
864 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
866 mono_gc_wbarrier_generic_store (method, (MonoObject*) mono_method_get_object (domain, actual_method, NULL));
868 location = mono_debug_lookup_source_location (ji->method, *native_offset, domain);
869 if (location)
870 *iloffset = location->il_offset;
871 else
872 *iloffset = 0;
874 if (need_file_info) {
875 if (location) {
876 mono_gc_wbarrier_generic_store (file, (MonoObject*) mono_string_new (domain, location->source_file));
877 *line = location->row;
878 *column = location->column;
879 } else {
880 *file = NULL;
881 *line = *column = 0;
885 mono_debug_free_source_location (location);
887 return TRUE;
890 typedef struct {
891 guint32 skips;
892 MonoSecurityFrame *frame;
893 } MonoFrameSecurityInfo;
895 static gboolean
896 callback_get_first_frame_security_info (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
898 MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
899 MonoJitInfo *ji = frame->ji;
901 if (!ji)
902 return FALSE;
904 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
905 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
906 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
907 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
908 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
909 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
910 return FALSE;
913 if (si->skips > 0) {
914 si->skips--;
915 return FALSE;
918 si->frame = mono_declsec_create_frame (frame->domain, ji);
920 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
921 return TRUE;
925 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
926 * @skip: the number of stack frames to skip
928 * This function returns a the security informations of a single stack frame
929 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
930 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
931 * evaluated.
933 MonoSecurityFrame*
934 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
936 MonoFrameSecurityInfo si;
938 si.skips = skip;
939 si.frame = NULL;
941 mono_walk_stack (callback_get_first_frame_security_info, MONO_UNWIND_DEFAULT, &si);
943 return (si.skips == 0) ? si.frame : NULL;
947 typedef struct {
948 guint32 skips;
949 MonoArray *stack;
950 guint32 count;
951 guint32 maximum;
952 } MonoSecurityStack;
954 static void
955 grow_array (MonoSecurityStack *stack)
957 MonoDomain *domain = mono_domain_get ();
958 guint32 newsize = (stack->maximum << 1);
959 MonoArray *newstack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, newsize);
960 int i;
961 for (i=0; i < stack->maximum; i++) {
962 gpointer frame = mono_array_get (stack->stack, gpointer, i);
963 mono_array_setref (newstack, i, frame);
965 stack->maximum = newsize;
966 stack->stack = newstack;
969 static gboolean
970 callback_get_stack_frames_security_info (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
972 MonoSecurityStack *ss = (MonoSecurityStack*) data;
973 MonoJitInfo *ji = frame->ji;
975 if (!ji)
976 return FALSE;
978 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
979 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
980 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
981 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
982 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
983 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
984 return FALSE;
987 if (ss->skips > 0) {
988 ss->skips--;
989 return FALSE;
992 if (ss->count == ss->maximum)
993 grow_array (ss);
995 mono_array_setref (ss->stack, ss->count++, mono_declsec_create_frame (frame->domain, ji));
997 /* continue down the stack */
998 return FALSE;
1001 static MonoArray *
1002 glist_to_array (GList *list, MonoClass *eclass)
1004 MonoDomain *domain = mono_domain_get ();
1005 MonoArray *res;
1006 int len, i;
1008 if (!list)
1009 return NULL;
1011 len = g_list_length (list);
1012 res = mono_array_new (domain, eclass, len);
1014 for (i = 0; list; list = list->next, i++)
1015 mono_array_set (res, gpointer, i, list->data);
1017 return res;
1021 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
1022 * @skip: the number of stack frames to skip
1024 * This function returns an managed array of containing the security
1025 * informations for each frame (after the skipped ones). This is used for
1026 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
1027 * required.
1029 MonoArray*
1030 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
1032 MonoSecurityStack ss;
1034 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
1035 skip--;
1036 #endif
1038 ss.skips = skip;
1039 ss.count = 0;
1040 ss.maximum = MONO_CAS_INITIAL_STACK_SIZE;
1041 ss.stack = mono_array_new (mono_domain_get (), mono_defaults.runtimesecurityframe_class, ss.maximum);
1042 mono_walk_stack (callback_get_stack_frames_security_info, MONO_UNWIND_DEFAULT, &ss);
1043 /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
1044 return ss.stack;
1047 static MonoClass*
1048 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1050 MonoClass *catch_class = ei->data.catch_class;
1051 MonoType *inflated_type;
1052 MonoGenericContext context;
1054 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1055 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
1056 return NULL;
1058 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1059 return catch_class;
1060 context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1062 /* FIXME: we shouldn't inflate but instead put the
1063 type in the rgctx and fetch it from there. It
1064 might be a good idea to do this lazily, i.e. only
1065 when the exception is actually thrown, so as not to
1066 waste space for exception clauses which might never
1067 be encountered. */
1068 inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
1069 catch_class = mono_class_from_mono_type (inflated_type);
1070 mono_metadata_free_type (inflated_type);
1072 return catch_class;
1076 * mini_jit_info_table_find:
1078 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1079 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1080 * OUT_DOMAIN if it is not NULL.
1082 MonoJitInfo*
1083 mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
1085 MonoJitInfo *ji;
1086 MonoInternalThread *t = mono_thread_internal_current ();
1087 gpointer *refs;
1089 if (out_domain)
1090 *out_domain = NULL;
1092 ji = mono_jit_info_table_find (domain, addr);
1093 if (ji) {
1094 if (out_domain)
1095 *out_domain = domain;
1096 return ji;
1099 /* maybe it is shared code, so we also search in the root domain */
1100 if (domain != mono_get_root_domain ()) {
1101 ji = mono_jit_info_table_find (mono_get_root_domain (), addr);
1102 if (ji) {
1103 if (out_domain)
1104 *out_domain = mono_get_root_domain ();
1105 return ji;
1109 refs = (t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL;
1110 for (; refs && *refs; refs++) {
1111 if (*refs != domain && *refs != mono_get_root_domain ()) {
1112 ji = mono_jit_info_table_find ((MonoDomain*) *refs, addr);
1113 if (ji) {
1114 if (out_domain)
1115 *out_domain = (MonoDomain*) *refs;
1116 return ji;
1121 return NULL;
1125 * wrap_non_exception_throws:
1127 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
1128 * WrapNonExceptionThrows flag set.
1130 static gboolean
1131 wrap_non_exception_throws (MonoMethod *m)
1133 MonoAssembly *ass = m->klass->image->assembly;
1134 MonoCustomAttrInfo* attrs;
1135 static MonoClass *klass;
1136 int i;
1137 gboolean val = FALSE;
1139 g_assert (ass);
1140 if (ass->wrap_non_exception_throws_inited)
1141 return ass->wrap_non_exception_throws;
1143 klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1145 attrs = mono_custom_attrs_from_assembly (ass);
1146 if (attrs) {
1147 for (i = 0; i < attrs->num_attrs; ++i) {
1148 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1149 const gchar *p;
1150 int len, num_named, named_type, data_type, name_len;
1151 char *name;
1153 if (!attr->ctor || attr->ctor->klass != klass)
1154 continue;
1155 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
1156 len = attr->data_size;
1157 p = (const char*)attr->data;
1158 g_assert (read16 (p) == 0x0001);
1159 p += 2;
1160 num_named = read16 (p);
1161 if (num_named != 1)
1162 continue;
1163 p += 2;
1164 named_type = *p;
1165 p ++;
1166 data_type = *p;
1167 p ++;
1168 /* Property */
1169 if (named_type != 0x54)
1170 continue;
1171 name_len = mono_metadata_decode_blob_size (p, &p);
1172 name = g_malloc (name_len + 1);
1173 memcpy (name, p, name_len);
1174 name [name_len] = 0;
1175 p += name_len;
1176 g_assert (!strcmp (name, "WrapNonExceptionThrows"));
1177 g_free (name);
1178 /* The value is a BOOLEAN */
1179 val = *p;
1181 mono_custom_attrs_free (attrs);
1184 ass->wrap_non_exception_throws = val;
1185 mono_memory_barrier ();
1186 ass->wrap_non_exception_throws_inited = TRUE;
1188 return val;
1191 #ifndef MONO_ARCH_STACK_GROWS_UP
1192 #define DOES_STACK_GROWS_UP 1
1193 #else
1194 #define DOES_STACK_GROWS_UP 0
1195 #endif
1197 #define MAX_UNMANAGED_BACKTRACE 128
1198 static MonoArray*
1199 build_native_trace (void)
1201 /* This puppy only makes sense on mobile, IOW, ARM. */
1202 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
1203 MonoArray *res;
1204 void *native_trace [MAX_UNMANAGED_BACKTRACE];
1205 int size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE);
1206 int i;
1208 if (!size)
1209 return NULL;
1210 res = mono_array_new (mono_domain_get (), mono_defaults.int_class, size);
1212 for (i = 0; i < size; i++)
1213 mono_array_set (res, gpointer, i, native_trace [i]);
1214 return res;
1215 #else
1216 return NULL;
1217 #endif
1220 #define setup_managed_stacktrace_information() do { \
1221 if (mono_ex && !initial_trace_ips) { \
1222 trace_ips = g_list_reverse (trace_ips); \
1223 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class)); \
1224 MONO_OBJECT_SETREF (mono_ex, native_trace_ips, build_native_trace ()); \
1225 if (has_dynamic_methods) \
1226 /* These methods could go away anytime, so compute the stack trace now */ \
1227 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex)); \
1229 g_list_free (trace_ips); \
1230 trace_ips = NULL; \
1231 } while (0)
1233 * mono_handle_exception_internal_first_pass:
1235 * The first pass of exception handling. Unwind the stack until a catch clause which can catch
1236 * OBJ is found. Run the index of the filter clause which caught the exception into
1237 * OUT_FILTER_IDX. Return TRUE if the exception is caught, FALSE otherwise.
1239 static gboolean
1240 mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoObject *non_exception)
1242 MonoDomain *domain = mono_domain_get ();
1243 MonoJitInfo *ji;
1244 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1245 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1246 MonoLMF *lmf = mono_get_lmf ();
1247 MonoArray *initial_trace_ips = NULL;
1248 GList *trace_ips = NULL;
1249 MonoException *mono_ex;
1250 gboolean stack_overflow = FALSE;
1251 MonoContext initial_ctx;
1252 int frame_count = 0;
1253 gboolean has_dynamic_methods = FALSE;
1254 gint32 filter_idx;
1255 int i;
1256 MonoObject *ex_obj;
1258 g_assert (ctx != NULL);
1260 if (obj == domain->stack_overflow_ex)
1261 stack_overflow = TRUE;
1263 mono_ex = (MonoException*)obj;
1264 initial_trace_ips = mono_ex->trace_ips;
1266 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1267 mono_ex = (MonoException*)obj;
1268 initial_trace_ips = mono_ex->trace_ips;
1269 } else {
1270 mono_ex = NULL;
1273 if (!call_filter)
1274 call_filter = mono_get_call_filter ();
1276 g_assert (jit_tls->end_of_stack);
1277 g_assert (jit_tls->abort_func);
1279 if (out_filter_idx)
1280 *out_filter_idx = -1;
1281 if (out_ji)
1282 *out_ji = NULL;
1283 filter_idx = 0;
1284 initial_ctx = *ctx;
1286 while (1) {
1287 MonoContext new_ctx;
1288 guint32 free_stack;
1289 int clause_index_start = 0;
1290 gboolean unwind_res = TRUE;
1292 StackFrameInfo frame;
1294 unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1295 if (unwind_res) {
1296 if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
1297 *ctx = new_ctx;
1298 continue;
1300 g_assert (frame.type == FRAME_TYPE_MANAGED);
1301 ji = frame.ji;
1304 if (!unwind_res) {
1305 setup_managed_stacktrace_information ();
1306 return FALSE;
1309 frame_count ++;
1310 //printf ("M: %s %d.\n", mono_method_full_name (ji->method, TRUE), frame_count);
1312 if (mini_get_debug_options ()->reverse_pinvoke_exceptions && ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
1313 g_error ("A native frame was found while unwinding the stack after an exception.\n"
1314 "The native frame called the managed method:\n%s\n",
1315 mono_method_full_name (ji->method, TRUE));
1318 if (ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1320 * Avoid overwriting the stack trace if the exception is
1321 * rethrown. Also avoid giant stack traces during a stack
1322 * overflow.
1324 if (!initial_trace_ips && (frame_count < 1000)) {
1325 trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1326 trace_ips = g_list_prepend (trace_ips,
1327 get_generic_info_from_stack_frame (ji, ctx));
1331 if (ji->method->dynamic)
1332 has_dynamic_methods = TRUE;
1334 if (stack_overflow) {
1335 if (DOES_STACK_GROWS_UP)
1336 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1337 else
1338 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1339 } else {
1340 free_stack = 0xffffff;
1343 for (i = clause_index_start; i < ji->num_clauses; i++) {
1344 MonoJitExceptionInfo *ei = &ji->clauses [i];
1345 gboolean filtered = FALSE;
1348 * During stack overflow, wait till the unwinding frees some stack
1349 * space before running handlers/finalizers.
1351 if (free_stack <= (64 * 1024))
1352 continue;
1354 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1355 /* catch block */
1356 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1359 * Have to unwrap RuntimeWrappedExceptions if the
1360 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1362 if (non_exception && !wrap_non_exception_throws (ji->method))
1363 ex_obj = non_exception;
1364 else
1365 ex_obj = obj;
1367 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1368 gboolean is_user_frame = ji->method->wrapper_type == MONO_WRAPPER_NONE || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD;
1369 #ifndef DISABLE_PERFCOUNTERS
1370 mono_perfcounters->exceptions_filters++;
1371 #endif
1372 mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1375 Here's the thing, if this is a filter clause done by a wrapper like runtime invoke, we don't want to
1376 trim the stackframe since if it returns FALSE we lose information.
1378 FIXME Not 100% sure if it's a good idea even with user clauses.
1380 if (is_user_frame)
1381 setup_managed_stacktrace_information ();
1383 if (ji->from_llvm) {
1384 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1385 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1386 #else
1387 g_assert_not_reached ();
1388 #endif
1389 } else {
1390 /* store the exception object in bp + ei->exvar_offset */
1391 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1394 mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx);
1395 filtered = call_filter (ctx, ei->data.filter);
1396 mono_debugger_agent_end_exception_filter (mono_ex, ctx, &initial_ctx);
1397 if (filtered && out_filter_idx)
1398 *out_filter_idx = filter_idx;
1399 if (out_ji)
1400 *out_ji = ji;
1401 filter_idx ++;
1403 if (filtered) {
1404 if (!is_user_frame)
1405 setup_managed_stacktrace_information ();
1406 /* mono_debugger_agent_handle_exception () needs this */
1407 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1408 return TRUE;
1412 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (ex_obj, catch_class)) {
1413 setup_managed_stacktrace_information ();
1415 if (out_ji)
1416 *out_ji = ji;
1418 /* mono_debugger_agent_handle_exception () needs this */
1419 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1420 return TRUE;
1425 *ctx = new_ctx;
1428 g_assert_not_reached ();
1432 * mono_handle_exception_internal:
1433 * @ctx: saved processor state
1434 * @obj: the exception object
1435 * @resume: whenever to resume unwinding based on the state in MonoJitTlsData.
1437 static gboolean
1438 mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gboolean resume, MonoJitInfo **out_ji)
1440 MonoDomain *domain = mono_domain_get ();
1441 MonoJitInfo *ji;
1442 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1443 static void (*restore_context) (void *);
1444 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1445 MonoLMF *lmf = mono_get_lmf ();
1446 MonoException *mono_ex;
1447 gboolean stack_overflow = FALSE;
1448 MonoContext initial_ctx;
1449 int frame_count = 0;
1450 gint32 filter_idx, first_filter_idx;
1451 int i;
1452 MonoObject *ex_obj;
1453 MonoObject *non_exception = NULL;
1455 g_assert (ctx != NULL);
1456 if (!obj) {
1457 MonoException *ex = mono_get_exception_null_reference ();
1458 MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object"));
1459 obj = (MonoObject *)ex;
1463 * Allocate a new exception object instead of the preconstructed ones.
1465 if (obj == domain->stack_overflow_ex) {
1467 * It is not a good idea to try and put even more pressure on the little stack available.
1468 * obj = mono_get_exception_stack_overflow ();
1470 stack_overflow = TRUE;
1472 else if (obj == domain->null_reference_ex) {
1473 obj = mono_get_exception_null_reference ();
1476 if (!mono_object_isinst (obj, mono_defaults.exception_class)) {
1477 non_exception = obj;
1478 obj = mono_get_exception_runtime_wrapped (obj);
1481 mono_ex = (MonoException*)obj;
1483 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1484 mono_ex = (MonoException*)obj;
1485 } else {
1486 mono_ex = NULL;
1489 if (mono_ex && jit_tls->class_cast_from) {
1490 if (!strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) {
1491 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1492 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1493 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
1494 mono_ex->message = mono_string_new (domain, msg);
1495 g_free (from_name);
1496 g_free (to_name);
1497 g_free (msg);
1499 if (!strcmp (mono_ex->object.vtable->klass->name, "ArrayTypeMismatchException")) {
1500 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1501 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1502 char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
1503 mono_ex->message = mono_string_new (domain, msg);
1504 g_free (from_name);
1505 g_free (to_name);
1506 g_free (msg);
1510 if (!call_filter)
1511 call_filter = mono_get_call_filter ();
1513 if (!restore_context)
1514 restore_context = mono_get_restore_context ();
1516 g_assert (jit_tls->end_of_stack);
1517 g_assert (jit_tls->abort_func);
1520 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
1521 * end up being TRUE on any code path.
1523 memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
1525 if (!resume) {
1526 gboolean res;
1528 MonoContext ctx_cp = *ctx;
1529 if (mono_trace_is_enabled ()) {
1530 MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0);
1531 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message);
1532 MonoObject *message;
1533 const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
1534 char *msg = NULL;
1535 MonoObject *exc = NULL;
1536 if (get_message == NULL) {
1537 message = NULL;
1538 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
1539 message = NULL;
1540 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
1541 } else {
1542 message = mono_runtime_invoke (get_message, obj, NULL, &exc);
1545 if (msg == NULL) {
1546 msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
1548 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
1549 g_free (msg);
1550 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
1551 mono_print_thread_dump_from_ctx (ctx);
1553 jit_tls->orig_ex_ctx_set = TRUE;
1554 mono_profiler_exception_thrown (obj);
1555 jit_tls->orig_ex_ctx_set = FALSE;
1557 res = mono_handle_exception_internal_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, non_exception);
1559 if (!res) {
1560 if (mini_get_debug_options ()->break_on_exc)
1561 G_BREAKPOINT ();
1562 mono_debugger_agent_handle_exception (obj, ctx, NULL);
1564 if (mini_get_debug_options ()->suspend_on_unhandled) {
1565 fprintf (stderr, "Unhandled exception, suspending...");
1566 while (1)
1570 // FIXME: This runs managed code so it might cause another stack overflow when
1571 // we are handling a stack overflow
1572 mono_unhandled_exception (obj);
1573 } else {
1575 // Treat exceptions that are "handled" by mono_runtime_invoke() as unhandled.
1576 // See bug #669836.
1578 if (ji && ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)
1579 mono_debugger_agent_handle_exception (obj, ctx, NULL);
1580 else
1581 mono_debugger_agent_handle_exception (obj, ctx, &ctx_cp);
1585 if (out_ji)
1586 *out_ji = NULL;
1587 filter_idx = 0;
1588 initial_ctx = *ctx;
1590 while (1) {
1591 MonoContext new_ctx;
1592 guint32 free_stack;
1593 int clause_index_start = 0;
1594 gboolean unwind_res = TRUE;
1596 if (resume) {
1597 resume = FALSE;
1598 ji = jit_tls->resume_state.ji;
1599 new_ctx = jit_tls->resume_state.new_ctx;
1600 clause_index_start = jit_tls->resume_state.clause_index;
1601 lmf = jit_tls->resume_state.lmf;
1602 first_filter_idx = jit_tls->resume_state.first_filter_idx;
1603 filter_idx = jit_tls->resume_state.filter_idx;
1604 } else {
1605 StackFrameInfo frame;
1607 unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1608 if (unwind_res) {
1609 if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
1610 *ctx = new_ctx;
1611 continue;
1613 g_assert (frame.type == FRAME_TYPE_MANAGED);
1614 ji = frame.ji;
1618 if (!unwind_res) {
1619 *(mono_get_lmf_addr ()) = lmf;
1621 jit_tls->abort_func (obj);
1622 g_assert_not_reached ();
1625 frame_count ++;
1626 //printf ("M: %s %d.\n", mono_method_full_name (ji->method, TRUE), frame_count);
1628 if (stack_overflow) {
1629 if (DOES_STACK_GROWS_UP)
1630 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1631 else
1632 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1633 } else {
1634 free_stack = 0xffffff;
1637 for (i = clause_index_start; i < ji->num_clauses; i++) {
1638 MonoJitExceptionInfo *ei = &ji->clauses [i];
1639 gboolean filtered = FALSE;
1642 * During stack overflow, wait till the unwinding frees some stack
1643 * space before running handlers/finalizers.
1645 if (free_stack <= (64 * 1024))
1646 continue;
1648 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1649 /* catch block */
1650 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1653 * Have to unwrap RuntimeWrappedExceptions if the
1654 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1656 if (non_exception && !wrap_non_exception_throws (ji->method))
1657 ex_obj = non_exception;
1658 else
1659 ex_obj = obj;
1661 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
1662 if (ji->from_llvm) {
1663 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1664 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1665 #else
1666 g_assert_not_reached ();
1667 #endif
1668 } else {
1669 /* store the exception object in bp + ei->exvar_offset */
1670 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1674 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1676 * Filter clauses should only be run in the
1677 * first pass of exception handling.
1679 filtered = (filter_idx == first_filter_idx);
1680 filter_idx ++;
1683 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
1684 mono_object_isinst (ex_obj, catch_class)) || filtered) {
1686 * This guards against the situation that we abort a thread that is executing a finally clause
1687 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
1688 * check for this situation here and resume interruption if we are below the guarded block.
1690 if (G_UNLIKELY (jit_tls->handler_block_return_address)) {
1691 gboolean is_outside = FALSE;
1692 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
1693 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
1694 //FIXME make this stack direction aware
1695 if (catch_bp > prot_bp) {
1696 is_outside = TRUE;
1697 } else if (catch_bp == prot_bp) {
1698 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
1699 * So we check if the catch handler_start is protected by the guarded handler protected region
1701 * Assumptions:
1702 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
1703 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
1704 * There aren't any further finally/fault handler blocks down the stack over this exception.
1705 * This must be ensured by the code that installs the guard trampoline.
1707 g_assert (ji == mini_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
1709 if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
1710 is_outside = TRUE;
1713 if (is_outside) {
1714 jit_tls->handler_block_return_address = NULL;
1715 jit_tls->handler_block = NULL;
1716 mono_thread_resume_interruption (); /*We ignore the exception here, it will be raised later*/
1720 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1721 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1722 jit_tls->orig_ex_ctx_set = TRUE;
1723 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1724 jit_tls->orig_ex_ctx_set = FALSE;
1725 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1726 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1727 *(mono_get_lmf_addr ()) = lmf;
1728 #ifndef DISABLE_PERFCOUNTERS
1729 mono_perfcounters->exceptions_depth += frame_count;
1730 #endif
1731 if (obj == domain->stack_overflow_ex)
1732 jit_tls->handling_stack_ovf = FALSE;
1734 return 0;
1736 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1737 (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
1738 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1739 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1740 jit_tls->orig_ex_ctx_set = TRUE;
1741 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1742 jit_tls->orig_ex_ctx_set = FALSE;
1743 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1744 call_filter (ctx, ei->handler_start);
1746 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1747 (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
1748 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1749 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1750 jit_tls->orig_ex_ctx_set = TRUE;
1751 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1752 jit_tls->orig_ex_ctx_set = FALSE;
1753 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1754 #ifndef DISABLE_PERFCOUNTERS
1755 mono_perfcounters->exceptions_finallys++;
1756 #endif
1757 *(mono_get_lmf_addr ()) = lmf;
1758 if (ji->from_llvm) {
1760 * LLVM compiled finally handlers follow the design
1761 * of the c++ ehabi, i.e. they call a resume function
1762 * at the end instead of returning to the caller.
1763 * So save the exception handling state,
1764 * mono_resume_unwind () will call us again to continue
1765 * the unwinding.
1767 jit_tls->resume_state.ex_obj = obj;
1768 jit_tls->resume_state.ji = ji;
1769 jit_tls->resume_state.clause_index = i + 1;
1770 jit_tls->resume_state.ctx = *ctx;
1771 jit_tls->resume_state.new_ctx = new_ctx;
1772 jit_tls->resume_state.lmf = lmf;
1773 jit_tls->resume_state.first_filter_idx = first_filter_idx;
1774 jit_tls->resume_state.filter_idx = filter_idx;
1775 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1776 return 0;
1777 } else {
1778 call_filter (ctx, ei->handler_start);
1784 jit_tls->orig_ex_ctx_set = TRUE;
1785 mono_profiler_exception_method_leave (ji->method);
1786 jit_tls->orig_ex_ctx_set = FALSE;
1788 *ctx = new_ctx;
1791 g_assert_not_reached ();
1795 * mono_debugger_handle_exception:
1797 * Notify the debugger about exceptions. Returns TRUE if the debugger wants us to stop
1798 * at the exception and FALSE to resume with the normal exception handling.
1800 * The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
1801 * MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
1802 * `callq throw' instruction.
1804 gboolean
1805 mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
1807 MonoDebuggerExceptionAction action;
1809 if (!mono_debug_using_mono_debugger ())
1810 return FALSE;
1812 if (!obj) {
1813 MonoException *ex = mono_get_exception_null_reference ();
1814 MONO_OBJECT_SETREF (ex, message, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
1815 obj = (MonoObject *)ex;
1818 action = _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1820 if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP) {
1822 * The debugger wants us to stop on the `throw' instruction.
1823 * By the time we get here, it already inserted a breakpoint there.
1825 return TRUE;
1826 } else if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED) {
1827 MonoContext ctx_cp = *ctx;
1828 MonoJitInfo *ji = NULL;
1829 gboolean ret;
1832 * The debugger wants us to stop only if this exception is user-unhandled.
1835 ret = mono_handle_exception_internal_first_pass (&ctx_cp, obj, NULL, &ji, NULL);
1836 if (ret && (ji != NULL) && (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
1838 * The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
1839 * inside the method being invoked, so we handle it like a user-unhandled exception.
1841 ret = FALSE;
1844 if (!ret) {
1846 * The exception is user-unhandled - tell the debugger to stop.
1848 return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1852 * The exception is catched somewhere - resume with the normal exception handling and don't
1853 * stop in the debugger.
1857 return FALSE;
1861 * mono_debugger_run_finally:
1862 * @start_ctx: saved processor state
1864 * This method is called by the Mono Debugger to call all `finally' clauses of the
1865 * current stack frame. It's used when the user issues a `return' command to make
1866 * the current stack frame return. After returning from this method, the debugger
1867 * unwinds the stack one frame and gives control back to the user.
1869 * NOTE: This method is only used when running inside the Mono Debugger.
1871 void
1872 mono_debugger_run_finally (MonoContext *start_ctx)
1874 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1875 MonoDomain *domain = mono_domain_get ();
1876 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1877 MonoLMF *lmf = mono_get_lmf ();
1878 MonoContext ctx, new_ctx;
1879 MonoJitInfo *ji, rji;
1880 int i;
1882 ctx = *start_ctx;
1884 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1885 if (!ji || ji == (gpointer)-1)
1886 return;
1888 if (!call_filter)
1889 call_filter = mono_get_call_filter ();
1891 for (i = 0; i < ji->num_clauses; i++) {
1892 MonoJitExceptionInfo *ei = &ji->clauses [i];
1894 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
1895 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1896 call_filter (&ctx, ei->handler_start);
1902 * mono_handle_exception:
1903 * @ctx: saved processor state
1904 * @obj: the exception object
1906 gboolean
1907 mono_handle_exception (MonoContext *ctx, gpointer obj)
1909 #ifndef DISABLE_PERFCOUNTERS
1910 mono_perfcounters->exceptions_thrown++;
1911 #endif
1913 return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
1916 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1918 #ifndef MONO_ARCH_USE_SIGACTION
1919 #error "Can't use sigaltstack without sigaction"
1920 #endif
1922 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1924 void
1925 mono_setup_altstack (MonoJitTlsData *tls)
1927 size_t stsize = 0;
1928 stack_t sa;
1929 guint8 *staddr = NULL;
1931 if (mono_running_on_valgrind ())
1932 return;
1934 mono_thread_get_stack_bounds (&staddr, &stsize);
1936 g_assert (staddr);
1938 tls->end_of_stack = staddr + stsize;
1939 tls->stack_size = stsize;
1941 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1943 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1944 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
1946 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
1948 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1949 /* mprotect can fail for the main thread stack */
1950 gpointer gaddr = mono_valloc (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON|MONO_MMAP_FIXED);
1951 g_assert (gaddr == tls->stack_ovf_guard_base);
1952 tls->stack_ovf_valloced = TRUE;
1955 /* Setup an alternate signal stack */
1956 tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
1957 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1959 g_assert (tls->signal_stack);
1961 sa.ss_sp = tls->signal_stack;
1962 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1963 #if __APPLE__
1964 sa.ss_flags = 0;
1965 #else
1966 sa.ss_flags = SS_ONSTACK;
1967 #endif
1968 g_assert (sigaltstack (&sa, NULL) == 0);
1970 mono_gc_register_altstack ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size, (char*)staddr + stsize - ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size), tls->signal_stack, tls->signal_stack_size);
1973 void
1974 mono_free_altstack (MonoJitTlsData *tls)
1976 stack_t sa;
1977 int err;
1979 sa.ss_sp = tls->signal_stack;
1980 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1981 sa.ss_flags = SS_DISABLE;
1982 err = sigaltstack (&sa, NULL);
1983 g_assert (err == 0);
1985 if (tls->signal_stack)
1986 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1987 if (tls->stack_ovf_valloced)
1988 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size);
1989 else
1990 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1993 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1995 void
1996 mono_setup_altstack (MonoJitTlsData *tls)
2000 void
2001 mono_free_altstack (MonoJitTlsData *tls)
2005 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
2007 static gboolean
2008 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
2010 gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
2011 /* we need to leave some room for throwing the exception */
2012 while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
2013 unprotect_size -= mono_pagesize ();
2014 /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
2015 * is sufficient stack
2017 //fprintf (stderr, "restoring stack protection: %p-%p (%d)\n", jit_tls->stack_ovf_guard_base, (char*)jit_tls->stack_ovf_guard_base + unprotect_size, unprotect_size);
2018 if (unprotect_size)
2019 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
2020 return unprotect_size == jit_tls->stack_ovf_guard_size;
2023 static G_GNUC_UNUSED void
2024 try_more_restore (void)
2026 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2027 if (try_restore_stack_protection (jit_tls, 500))
2028 jit_tls->restore_stack_prot = NULL;
2031 static G_GNUC_UNUSED void
2032 restore_stack_protection (void)
2034 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2035 MonoException *ex = mono_domain_get ()->stack_overflow_ex;
2036 /* if we can't restore the stack protection, keep a callback installed so
2037 * we'll try to restore as much stack as we can at each return from unmanaged
2038 * code.
2040 if (try_restore_stack_protection (jit_tls, 4096))
2041 jit_tls->restore_stack_prot = NULL;
2042 else
2043 jit_tls->restore_stack_prot = try_more_restore_tramp;
2044 /* here we also throw a stack overflow exception */
2045 ex->trace_ips = NULL;
2046 ex->stack_trace = NULL;
2047 mono_raise_exception (ex);
2050 gpointer
2051 mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
2053 void (*func)(void) = (gpointer)tramp_data;
2054 func ();
2055 return NULL;
2058 gboolean
2059 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
2061 /* we got a stack overflow in the soft-guard pages
2062 * There are two cases:
2063 * 1) managed code caused the overflow: we unprotect the soft-guard page
2064 * and let the arch-specific code trigger the exception handling mechanism
2065 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
2066 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
2067 * and hope we can continue with those enabled, at least until the hard-guard page
2068 * is hit. The alternative to continuing here is to just print a message and abort.
2069 * We may add in the future the code to protect the pages again in the codepath
2070 * when we return from unmanaged to managed code.
2072 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
2073 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
2074 /* we unprotect the minimum amount we can */
2075 guint32 guard_size;
2076 gboolean handled = FALSE;
2078 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
2079 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
2080 guard_size -= mono_pagesize ();
2082 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
2083 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
2084 mono_mprotect ((char*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size - guard_size, guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
2085 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2086 if (ji) {
2087 mono_arch_handle_altstack_exception (ctx, fault_addr, TRUE);
2088 handled = TRUE;
2090 #endif
2091 if (!handled) {
2092 /* We print a message: after this even managed stack overflows
2093 * may crash the runtime
2095 fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), fault_addr);
2096 if (!jit_tls->handling_stack_ovf) {
2097 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
2098 jit_tls->handling_stack_ovf = 1;
2099 } else {
2100 /*fprintf (stderr, "Already handling stack overflow\n");*/
2103 return TRUE;
2105 return FALSE;
2108 typedef struct {
2109 FILE *stream;
2110 MonoMethod *omethod;
2111 int count;
2112 } PrintOverflowUserData;
2114 static gboolean
2115 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2117 MonoMethod *method = NULL;
2118 PrintOverflowUserData *user_data = data;
2119 FILE *stream = user_data->stream;
2120 gchar *location;
2122 if (frame->ji)
2123 method = frame->ji->method;
2125 if (method) {
2126 if (user_data->count == 0) {
2127 /* The first frame is in its prolog, so a line number cannot be computed */
2128 user_data->count ++;
2129 return FALSE;
2132 /* If this is a one method overflow, skip the other instances */
2133 if (method == user_data->omethod)
2134 return FALSE;
2136 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2137 fprintf (stream, " %s\n", location);
2138 g_free (location);
2140 if (user_data->count == 1) {
2141 fprintf (stream, " <...>\n");
2142 user_data->omethod = method;
2143 } else {
2144 user_data->omethod = NULL;
2147 user_data->count ++;
2148 } else
2149 fprintf (stream, " at <unknown> <0x%05x>\n", frame->native_offset);
2151 return FALSE;
2154 void
2155 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
2157 PrintOverflowUserData ud;
2158 MonoContext mctx;
2160 /* we don't do much now, but we can warn the user with a useful message */
2161 fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), fault_addr);
2163 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2164 mono_arch_sigctx_to_monoctx (ctx, &mctx);
2166 fprintf (stderr, "Stacktrace:\n");
2168 memset (&ud, 0, sizeof (ud));
2169 ud.stream = stderr;
2171 mono_walk_stack_with_ctx (print_overflow_stack_frame, &mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
2172 #else
2173 if (ji && ji->method)
2174 fprintf (stderr, "At %s\n", mono_method_full_name (ji->method, TRUE));
2175 else
2176 fprintf (stderr, "At <unmanaged>.\n");
2177 #endif
2179 _exit (1);
2182 static gboolean
2183 print_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2185 FILE *stream = (FILE*)data;
2186 MonoMethod *method = NULL;
2187 if (frame->ji)
2188 method = frame->ji->method;
2190 if (method) {
2191 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2192 fprintf (stream, " %s\n", location);
2193 g_free (location);
2194 } else
2195 fprintf (stream, " at <unknown> <0x%05x>\n", frame->native_offset);
2197 return FALSE;
2200 static G_GNUC_UNUSED gboolean
2201 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2203 GString *p = (GString*)data;
2204 MonoMethod *method = NULL;
2205 if (frame->ji)
2206 method = frame->ji->method;
2208 if (method) {
2209 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2210 g_string_append_printf (p, " %s\n", location);
2211 g_free (location);
2212 } else
2213 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
2215 return FALSE;
2218 static gboolean handling_sigsegv = FALSE;
2221 * mono_handle_native_sigsegv:
2223 * Handle a SIGSEGV received while in native code by printing diagnostic
2224 * information and aborting.
2226 void
2227 mono_handle_native_sigsegv (int signal, void *ctx)
2229 #ifdef MONO_ARCH_USE_SIGACTION
2230 struct sigaction sa;
2231 #endif
2232 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2234 if (handling_sigsegv)
2235 return;
2237 if (mini_get_debug_options ()->suspend_on_sigsegv) {
2238 fprintf (stderr, "Received SIGSEGV, suspending...");
2239 while (1)
2243 /* To prevent infinite loops when the stack walk causes a crash */
2244 handling_sigsegv = TRUE;
2246 /* !jit_tls means the thread was not registered with the runtime */
2247 if (jit_tls && mono_thread_internal_current ()) {
2248 fprintf (stderr, "Stacktrace:\n\n");
2250 mono_walk_stack (print_stack_frame, TRUE, stderr);
2252 fflush (stderr);
2255 #ifdef HAVE_BACKTRACE_SYMBOLS
2257 void *array [256];
2258 char **names;
2259 int i, size;
2260 const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
2262 fprintf (stderr, "\nNative stacktrace:\n\n");
2264 size = backtrace (array, 256);
2265 names = backtrace_symbols (array, size);
2266 for (i =0; i < size; ++i) {
2267 fprintf (stderr, "\t%s\n", names [i]);
2269 free (names);
2271 fflush (stderr);
2273 /* Try to get more meaningful information using gdb */
2275 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
2276 if (!mini_get_debug_options ()->no_gdb_backtrace && !mono_debug_using_mono_debugger ()) {
2277 /* From g_spawn_command_line_sync () in eglib */
2278 pid_t pid;
2279 int status;
2280 pid_t crashed_pid = getpid ();
2282 //pid = fork ();
2284 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
2285 * it will deadlock. Call the syscall directly instead.
2287 pid = mono_runtime_syscall_fork ();
2289 if (pid == 0) {
2290 dup2 (STDERR_FILENO, STDOUT_FILENO);
2292 mono_gdb_render_native_backtraces (crashed_pid);
2293 exit (1);
2296 fprintf (stderr, "\nDebug info from gdb:\n\n");
2297 waitpid (pid, &status, 0);
2299 #endif
2301 * A SIGSEGV indicates something went very wrong so we can no longer depend
2302 * on anything working. So try to print out lots of diagnostics, starting
2303 * with ones which have a greater chance of working.
2305 fprintf (stderr,
2306 "\n"
2307 "=================================================================\n"
2308 "Got a %s while executing native code. This usually indicates\n"
2309 "a fatal error in the mono runtime or one of the native libraries \n"
2310 "used by your application.\n"
2311 "=================================================================\n"
2312 "\n", signal_str);
2315 #endif
2317 #ifdef MONO_ARCH_USE_SIGACTION
2319 /* Remove our SIGABRT handler */
2320 sa.sa_handler = SIG_DFL;
2321 sigemptyset (&sa.sa_mask);
2322 sa.sa_flags = 0;
2324 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
2326 #endif
2328 abort ();
2331 static void
2332 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
2334 MonoInternalThread *thread = mono_thread_internal_current ();
2335 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2336 MonoContext ctx;
2337 #endif
2338 GString* text = g_string_new (0);
2339 char *name, *wapi_desc;
2340 GError *error = NULL;
2342 if (thread->name) {
2343 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
2344 g_assert (!error);
2345 g_string_append_printf (text, "\n\"%s\"", name);
2346 g_free (name);
2348 else if (thread->threadpool_thread)
2349 g_string_append (text, "\n\"<threadpool thread>\"");
2350 else
2351 g_string_append (text, "\n\"<unnamed thread>\"");
2353 #ifndef HOST_WIN32
2354 wapi_desc = wapi_current_thread_desc ();
2355 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
2356 free (wapi_desc);
2357 #endif
2359 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2360 if (start_ctx) {
2361 memcpy (&ctx, start_ctx, sizeof (MonoContext));
2362 } else if (!sigctx)
2363 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
2364 else
2365 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
2367 mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
2368 #else
2369 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
2370 #endif
2372 fprintf (stdout, "%s", text->str);
2374 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
2375 OutputDebugStringA(text->str);
2376 #endif
2378 g_string_free (text, TRUE);
2379 fflush (stdout);
2383 * mono_print_thread_dump:
2385 * Print information about the current thread to stdout.
2386 * SIGCTX can be NULL, allowing this to be called from gdb.
2388 void
2389 mono_print_thread_dump (void *sigctx)
2391 mono_print_thread_dump_internal (sigctx, NULL);
2394 void
2395 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2397 mono_print_thread_dump_internal (NULL, ctx);
2401 * mono_resume_unwind:
2403 * This is called by a trampoline from LLVM compiled finally clauses to continue
2404 * unwinding.
2406 void
2407 mono_resume_unwind (MonoContext *ctx)
2409 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2410 static void (*restore_context) (MonoContext *);
2411 MonoContext new_ctx;
2413 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
2414 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
2415 new_ctx = *ctx;
2417 mono_handle_exception_internal (&new_ctx, jit_tls->resume_state.ex_obj, TRUE, NULL);
2419 if (!restore_context)
2420 restore_context = mono_get_restore_context ();
2422 restore_context (&new_ctx);
2425 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
2427 typedef struct {
2428 MonoJitInfo *ji;
2429 MonoContext ctx;
2430 MonoJitExceptionInfo *ei;
2431 } FindHandlerBlockData;
2433 static gboolean
2434 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2436 int i;
2437 gpointer ip;
2438 FindHandlerBlockData *pdata = data;
2439 MonoJitInfo *ji = frame->ji;
2441 if (!ji)
2442 return FALSE;
2444 if (ji->method->wrapper_type)
2445 return FALSE;
2447 ip = MONO_CONTEXT_GET_IP (ctx);
2449 for (i = 0; i < ji->num_clauses; ++i) {
2450 MonoJitExceptionInfo *ei = ji->clauses + i;
2451 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2452 continue;
2453 /*If ip points to the first instruction it means the handler block didn't start
2454 so we can leave its execution to the EH machinery*/
2455 if (ei->handler_start < ip && ip < ei->data.handler_end) {
2456 pdata->ji = ji;
2457 pdata->ei = ei;
2458 pdata->ctx = *ctx;
2459 break;
2462 return FALSE;
2466 static gpointer
2467 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
2469 int i;
2470 MonoJitExceptionInfo *clause = NULL;
2471 gpointer ip;
2473 ip = MONO_CONTEXT_GET_IP (ctx);
2475 for (i = 0; i < ji->num_clauses; ++i) {
2476 clause = &ji->clauses [i];
2477 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2478 continue;
2479 if (clause->handler_start < ip && clause->data.handler_end > ip)
2480 break;
2483 /*no matching finally */
2484 if (i == ji->num_clauses)
2485 return NULL;
2487 /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
2488 if (ip == clause->handler_start)
2489 return NULL;
2491 return mono_arch_install_handler_block_guard (ji, clause, ctx, mono_create_handler_block_trampoline ());
2495 * Finds the bottom handler block running and install a block guard if needed.
2496 * FIXME add full-aot support.
2498 gboolean
2499 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
2501 FindHandlerBlockData data = { 0 };
2502 MonoJitTlsData *jit_tls = ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
2503 gpointer resume_ip;
2505 /* FIXME */
2506 if (mono_aot_only)
2507 return FALSE;
2509 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
2510 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
2512 if (!jit_tls || jit_tls->handler_block_return_address)
2513 return FALSE;
2515 mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_SIGNAL_SAFE, &data);
2517 if (!data.ji)
2518 return FALSE;
2520 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
2522 resume_ip = install_handler_block_guard (data.ji, &data.ctx);
2523 if (resume_ip == NULL)
2524 return FALSE;
2526 jit_tls->handler_block_return_address = resume_ip;
2527 jit_tls->handler_block = data.ei;
2529 return TRUE;
2532 #else
2533 gboolean
2534 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
2536 return FALSE;
2539 #endif
2541 void
2542 mono_set_cast_details (MonoClass *from, MonoClass *to)
2544 MonoJitTlsData *jit_tls = NULL;
2546 if (mini_get_debug_options ()->better_cast_details) {
2547 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2548 jit_tls->class_cast_from = from;
2549 jit_tls->class_cast_to = to;
2554 /*returns false if the thread is not attached*/
2555 gboolean
2556 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
2558 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2559 MonoInternalThread *thread = mono_thread_internal_current ();
2560 if (!thread || !thread->jit_data) {
2561 ctx->valid = FALSE;
2562 return FALSE;
2565 if (sigctx)
2566 mono_arch_sigctx_to_monoctx (sigctx, &ctx->ctx);
2567 else
2568 #if MONO_ARCH_HAS_MONO_CONTEXT && !defined(MONO_CROSS_COMPILE)
2569 MONO_CONTEXT_GET_CURRENT (ctx->ctx);
2570 #else
2571 g_error ("Use a null sigctx requires a working mono-context");
2572 #endif
2574 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2575 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2576 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2577 ctx->valid = TRUE;
2578 return TRUE;
2579 #else
2580 g_error ("Implement mono_arch_sigctx_to_monoctx for the current target");
2581 return FALSE;
2582 #endif
2585 gboolean
2586 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
2588 MonoInternalThread *thread = mono_thread_internal_current ();
2589 if (!thread || !thread->jit_data) {
2590 ctx->valid = FALSE;
2591 return FALSE;
2594 ctx->ctx = *mctx;
2595 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2596 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2597 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2598 ctx->valid = TRUE;
2599 return TRUE;
2602 /*returns false if the thread is not attached*/
2603 gboolean
2604 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
2606 MonoInternalThread *thread = mono_thread_internal_current ();
2607 MONO_ARCH_CONTEXT_DEF
2609 mono_arch_flush_register_windows ();
2611 if (!thread || !thread->jit_data) {
2612 ctx->valid = FALSE;
2613 return FALSE;
2615 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
2616 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx->ctx);
2617 #else
2618 MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
2619 #endif
2621 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2622 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2623 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2624 ctx->valid = TRUE;
2625 return TRUE;
2628 static void
2629 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
2631 void (*restore_context) (MonoContext *);
2632 restore_context = mono_get_restore_context ();
2634 mono_handle_exception (ctx, exc);
2635 restore_context (ctx);
2638 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
2639 void
2640 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
2642 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
2643 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2644 jit_tls->ex_ctx = *ctx;
2646 mono_arch_setup_async_callback (ctx, async_cb, user_data);
2647 #else
2648 g_error ("This target doesn't support mono_arch_setup_async_callback");
2649 #endif
2652 void
2653 mono_install_unhandled_exception_hook (MonoUnhandledExceptionFunc func, gpointer user_data)
2655 unhandled_exception_hook = func;
2656 unhandled_exception_hook_data = user_data;
2659 void
2660 mono_invoke_unhandled_exception_hook (MonoObject *exc)
2662 if (unhandled_exception_hook) {
2663 unhandled_exception_hook (exc, unhandled_exception_hook_data);
2664 } else {
2665 MonoObject *other = NULL;
2666 MonoString *str = mono_object_to_string (exc, &other);
2667 if (str) {
2668 char *msg = mono_string_to_utf8 (str);
2669 fprintf (stderr, "[ERROR] FATAL UNHANDLED EXCEPTION: %s\n", msg);
2670 fflush (stderr);
2671 g_free (msg);
2674 exit (mono_environment_exitcode_get ());
2677 g_assert_not_reached ();