Merge pull request #444 from knocte/xbuild_improvements
[mono-project.git] / mono / mini / mini-exceptions.c
blob362b18aff33ead5bbb798b1587eb66f41cb56b68
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/utils/mono-mmap.h>
50 #include "mini.h"
51 #include "debug-mini.h"
52 #include "trace.h"
53 #include "debugger-agent.h"
55 #ifndef MONO_ARCH_CONTEXT_DEF
56 #define MONO_ARCH_CONTEXT_DEF
57 #endif
59 static gpointer restore_context_func, call_filter_func;
60 static gpointer throw_exception_func, rethrow_exception_func;
61 static gpointer throw_corlib_exception_func;
63 static gpointer try_more_restore_tramp = NULL;
64 static gpointer restore_stack_protection_tramp = NULL;
66 static void try_more_restore (void);
67 static void restore_stack_protection (void);
68 static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data);
69 static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx);
70 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
72 void
73 mono_exceptions_init (void)
75 MonoRuntimeExceptionHandlingCallbacks cbs;
76 if (mono_aot_only) {
77 restore_context_func = mono_aot_get_trampoline ("restore_context");
78 call_filter_func = mono_aot_get_trampoline ("call_filter");
79 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
80 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
81 } else {
82 MonoTrampInfo *info;
84 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
85 if (info) {
86 mono_save_trampoline_xdebug_info (info);
87 mono_tramp_info_free (info);
89 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
90 if (info) {
91 mono_save_trampoline_xdebug_info (info);
92 mono_tramp_info_free (info);
94 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
95 if (info) {
96 mono_save_trampoline_xdebug_info (info);
97 mono_tramp_info_free (info);
99 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
100 if (info) {
101 mono_save_trampoline_xdebug_info (info);
102 mono_tramp_info_free (info);
105 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
106 try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
107 restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
108 #endif
110 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
111 mono_arch_exceptions_init ();
112 #endif
113 cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
114 cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
115 cbs.mono_raise_exception = mono_get_throw_exception ();
116 cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
117 cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
118 mono_install_eh_callbacks (&cbs);
121 gpointer
122 mono_get_throw_exception (void)
124 g_assert (throw_exception_func);
125 return throw_exception_func;
128 gpointer
129 mono_get_rethrow_exception (void)
131 g_assert (rethrow_exception_func);
132 return rethrow_exception_func;
135 gpointer
136 mono_get_call_filter (void)
138 g_assert (call_filter_func);
139 return call_filter_func;
142 gpointer
143 mono_get_restore_context (void)
145 g_assert (restore_context_func);
146 return restore_context_func;
149 gpointer
150 mono_get_throw_corlib_exception (void)
152 gpointer code = NULL;
153 MonoTrampInfo *info;
155 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
156 if (throw_corlib_exception_func)
157 return throw_corlib_exception_func;
159 if (mono_aot_only)
160 code = mono_aot_get_trampoline ("throw_corlib_exception");
161 else {
162 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
163 if (info) {
164 mono_save_trampoline_xdebug_info (info);
165 mono_tramp_info_free (info);
169 mono_memory_barrier ();
171 throw_corlib_exception_func = code;
173 return throw_corlib_exception_func;
176 static gboolean
177 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
179 MonoTryBlockHoleTableJitInfo *table;
180 int i;
181 guint32 offset;
182 guint16 clause;
184 if (ei->try_start > ip || ip >= ei->try_end)
185 return FALSE;
187 if (!ji->has_try_block_holes)
188 return TRUE;
190 table = mono_jit_info_get_try_block_hole_table_info (ji);
191 offset = (guint32)((char*)ip - (char*)ji->code_start);
192 clause = (guint16)(ei - ji->clauses);
193 g_assert (clause < ji->num_clauses);
195 for (i = 0; i < table->num_holes; ++i) {
196 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
197 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
198 return FALSE;
200 return TRUE;
204 * find_jit_info:
206 * Translate between the mono_arch_find_jit_info function and the old API.
208 static MonoJitInfo *
209 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
210 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
212 StackFrameInfo frame;
213 MonoJitInfo *ji;
214 gboolean err;
215 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
217 /* Avoid costly table lookup during stack overflow */
218 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
219 ji = prev_ji;
220 else
221 ji = mini_jit_info_table_find (domain, ip, NULL);
223 if (managed)
224 *managed = FALSE;
226 err = mono_arch_find_jit_info (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
227 if (!err)
228 return (gpointer)-1;
230 /* Convert between the new and the old APIs */
231 switch (frame.type) {
232 case FRAME_TYPE_MANAGED:
233 if (managed)
234 *managed = TRUE;
235 return frame.ji;
236 case FRAME_TYPE_MANAGED_TO_NATIVE:
237 if (frame.ji)
238 return frame.ji;
239 else {
240 memset (res, 0, sizeof (MonoJitInfo));
241 res->method = frame.method;
242 return res;
244 case FRAME_TYPE_DEBUGGER_INVOKE: {
245 MonoContext tmp_ctx;
248 * The normal exception handling code can't handle this frame, so just
249 * skip it.
251 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
252 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
253 return ji;
255 default:
256 g_assert_not_reached ();
257 return NULL;
261 /* mono_find_jit_info:
263 * This function is used to gather information from @ctx. It return the
264 * MonoJitInfo of the corresponding function, unwinds one stack frame and
265 * stores the resulting context into @new_ctx. It also stores a string
266 * describing the stack location into @trace (if not NULL), and modifies
267 * the @lmf if necessary. @native_offset return the IP offset from the
268 * start of the function or -1 if that info is not available.
270 MonoJitInfo *
271 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
272 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
273 gboolean *managed)
275 gboolean managed2;
276 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
277 MonoJitInfo *ji;
279 if (trace)
280 *trace = NULL;
282 if (native_offset)
283 *native_offset = -1;
285 if (managed)
286 *managed = FALSE;
288 ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
290 if (ji == (gpointer)-1)
291 return ji;
293 if (managed2 || (ji && ji->method->wrapper_type)) {
294 const char *real_ip, *start;
295 gint32 offset;
297 start = (const char *)ji->code_start;
298 if (!managed2)
299 /* ctx->ip points into native code */
300 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
301 else
302 real_ip = (const char*)ip;
304 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
305 offset = real_ip - start;
306 else
307 offset = -1;
309 if (native_offset)
310 *native_offset = offset;
312 if (managed)
313 if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
314 *managed = TRUE;
316 if (trace)
317 *trace = mono_debug_print_stack_frame (ji->method, offset, domain);
318 } else {
319 if (trace) {
320 char *fname = mono_method_full_name (res->method, TRUE);
321 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
322 g_free (fname);
326 return ji;
330 * mono_find_jit_info_ext:
332 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
333 * structure.
334 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
335 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
336 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
337 * to obtain the last managed frame.
338 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
339 * On return, it will be filled with the locations where callee saved registers are saved
340 * by the current frame. This is returned outside of StackFrameInfo because it can be
341 * quite large on some platforms.
343 gboolean
344 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
345 MonoJitInfo *prev_ji, MonoContext *ctx,
346 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
347 mgreg_t **save_locations,
348 StackFrameInfo *frame)
350 gboolean err;
351 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
352 MonoJitInfo *ji;
353 MonoDomain *target_domain;
355 if (trace)
356 *trace = NULL;
358 /* Avoid costly table lookup during stack overflow */
359 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
360 ji = prev_ji;
361 else
362 ji = mini_jit_info_table_find (domain, ip, &target_domain);
364 if (!target_domain)
365 target_domain = domain;
367 if (save_locations)
368 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (mgreg_t*));
370 err = mono_arch_find_jit_info (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
371 if (!err)
372 return FALSE;
374 if (frame->type == FRAME_TYPE_MANAGED) {
375 if (!frame->ji->method->wrapper_type || frame->ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
376 frame->managed = TRUE;
379 if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
381 * This type of frame is just a marker, the caller should unwind once more to get the
382 * last managed frame.
384 frame->ji = NULL;
385 frame->method = NULL;
388 frame->native_offset = -1;
389 frame->domain = target_domain;
391 ji = frame->ji;
393 if (frame->type == FRAME_TYPE_MANAGED)
394 frame->method = ji->method;
396 if (ji && (frame->managed || ji->method->wrapper_type)) {
397 const char *real_ip, *start;
399 start = (const char *)ji->code_start;
400 if (!frame->managed)
401 /* ctx->ip points into native code */
402 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
403 else
404 real_ip = (const char*)ip;
406 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
407 frame->native_offset = real_ip - start;
408 else
409 frame->native_offset = -1;
411 if (trace)
412 *trace = mono_debug_print_stack_frame (ji->method, frame->native_offset, domain);
413 } else {
414 if (trace && frame->method) {
415 char *fname = mono_method_full_name (frame->method, TRUE);
416 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
417 g_free (fname);
421 return TRUE;
424 static gpointer
425 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
427 MonoGenericJitInfo *gi;
428 gpointer info;
430 if (!ji->has_generic_jit_info)
431 return NULL;
432 gi = mono_jit_info_get_generic_jit_info (ji);
433 if (!gi->has_this)
434 return NULL;
436 info = NULL;
438 * Search location list if available, it contains the precise location of the
439 * argument for every pc offset, even if the method was interrupted while it was in
440 * its prolog.
442 if (gi->nlocs) {
443 int offset = (mgreg_t)MONO_CONTEXT_GET_IP (ctx) - (mgreg_t)ji->code_start;
444 int i;
446 for (i = 0; i < gi->nlocs; ++i) {
447 MonoDwarfLocListEntry *entry = &gi->locations [i];
449 if (offset >= entry->from && (offset < entry->to || entry->to == 0)) {
450 if (entry->is_reg)
451 info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg);
452 else
453 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset);
454 break;
457 g_assert (i < gi->nlocs);
458 } else {
459 if (gi->this_in_reg)
460 info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg);
461 else
462 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
463 gi->this_offset);
466 if (mono_method_get_context (ji->method)->method_inst) {
467 return info;
468 } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
469 return info;
470 } else {
471 /* Avoid returning a managed object */
472 MonoObject *this_obj = info;
474 return this_obj->vtable->klass;
478 static MonoGenericContext
479 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
481 MonoGenericContext context = { NULL, NULL };
482 MonoClass *class, *method_container_class;
484 g_assert (generic_info);
486 g_assert (ji->method->is_inflated);
487 if (mono_method_get_context (ji->method)->method_inst) {
488 MonoMethodRuntimeGenericContext *mrgctx = generic_info;
490 class = mrgctx->class_vtable->klass;
491 context.method_inst = mrgctx->method_inst;
492 g_assert (context.method_inst);
493 } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
494 MonoVTable *vtable = generic_info;
496 class = vtable->klass;
497 } else {
498 class = generic_info;
501 //g_assert (!ji->method->klass->generic_container);
502 if (ji->method->klass->generic_class)
503 method_container_class = ji->method->klass->generic_class->container_class;
504 else
505 method_container_class = ji->method->klass;
507 /* class might refer to a subclass of ji->method's class */
508 while (!(class == ji->method->klass || (class->generic_class && class->generic_class->container_class == method_container_class))) {
509 class = class->parent;
510 g_assert (class);
513 if (class->generic_class || class->generic_container)
514 context.class_inst = mini_class_get_context (class)->class_inst;
516 if (class->generic_class)
517 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class->container_class, method_container_class));
518 else
519 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class));
521 return context;
524 static MonoMethod*
525 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
527 MonoGenericContext context;
528 MonoMethod *method;
530 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
531 return ji->method;
532 context = get_generic_context_from_stack_frame (ji, generic_info);
534 method = mono_method_get_declaring_generic_method (ji->method);
535 method = mono_class_inflate_generic_method (method, &context);
537 return method;
540 MonoString *
541 ves_icall_System_Exception_get_trace (MonoException *ex)
543 MonoDomain *domain = mono_domain_get ();
544 MonoString *res;
545 MonoArray *ta = ex->trace_ips;
546 int i, len;
547 GString *trace_str;
549 if (ta == NULL)
550 /* Exception is not thrown yet */
551 return NULL;
553 len = mono_array_length (ta) >> 1;
554 trace_str = g_string_new ("");
555 for (i = 0; i < len; i++) {
556 MonoJitInfo *ji;
557 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
558 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
560 ji = mono_jit_info_table_find (domain, ip);
561 if (ji == NULL) {
562 /* Unmanaged frame */
563 g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
564 } else {
565 gchar *location;
566 gint32 address;
567 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
569 address = (char *)ip - (char *)ji->code_start;
570 location = mono_debug_print_stack_frame (
571 method, address, ex->object.vtable->domain);
573 g_string_append_printf (trace_str, "%s\n", location);
574 g_free (location);
578 res = mono_string_new (ex->object.vtable->domain, trace_str->str);
579 g_string_free (trace_str, TRUE);
581 return res;
584 MonoArray *
585 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
587 MonoDomain *domain = mono_domain_get ();
588 MonoArray *res;
589 MonoArray *ta = exc->trace_ips;
590 MonoDebugSourceLocation *location;
591 int i, len;
593 if (ta == NULL) {
594 /* Exception is not thrown yet */
595 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
598 len = mono_array_length (ta) >> 1;
600 res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
602 for (i = skip; i < len; i++) {
603 MonoJitInfo *ji;
604 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
605 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
606 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
607 MonoMethod *method;
609 ji = mono_jit_info_table_find (domain, ip);
610 if (ji == NULL) {
611 /* Unmanaged frame */
612 mono_array_setref (res, i, sf);
613 continue;
616 g_assert (ji != NULL);
618 method = get_method_from_stack_frame (ji, generic_info);
619 if (ji->method->wrapper_type) {
620 char *s;
622 sf->method = NULL;
623 s = mono_method_full_name (method, TRUE);
624 MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
625 g_free (s);
627 else
628 MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
629 sf->native_offset = (char *)ip - (char *)ji->code_start;
632 * mono_debug_lookup_source_location() returns both the file / line number information
633 * and the IL offset. Note that computing the IL offset is already an expensive
634 * operation, so we shouldn't call this method twice.
636 location = mono_debug_lookup_source_location (ji->method, sf->native_offset, domain);
637 if (location)
638 sf->il_offset = location->il_offset;
639 else
640 sf->il_offset = 0;
642 if (need_file_info) {
643 if (location && location->source_file) {
644 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
645 sf->line = location->row;
646 sf->column = location->column;
647 } else {
648 sf->line = sf->column = 0;
649 sf->filename = NULL;
653 mono_debug_free_source_location (location);
654 mono_array_setref (res, i, sf);
657 return res;
660 static void
661 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
663 if (!start_ctx) {
664 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
665 if (jit_tls && jit_tls->orig_ex_ctx_set)
666 start_ctx = &jit_tls->orig_ex_ctx;
668 mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
671 * mono_walk_stack_with_ctx:
673 * Unwind the current thread starting at @start_ctx.
675 * If @start_ctx is null, we capture the current context.
677 void
678 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
680 MonoContext extra_ctx;
681 MonoInternalThread *thread = mono_thread_internal_current ();
682 MONO_ARCH_CONTEXT_DEF
684 if (!thread || !thread->jit_data)
685 return;
687 if (!start_ctx) {
688 mono_arch_flush_register_windows ();
690 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
691 MONO_INIT_CONTEXT_FROM_CURRENT (&extra_ctx);
692 #else
693 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
694 #endif
695 start_ctx = &extra_ctx;
698 mono_walk_stack_full (func, start_ctx, mono_domain_get (), thread->jit_data, mono_get_lmf (), unwind_options, user_data);
702 * mono_walk_stack_with_state:
704 * Unwind a thread described by @state.
706 * State must be valid (state->valid == TRUE).
708 * If you are using this function to unwind another thread, make sure it is suspended.
710 * If @state is null, we capture the current context.
712 void
713 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
715 MonoThreadUnwindState extra_state;
716 if (!state) {
717 if (!mono_thread_state_init_from_current (&extra_state))
718 return;
719 state = &extra_state;
722 g_assert (state->valid);
724 mono_walk_stack_full (func,
725 &state->ctx,
726 state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
727 state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
728 state->unwind_data [MONO_UNWIND_DATA_LMF],
729 unwind_options, user_data);
732 void
733 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
735 MonoThreadUnwindState state;
736 if (!mono_thread_state_init_from_current (&state))
737 return;
738 mono_walk_stack_with_state (func, &state, options, user_data);
742 * mono_walk_stack_full:
743 * @func: callback to call for each stack frame
744 * @domain: starting appdomain, can be NULL to use the current domain
745 * @unwind_options: what extra information the unwinder should gather
746 * @start_ctx: starting state of the stack walk, can be NULL.
747 * @thread: the thread whose stack to walk, can be NULL to use the current thread
748 * @lmf: the LMF of @thread, can be NULL to use the LMF of the current thread
749 * @user_data: data passed to the callback
751 * This function walks the stack of a thread, starting from the state
752 * represented by start_ctx. For each frame the callback
753 * function is called with the relevant info. The walk ends when no more
754 * managed stack frames are found or when the callback returns a TRUE value.
756 static void
757 mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data)
759 gint il_offset, i;
760 MonoContext ctx, new_ctx;
761 StackFrameInfo frame;
762 gboolean res;
763 mgreg_t *reg_locations [MONO_MAX_IREGS];
764 mgreg_t *new_reg_locations [MONO_MAX_IREGS];
765 gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
767 g_assert (start_ctx);
768 g_assert (domain);
769 g_assert (jit_tls);
770 /*The LMF will be null if the target have no managed frames.*/
771 /* g_assert (lmf); */
773 memcpy (&ctx, start_ctx, sizeof (MonoContext));
774 memset (reg_locations, 0, sizeof (reg_locations));
776 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
777 frame.lmf = lmf;
778 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
779 if (!res)
780 return;
782 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) {
783 MonoDebugSourceLocation *source;
785 source = mono_debug_lookup_source_location (frame.ji->method, frame.native_offset, domain);
786 il_offset = source ? source->il_offset : -1;
787 mono_debug_free_source_location (source);
788 } else
789 il_offset = -1;
791 frame.il_offset = il_offset;
793 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) {
794 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
795 } else {
796 frame.actual_method = frame.method;
799 if (get_reg_locations)
800 frame.reg_locations = reg_locations;
802 if (func (&frame, &ctx, user_data))
803 return;
805 if (get_reg_locations) {
806 for (i = 0; i < MONO_MAX_IREGS; ++i)
807 if (new_reg_locations [i])
808 reg_locations [i] = new_reg_locations [i];
811 ctx = new_ctx;
815 MonoBoolean
816 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
817 MonoReflectionMethod **method,
818 gint32 *iloffset, gint32 *native_offset,
819 MonoString **file, gint32 *line, gint32 *column)
821 MonoDomain *domain = mono_domain_get ();
822 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
823 MonoLMF *lmf = mono_get_lmf ();
824 MonoJitInfo *ji = NULL;
825 MonoContext ctx, new_ctx;
826 MonoDebugSourceLocation *location;
827 MonoMethod *actual_method;
828 StackFrameInfo frame;
829 gboolean res;
831 MONO_ARCH_CONTEXT_DEF;
833 mono_arch_flush_register_windows ();
835 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
836 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
837 #else
838 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
839 #endif
841 new_ctx = ctx;
842 do {
843 ctx = new_ctx;
844 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
845 if (!res)
846 return FALSE;
848 if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || frame.type == FRAME_TYPE_DEBUGGER_INVOKE)
849 continue;
851 ji = frame.ji;
852 *native_offset = frame.native_offset;
854 /* skip all wrappers ??*/
855 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
856 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
857 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
858 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
859 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE ||
860 ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
861 continue;
863 skip--;
864 } while (skip >= 0);
866 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
868 mono_gc_wbarrier_generic_store (method, (MonoObject*) mono_method_get_object (domain, actual_method, NULL));
870 location = mono_debug_lookup_source_location (ji->method, *native_offset, domain);
871 if (location)
872 *iloffset = location->il_offset;
873 else
874 *iloffset = 0;
876 if (need_file_info) {
877 if (location) {
878 mono_gc_wbarrier_generic_store (file, (MonoObject*) mono_string_new (domain, location->source_file));
879 *line = location->row;
880 *column = location->column;
881 } else {
882 *file = NULL;
883 *line = *column = 0;
887 mono_debug_free_source_location (location);
889 return TRUE;
892 typedef struct {
893 guint32 skips;
894 MonoSecurityFrame *frame;
895 } MonoFrameSecurityInfo;
897 static gboolean
898 callback_get_first_frame_security_info (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
900 MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
901 MonoJitInfo *ji = frame->ji;
903 if (!ji)
904 return FALSE;
906 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
907 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
908 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
909 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
910 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
911 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
912 return FALSE;
915 if (si->skips > 0) {
916 si->skips--;
917 return FALSE;
920 si->frame = mono_declsec_create_frame (frame->domain, ji);
922 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
923 return TRUE;
927 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
928 * @skip: the number of stack frames to skip
930 * This function returns a the security informations of a single stack frame
931 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
932 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
933 * evaluated.
935 MonoSecurityFrame*
936 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
938 MonoFrameSecurityInfo si;
940 si.skips = skip;
941 si.frame = NULL;
943 mono_walk_stack (callback_get_first_frame_security_info, MONO_UNWIND_DEFAULT, &si);
945 return (si.skips == 0) ? si.frame : NULL;
949 typedef struct {
950 guint32 skips;
951 MonoArray *stack;
952 guint32 count;
953 guint32 maximum;
954 } MonoSecurityStack;
956 static void
957 grow_array (MonoSecurityStack *stack)
959 MonoDomain *domain = mono_domain_get ();
960 guint32 newsize = (stack->maximum << 1);
961 MonoArray *newstack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, newsize);
962 int i;
963 for (i=0; i < stack->maximum; i++) {
964 gpointer frame = mono_array_get (stack->stack, gpointer, i);
965 mono_array_setref (newstack, i, frame);
967 stack->maximum = newsize;
968 stack->stack = newstack;
971 static gboolean
972 callback_get_stack_frames_security_info (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
974 MonoSecurityStack *ss = (MonoSecurityStack*) data;
975 MonoJitInfo *ji = frame->ji;
977 if (!ji)
978 return FALSE;
980 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
981 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
982 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
983 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
984 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
985 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
986 return FALSE;
989 if (ss->skips > 0) {
990 ss->skips--;
991 return FALSE;
994 if (ss->count == ss->maximum)
995 grow_array (ss);
997 mono_array_setref (ss->stack, ss->count++, mono_declsec_create_frame (frame->domain, ji));
999 /* continue down the stack */
1000 return FALSE;
1003 static MonoArray *
1004 glist_to_array (GList *list, MonoClass *eclass)
1006 MonoDomain *domain = mono_domain_get ();
1007 MonoArray *res;
1008 int len, i;
1010 if (!list)
1011 return NULL;
1013 len = g_list_length (list);
1014 res = mono_array_new (domain, eclass, len);
1016 for (i = 0; list; list = list->next, i++)
1017 mono_array_set (res, gpointer, i, list->data);
1019 return res;
1023 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
1024 * @skip: the number of stack frames to skip
1026 * This function returns an managed array of containing the security
1027 * informations for each frame (after the skipped ones). This is used for
1028 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
1029 * required.
1031 MonoArray*
1032 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
1034 MonoSecurityStack ss;
1036 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
1037 skip--;
1038 #endif
1040 ss.skips = skip;
1041 ss.count = 0;
1042 ss.maximum = MONO_CAS_INITIAL_STACK_SIZE;
1043 ss.stack = mono_array_new (mono_domain_get (), mono_defaults.runtimesecurityframe_class, ss.maximum);
1044 mono_walk_stack (callback_get_stack_frames_security_info, MONO_UNWIND_DEFAULT, &ss);
1045 /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
1046 return ss.stack;
1049 static MonoClass*
1050 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1052 MonoClass *catch_class = ei->data.catch_class;
1053 MonoType *inflated_type;
1054 MonoGenericContext context;
1056 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1057 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
1058 return NULL;
1060 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1061 return catch_class;
1062 context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1064 /* FIXME: we shouldn't inflate but instead put the
1065 type in the rgctx and fetch it from there. It
1066 might be a good idea to do this lazily, i.e. only
1067 when the exception is actually thrown, so as not to
1068 waste space for exception clauses which might never
1069 be encountered. */
1070 inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
1071 catch_class = mono_class_from_mono_type (inflated_type);
1072 mono_metadata_free_type (inflated_type);
1074 return catch_class;
1078 * mini_jit_info_table_find:
1080 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1081 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1082 * OUT_DOMAIN if it is not NULL.
1084 MonoJitInfo*
1085 mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
1087 MonoJitInfo *ji;
1088 MonoInternalThread *t = mono_thread_internal_current ();
1089 gpointer *refs;
1091 if (out_domain)
1092 *out_domain = NULL;
1094 ji = mono_jit_info_table_find (domain, addr);
1095 if (ji) {
1096 if (out_domain)
1097 *out_domain = domain;
1098 return ji;
1101 /* maybe it is shared code, so we also search in the root domain */
1102 if (domain != mono_get_root_domain ()) {
1103 ji = mono_jit_info_table_find (mono_get_root_domain (), addr);
1104 if (ji) {
1105 if (out_domain)
1106 *out_domain = mono_get_root_domain ();
1107 return ji;
1111 refs = (t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL;
1112 for (; refs && *refs; refs++) {
1113 if (*refs != domain && *refs != mono_get_root_domain ()) {
1114 ji = mono_jit_info_table_find ((MonoDomain*) *refs, addr);
1115 if (ji) {
1116 if (out_domain)
1117 *out_domain = (MonoDomain*) *refs;
1118 return ji;
1123 return NULL;
1127 * wrap_non_exception_throws:
1129 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
1130 * WrapNonExceptionThrows flag set.
1132 static gboolean
1133 wrap_non_exception_throws (MonoMethod *m)
1135 MonoAssembly *ass = m->klass->image->assembly;
1136 MonoCustomAttrInfo* attrs;
1137 static MonoClass *klass;
1138 int i;
1139 gboolean val = FALSE;
1141 g_assert (ass);
1142 if (ass->wrap_non_exception_throws_inited)
1143 return ass->wrap_non_exception_throws;
1145 klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1147 attrs = mono_custom_attrs_from_assembly (ass);
1148 if (attrs) {
1149 for (i = 0; i < attrs->num_attrs; ++i) {
1150 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1151 const gchar *p;
1152 int len, num_named, named_type, data_type, name_len;
1153 char *name;
1155 if (!attr->ctor || attr->ctor->klass != klass)
1156 continue;
1157 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
1158 len = attr->data_size;
1159 p = (const char*)attr->data;
1160 g_assert (read16 (p) == 0x0001);
1161 p += 2;
1162 num_named = read16 (p);
1163 if (num_named != 1)
1164 continue;
1165 p += 2;
1166 named_type = *p;
1167 p ++;
1168 data_type = *p;
1169 p ++;
1170 /* Property */
1171 if (named_type != 0x54)
1172 continue;
1173 name_len = mono_metadata_decode_blob_size (p, &p);
1174 name = g_malloc (name_len + 1);
1175 memcpy (name, p, name_len);
1176 name [name_len] = 0;
1177 p += name_len;
1178 g_assert (!strcmp (name, "WrapNonExceptionThrows"));
1179 g_free (name);
1180 /* The value is a BOOLEAN */
1181 val = *p;
1183 mono_custom_attrs_free (attrs);
1186 ass->wrap_non_exception_throws = val;
1187 mono_memory_barrier ();
1188 ass->wrap_non_exception_throws_inited = TRUE;
1190 return val;
1193 #ifndef MONO_ARCH_STACK_GROWS_UP
1194 #define DOES_STACK_GROWS_UP 1
1195 #else
1196 #define DOES_STACK_GROWS_UP 0
1197 #endif
1199 #define MAX_UNMANAGED_BACKTRACE 128
1200 static MonoArray*
1201 build_native_trace (void)
1203 /* This puppy only makes sense on mobile, IOW, ARM. */
1204 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
1205 MonoArray *res;
1206 void *native_trace [MAX_UNMANAGED_BACKTRACE];
1207 int size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE);
1208 int i;
1210 if (!size)
1211 return NULL;
1212 res = mono_array_new (mono_domain_get (), mono_defaults.int_class, size);
1214 for (i = 0; i < size; i++)
1215 mono_array_set (res, gpointer, i, native_trace [i]);
1216 return res;
1217 #else
1218 return NULL;
1219 #endif
1222 #define setup_managed_stacktrace_information() do { \
1223 if (mono_ex && !initial_trace_ips) { \
1224 trace_ips = g_list_reverse (trace_ips); \
1225 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class)); \
1226 MONO_OBJECT_SETREF (mono_ex, native_trace_ips, build_native_trace ()); \
1227 if (has_dynamic_methods) \
1228 /* These methods could go away anytime, so compute the stack trace now */ \
1229 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex)); \
1231 g_list_free (trace_ips); \
1232 trace_ips = NULL; \
1233 } while (0)
1235 * mono_handle_exception_internal_first_pass:
1237 * The first pass of exception handling. Unwind the stack until a catch clause which can catch
1238 * OBJ is found. Run the index of the filter clause which caught the exception into
1239 * OUT_FILTER_IDX. Return TRUE if the exception is caught, FALSE otherwise.
1241 static gboolean
1242 mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoObject *non_exception)
1244 MonoDomain *domain = mono_domain_get ();
1245 MonoJitInfo *ji;
1246 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1247 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1248 MonoLMF *lmf = mono_get_lmf ();
1249 MonoArray *initial_trace_ips = NULL;
1250 GList *trace_ips = NULL;
1251 MonoException *mono_ex;
1252 gboolean stack_overflow = FALSE;
1253 MonoContext initial_ctx;
1254 int frame_count = 0;
1255 gboolean has_dynamic_methods = FALSE;
1256 gint32 filter_idx;
1257 int i;
1258 MonoObject *ex_obj;
1260 g_assert (ctx != NULL);
1262 if (obj == domain->stack_overflow_ex)
1263 stack_overflow = TRUE;
1265 mono_ex = (MonoException*)obj;
1266 initial_trace_ips = mono_ex->trace_ips;
1268 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1269 mono_ex = (MonoException*)obj;
1270 initial_trace_ips = mono_ex->trace_ips;
1271 } else {
1272 mono_ex = NULL;
1275 if (!call_filter)
1276 call_filter = mono_get_call_filter ();
1278 g_assert (jit_tls->end_of_stack);
1279 g_assert (jit_tls->abort_func);
1281 if (out_filter_idx)
1282 *out_filter_idx = -1;
1283 if (out_ji)
1284 *out_ji = NULL;
1285 filter_idx = 0;
1286 initial_ctx = *ctx;
1288 while (1) {
1289 MonoContext new_ctx;
1290 guint32 free_stack;
1291 int clause_index_start = 0;
1292 gboolean unwind_res = TRUE;
1294 StackFrameInfo frame;
1296 unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1297 if (unwind_res) {
1298 if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
1299 *ctx = new_ctx;
1300 continue;
1302 g_assert (frame.type == FRAME_TYPE_MANAGED);
1303 ji = frame.ji;
1306 if (!unwind_res) {
1307 setup_managed_stacktrace_information ();
1308 return FALSE;
1311 frame_count ++;
1312 //printf ("M: %s %d.\n", mono_method_full_name (ji->method, TRUE), frame_count);
1314 if (mini_get_debug_options ()->reverse_pinvoke_exceptions && ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
1315 g_error ("A native frame was found while unwinding the stack after an exception.\n"
1316 "The native frame called the managed method:\n%s\n",
1317 mono_method_full_name (ji->method, TRUE));
1320 if (ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1322 * Avoid overwriting the stack trace if the exception is
1323 * rethrown. Also avoid giant stack traces during a stack
1324 * overflow.
1326 if (!initial_trace_ips && (frame_count < 1000)) {
1327 trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1328 trace_ips = g_list_prepend (trace_ips,
1329 get_generic_info_from_stack_frame (ji, ctx));
1333 if (ji->method->dynamic)
1334 has_dynamic_methods = TRUE;
1336 if (stack_overflow) {
1337 if (DOES_STACK_GROWS_UP)
1338 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1339 else
1340 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1341 } else {
1342 free_stack = 0xffffff;
1345 for (i = clause_index_start; i < ji->num_clauses; i++) {
1346 MonoJitExceptionInfo *ei = &ji->clauses [i];
1347 gboolean filtered = FALSE;
1350 * During stack overflow, wait till the unwinding frees some stack
1351 * space before running handlers/finalizers.
1353 if (free_stack <= (64 * 1024))
1354 continue;
1356 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1357 /* catch block */
1358 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1361 * Have to unwrap RuntimeWrappedExceptions if the
1362 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1364 if (non_exception && !wrap_non_exception_throws (ji->method))
1365 ex_obj = non_exception;
1366 else
1367 ex_obj = obj;
1369 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1370 gboolean is_user_frame = ji->method->wrapper_type == MONO_WRAPPER_NONE || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD;
1371 mono_perfcounters->exceptions_filters++;
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 mono_perfcounters->exceptions_depth += frame_count;
1729 if (obj == domain->stack_overflow_ex)
1730 jit_tls->handling_stack_ovf = FALSE;
1732 return 0;
1734 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1735 (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
1736 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1737 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1738 jit_tls->orig_ex_ctx_set = TRUE;
1739 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1740 jit_tls->orig_ex_ctx_set = FALSE;
1741 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1742 call_filter (ctx, ei->handler_start);
1744 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1745 (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
1746 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1747 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1748 jit_tls->orig_ex_ctx_set = TRUE;
1749 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1750 jit_tls->orig_ex_ctx_set = FALSE;
1751 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1752 mono_perfcounters->exceptions_finallys++;
1753 *(mono_get_lmf_addr ()) = lmf;
1754 if (ji->from_llvm) {
1756 * LLVM compiled finally handlers follow the design
1757 * of the c++ ehabi, i.e. they call a resume function
1758 * at the end instead of returning to the caller.
1759 * So save the exception handling state,
1760 * mono_resume_unwind () will call us again to continue
1761 * the unwinding.
1763 jit_tls->resume_state.ex_obj = obj;
1764 jit_tls->resume_state.ji = ji;
1765 jit_tls->resume_state.clause_index = i + 1;
1766 jit_tls->resume_state.ctx = *ctx;
1767 jit_tls->resume_state.new_ctx = new_ctx;
1768 jit_tls->resume_state.lmf = lmf;
1769 jit_tls->resume_state.first_filter_idx = first_filter_idx;
1770 jit_tls->resume_state.filter_idx = filter_idx;
1771 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1772 return 0;
1773 } else {
1774 call_filter (ctx, ei->handler_start);
1780 jit_tls->orig_ex_ctx_set = TRUE;
1781 mono_profiler_exception_method_leave (ji->method);
1782 jit_tls->orig_ex_ctx_set = FALSE;
1784 *ctx = new_ctx;
1787 g_assert_not_reached ();
1791 * mono_debugger_handle_exception:
1793 * Notify the debugger about exceptions. Returns TRUE if the debugger wants us to stop
1794 * at the exception and FALSE to resume with the normal exception handling.
1796 * The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
1797 * MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
1798 * `callq throw' instruction.
1800 gboolean
1801 mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
1803 MonoDebuggerExceptionAction action;
1805 if (!mono_debug_using_mono_debugger ())
1806 return FALSE;
1808 if (!obj) {
1809 MonoException *ex = mono_get_exception_null_reference ();
1810 MONO_OBJECT_SETREF (ex, message, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
1811 obj = (MonoObject *)ex;
1814 action = _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1816 if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP) {
1818 * The debugger wants us to stop on the `throw' instruction.
1819 * By the time we get here, it already inserted a breakpoint there.
1821 return TRUE;
1822 } else if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED) {
1823 MonoContext ctx_cp = *ctx;
1824 MonoJitInfo *ji = NULL;
1825 gboolean ret;
1828 * The debugger wants us to stop only if this exception is user-unhandled.
1831 ret = mono_handle_exception_internal_first_pass (&ctx_cp, obj, NULL, &ji, NULL);
1832 if (ret && (ji != NULL) && (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
1834 * The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
1835 * inside the method being invoked, so we handle it like a user-unhandled exception.
1837 ret = FALSE;
1840 if (!ret) {
1842 * The exception is user-unhandled - tell the debugger to stop.
1844 return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1848 * The exception is catched somewhere - resume with the normal exception handling and don't
1849 * stop in the debugger.
1853 return FALSE;
1857 * mono_debugger_run_finally:
1858 * @start_ctx: saved processor state
1860 * This method is called by the Mono Debugger to call all `finally' clauses of the
1861 * current stack frame. It's used when the user issues a `return' command to make
1862 * the current stack frame return. After returning from this method, the debugger
1863 * unwinds the stack one frame and gives control back to the user.
1865 * NOTE: This method is only used when running inside the Mono Debugger.
1867 void
1868 mono_debugger_run_finally (MonoContext *start_ctx)
1870 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1871 MonoDomain *domain = mono_domain_get ();
1872 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1873 MonoLMF *lmf = mono_get_lmf ();
1874 MonoContext ctx, new_ctx;
1875 MonoJitInfo *ji, rji;
1876 int i;
1878 ctx = *start_ctx;
1880 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1881 if (!ji || ji == (gpointer)-1)
1882 return;
1884 if (!call_filter)
1885 call_filter = mono_get_call_filter ();
1887 for (i = 0; i < ji->num_clauses; i++) {
1888 MonoJitExceptionInfo *ei = &ji->clauses [i];
1890 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
1891 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1892 call_filter (&ctx, ei->handler_start);
1898 * mono_handle_exception:
1899 * @ctx: saved processor state
1900 * @obj: the exception object
1902 gboolean
1903 mono_handle_exception (MonoContext *ctx, gpointer obj)
1905 mono_perfcounters->exceptions_thrown++;
1907 return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
1910 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1912 #ifndef MONO_ARCH_USE_SIGACTION
1913 #error "Can't use sigaltstack without sigaction"
1914 #endif
1916 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1918 void
1919 mono_setup_altstack (MonoJitTlsData *tls)
1921 size_t stsize = 0;
1922 stack_t sa;
1923 guint8 *staddr = NULL;
1925 if (mono_running_on_valgrind ())
1926 return;
1928 mono_thread_get_stack_bounds (&staddr, &stsize);
1930 g_assert (staddr);
1932 tls->end_of_stack = staddr + stsize;
1933 tls->stack_size = stsize;
1935 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1937 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1938 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
1940 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
1942 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1943 /* mprotect can fail for the main thread stack */
1944 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);
1945 g_assert (gaddr == tls->stack_ovf_guard_base);
1946 tls->stack_ovf_valloced = TRUE;
1949 /* Setup an alternate signal stack */
1950 tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
1951 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1953 g_assert (tls->signal_stack);
1955 sa.ss_sp = tls->signal_stack;
1956 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1957 #if __APPLE__
1958 sa.ss_flags = 0;
1959 #else
1960 sa.ss_flags = SS_ONSTACK;
1961 #endif
1962 g_assert (sigaltstack (&sa, NULL) == 0);
1964 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);
1967 void
1968 mono_free_altstack (MonoJitTlsData *tls)
1970 stack_t sa;
1971 int err;
1973 sa.ss_sp = tls->signal_stack;
1974 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1975 sa.ss_flags = SS_DISABLE;
1976 err = sigaltstack (&sa, NULL);
1977 g_assert (err == 0);
1979 if (tls->signal_stack)
1980 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1981 if (tls->stack_ovf_valloced)
1982 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size);
1983 else
1984 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1987 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1989 void
1990 mono_setup_altstack (MonoJitTlsData *tls)
1994 void
1995 mono_free_altstack (MonoJitTlsData *tls)
1999 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
2001 static gboolean
2002 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
2004 gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
2005 /* we need to leave some room for throwing the exception */
2006 while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
2007 unprotect_size -= mono_pagesize ();
2008 /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
2009 * is sufficient stack
2011 //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);
2012 if (unprotect_size)
2013 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
2014 return unprotect_size == jit_tls->stack_ovf_guard_size;
2017 static G_GNUC_UNUSED void
2018 try_more_restore (void)
2020 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2021 if (try_restore_stack_protection (jit_tls, 500))
2022 jit_tls->restore_stack_prot = NULL;
2025 static G_GNUC_UNUSED void
2026 restore_stack_protection (void)
2028 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2029 MonoException *ex = mono_domain_get ()->stack_overflow_ex;
2030 /* if we can't restore the stack protection, keep a callback installed so
2031 * we'll try to restore as much stack as we can at each return from unmanaged
2032 * code.
2034 if (try_restore_stack_protection (jit_tls, 4096))
2035 jit_tls->restore_stack_prot = NULL;
2036 else
2037 jit_tls->restore_stack_prot = try_more_restore_tramp;
2038 /* here we also throw a stack overflow exception */
2039 ex->trace_ips = NULL;
2040 ex->stack_trace = NULL;
2041 mono_raise_exception (ex);
2044 gpointer
2045 mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
2047 void (*func)(void) = (gpointer)tramp_data;
2048 func ();
2049 return NULL;
2052 gboolean
2053 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
2055 /* we got a stack overflow in the soft-guard pages
2056 * There are two cases:
2057 * 1) managed code caused the overflow: we unprotect the soft-guard page
2058 * and let the arch-specific code trigger the exception handling mechanism
2059 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
2060 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
2061 * and hope we can continue with those enabled, at least until the hard-guard page
2062 * is hit. The alternative to continuing here is to just print a message and abort.
2063 * We may add in the future the code to protect the pages again in the codepath
2064 * when we return from unmanaged to managed code.
2066 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
2067 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
2068 /* we unprotect the minimum amount we can */
2069 guint32 guard_size;
2070 gboolean handled = FALSE;
2072 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
2073 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
2074 guard_size -= mono_pagesize ();
2076 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
2077 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
2078 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);
2079 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2080 if (ji) {
2081 mono_arch_handle_altstack_exception (ctx, fault_addr, TRUE);
2082 handled = TRUE;
2084 #endif
2085 if (!handled) {
2086 /* We print a message: after this even managed stack overflows
2087 * may crash the runtime
2089 fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), fault_addr);
2090 if (!jit_tls->handling_stack_ovf) {
2091 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
2092 jit_tls->handling_stack_ovf = 1;
2093 } else {
2094 /*fprintf (stderr, "Already handling stack overflow\n");*/
2097 return TRUE;
2099 return FALSE;
2102 typedef struct {
2103 FILE *stream;
2104 MonoMethod *omethod;
2105 int count;
2106 } PrintOverflowUserData;
2108 static gboolean
2109 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2111 MonoMethod *method = NULL;
2112 PrintOverflowUserData *user_data = data;
2113 FILE *stream = user_data->stream;
2114 gchar *location;
2116 if (frame->ji)
2117 method = frame->ji->method;
2119 if (method) {
2120 if (user_data->count == 0) {
2121 /* The first frame is in its prolog, so a line number cannot be computed */
2122 user_data->count ++;
2123 return FALSE;
2126 /* If this is a one method overflow, skip the other instances */
2127 if (method == user_data->omethod)
2128 return FALSE;
2130 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2131 fprintf (stream, " %s\n", location);
2132 g_free (location);
2134 if (user_data->count == 1) {
2135 fprintf (stream, " <...>\n");
2136 user_data->omethod = method;
2137 } else {
2138 user_data->omethod = NULL;
2141 user_data->count ++;
2142 } else
2143 fprintf (stream, " at <unknown> <0x%05x>\n", frame->native_offset);
2145 return FALSE;
2148 void
2149 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
2151 PrintOverflowUserData ud;
2152 MonoContext mctx;
2154 /* we don't do much now, but we can warn the user with a useful message */
2155 fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), fault_addr);
2157 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2158 mono_arch_sigctx_to_monoctx (ctx, &mctx);
2160 fprintf (stderr, "Stacktrace:\n");
2162 memset (&ud, 0, sizeof (ud));
2163 ud.stream = stderr;
2165 mono_walk_stack_with_ctx (print_overflow_stack_frame, &mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
2166 #else
2167 if (ji && ji->method)
2168 fprintf (stderr, "At %s\n", mono_method_full_name (ji->method, TRUE));
2169 else
2170 fprintf (stderr, "At <unmanaged>.\n");
2171 #endif
2173 _exit (1);
2176 static gboolean
2177 print_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2179 FILE *stream = (FILE*)data;
2180 MonoMethod *method = NULL;
2181 if (frame->ji)
2182 method = frame->ji->method;
2184 if (method) {
2185 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2186 fprintf (stream, " %s\n", location);
2187 g_free (location);
2188 } else
2189 fprintf (stream, " at <unknown> <0x%05x>\n", frame->native_offset);
2191 return FALSE;
2194 static G_GNUC_UNUSED gboolean
2195 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2197 GString *p = (GString*)data;
2198 MonoMethod *method = NULL;
2199 if (frame->ji)
2200 method = frame->ji->method;
2202 if (method) {
2203 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2204 g_string_append_printf (p, " %s\n", location);
2205 g_free (location);
2206 } else
2207 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
2209 return FALSE;
2212 static gboolean handling_sigsegv = FALSE;
2215 * mono_handle_native_sigsegv:
2217 * Handle a SIGSEGV received while in native code by printing diagnostic
2218 * information and aborting.
2220 void
2221 mono_handle_native_sigsegv (int signal, void *ctx)
2223 #ifdef MONO_ARCH_USE_SIGACTION
2224 struct sigaction sa;
2225 #endif
2226 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2228 if (handling_sigsegv)
2229 return;
2231 if (mini_get_debug_options ()->suspend_on_sigsegv) {
2232 fprintf (stderr, "Received SIGSEGV, suspending...");
2233 while (1)
2237 /* To prevent infinite loops when the stack walk causes a crash */
2238 handling_sigsegv = TRUE;
2240 /* !jit_tls means the thread was not registered with the runtime */
2241 if (jit_tls && mono_thread_internal_current ()) {
2242 fprintf (stderr, "Stacktrace:\n\n");
2244 mono_walk_stack (print_stack_frame, TRUE, stderr);
2246 fflush (stderr);
2249 #ifdef HAVE_BACKTRACE_SYMBOLS
2251 void *array [256];
2252 char **names;
2253 int i, size;
2254 const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
2256 fprintf (stderr, "\nNative stacktrace:\n\n");
2258 size = backtrace (array, 256);
2259 names = backtrace_symbols (array, size);
2260 for (i =0; i < size; ++i) {
2261 fprintf (stderr, "\t%s\n", names [i]);
2263 free (names);
2265 fflush (stderr);
2267 /* Try to get more meaningful information using gdb */
2269 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
2270 if (!mini_get_debug_options ()->no_gdb_backtrace && !mono_debug_using_mono_debugger ()) {
2271 /* From g_spawn_command_line_sync () in eglib */
2272 pid_t pid;
2273 int status;
2274 pid_t crashed_pid = getpid ();
2276 //pid = fork ();
2278 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
2279 * it will deadlock. Call the syscall directly instead.
2281 pid = mono_runtime_syscall_fork ();
2283 if (pid == 0) {
2284 dup2 (STDERR_FILENO, STDOUT_FILENO);
2286 mono_gdb_render_native_backtraces (crashed_pid);
2287 exit (1);
2290 fprintf (stderr, "\nDebug info from gdb:\n\n");
2291 waitpid (pid, &status, 0);
2293 #endif
2295 * A SIGSEGV indicates something went very wrong so we can no longer depend
2296 * on anything working. So try to print out lots of diagnostics, starting
2297 * with ones which have a greater chance of working.
2299 fprintf (stderr,
2300 "\n"
2301 "=================================================================\n"
2302 "Got a %s while executing native code. This usually indicates\n"
2303 "a fatal error in the mono runtime or one of the native libraries \n"
2304 "used by your application.\n"
2305 "=================================================================\n"
2306 "\n", signal_str);
2309 #endif
2311 #ifdef MONO_ARCH_USE_SIGACTION
2313 /* Remove our SIGABRT handler */
2314 sa.sa_handler = SIG_DFL;
2315 sigemptyset (&sa.sa_mask);
2316 sa.sa_flags = 0;
2318 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
2320 #endif
2322 abort ();
2325 static void
2326 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
2328 MonoInternalThread *thread = mono_thread_internal_current ();
2329 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2330 MonoContext ctx;
2331 #endif
2332 GString* text = g_string_new (0);
2333 char *name, *wapi_desc;
2334 GError *error = NULL;
2336 if (thread->name) {
2337 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
2338 g_assert (!error);
2339 g_string_append_printf (text, "\n\"%s\"", name);
2340 g_free (name);
2342 else if (thread->threadpool_thread)
2343 g_string_append (text, "\n\"<threadpool thread>\"");
2344 else
2345 g_string_append (text, "\n\"<unnamed thread>\"");
2347 #ifndef HOST_WIN32
2348 wapi_desc = wapi_current_thread_desc ();
2349 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
2350 free (wapi_desc);
2351 #endif
2353 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2354 if (start_ctx) {
2355 memcpy (&ctx, start_ctx, sizeof (MonoContext));
2356 } else if (!sigctx)
2357 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
2358 else
2359 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
2361 mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
2362 #else
2363 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
2364 #endif
2366 fprintf (stdout, "%s", text->str);
2368 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
2369 OutputDebugStringA(text->str);
2370 #endif
2372 g_string_free (text, TRUE);
2373 fflush (stdout);
2377 * mono_print_thread_dump:
2379 * Print information about the current thread to stdout.
2380 * SIGCTX can be NULL, allowing this to be called from gdb.
2382 void
2383 mono_print_thread_dump (void *sigctx)
2385 mono_print_thread_dump_internal (sigctx, NULL);
2388 void
2389 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2391 mono_print_thread_dump_internal (NULL, ctx);
2395 * mono_resume_unwind:
2397 * This is called by a trampoline from LLVM compiled finally clauses to continue
2398 * unwinding.
2400 void
2401 mono_resume_unwind (MonoContext *ctx)
2403 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2404 static void (*restore_context) (MonoContext *);
2405 MonoContext new_ctx;
2407 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
2408 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
2409 new_ctx = *ctx;
2411 mono_handle_exception_internal (&new_ctx, jit_tls->resume_state.ex_obj, TRUE, NULL);
2413 if (!restore_context)
2414 restore_context = mono_get_restore_context ();
2416 restore_context (&new_ctx);
2419 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
2421 typedef struct {
2422 MonoJitInfo *ji;
2423 MonoContext ctx;
2424 MonoJitExceptionInfo *ei;
2425 } FindHandlerBlockData;
2427 static gboolean
2428 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2430 int i;
2431 gpointer ip;
2432 FindHandlerBlockData *pdata = data;
2433 MonoJitInfo *ji = frame->ji;
2435 if (!ji)
2436 return FALSE;
2438 if (ji->method->wrapper_type)
2439 return FALSE;
2441 ip = MONO_CONTEXT_GET_IP (ctx);
2443 for (i = 0; i < ji->num_clauses; ++i) {
2444 MonoJitExceptionInfo *ei = ji->clauses + i;
2445 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2446 continue;
2447 /*If ip points to the first instruction it means the handler block didn't start
2448 so we can leave its execution to the EH machinery*/
2449 if (ei->handler_start < ip && ip < ei->data.handler_end) {
2450 pdata->ji = ji;
2451 pdata->ei = ei;
2452 pdata->ctx = *ctx;
2453 break;
2456 return FALSE;
2460 static gpointer
2461 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
2463 int i;
2464 MonoJitExceptionInfo *clause = NULL;
2465 gpointer ip;
2467 ip = MONO_CONTEXT_GET_IP (ctx);
2469 for (i = 0; i < ji->num_clauses; ++i) {
2470 clause = &ji->clauses [i];
2471 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2472 continue;
2473 if (clause->handler_start < ip && clause->data.handler_end > ip)
2474 break;
2477 /*no matching finally */
2478 if (i == ji->num_clauses)
2479 return NULL;
2481 /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
2482 if (ip == clause->handler_start)
2483 return NULL;
2485 return mono_arch_install_handler_block_guard (ji, clause, ctx, mono_create_handler_block_trampoline ());
2489 * Finds the bottom handler block running and install a block guard if needed.
2490 * FIXME add full-aot support.
2492 gboolean
2493 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
2495 FindHandlerBlockData data = { 0 };
2496 MonoJitTlsData *jit_tls = ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
2497 gpointer resume_ip;
2499 /* FIXME */
2500 if (mono_aot_only)
2501 return FALSE;
2503 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
2504 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
2506 if (!jit_tls || jit_tls->handler_block_return_address)
2507 return FALSE;
2509 mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_SIGNAL_SAFE, &data);
2511 if (!data.ji)
2512 return FALSE;
2514 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
2516 resume_ip = install_handler_block_guard (data.ji, &data.ctx);
2517 if (resume_ip == NULL)
2518 return FALSE;
2520 jit_tls->handler_block_return_address = resume_ip;
2521 jit_tls->handler_block = data.ei;
2523 return TRUE;
2526 #else
2527 gboolean
2528 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
2530 return FALSE;
2533 #endif
2535 void
2536 mono_set_cast_details (MonoClass *from, MonoClass *to)
2538 MonoJitTlsData *jit_tls = NULL;
2540 if (mini_get_debug_options ()->better_cast_details) {
2541 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2542 jit_tls->class_cast_from = from;
2543 jit_tls->class_cast_to = to;
2548 /*returns false if the thread is not attached*/
2549 gboolean
2550 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
2552 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2553 MonoInternalThread *thread = mono_thread_internal_current ();
2554 if (!thread || !thread->jit_data) {
2555 ctx->valid = FALSE;
2556 return FALSE;
2559 if (sigctx)
2560 mono_arch_sigctx_to_monoctx (sigctx, &ctx->ctx);
2561 else
2562 #if MONO_ARCH_HAS_MONO_CONTEXT && !defined(MONO_CROSS_COMPILE)
2563 MONO_CONTEXT_GET_CURRENT (ctx->ctx);
2564 #else
2565 g_error ("Use a null sigctx requires a working mono-context");
2566 #endif
2568 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2569 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2570 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2571 ctx->valid = TRUE;
2572 return TRUE;
2573 #else
2574 g_error ("Implement mono_arch_sigctx_to_monoctx for the current target");
2575 return FALSE;
2576 #endif
2579 gboolean
2580 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
2582 MonoInternalThread *thread = mono_thread_internal_current ();
2583 if (!thread || !thread->jit_data) {
2584 ctx->valid = FALSE;
2585 return FALSE;
2588 ctx->ctx = *mctx;
2589 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2590 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2591 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2592 ctx->valid = TRUE;
2593 return TRUE;
2596 /*returns false if the thread is not attached*/
2597 gboolean
2598 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
2600 MonoInternalThread *thread = mono_thread_internal_current ();
2601 MONO_ARCH_CONTEXT_DEF
2603 mono_arch_flush_register_windows ();
2605 if (!thread || !thread->jit_data) {
2606 ctx->valid = FALSE;
2607 return FALSE;
2609 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
2610 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx->ctx);
2611 #else
2612 MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
2613 #endif
2615 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2616 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2617 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2618 ctx->valid = TRUE;
2619 return TRUE;
2622 static void
2623 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
2625 void (*restore_context) (MonoContext *);
2626 restore_context = mono_get_restore_context ();
2628 mono_handle_exception (ctx, exc);
2629 restore_context (ctx);
2632 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
2633 void
2634 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
2636 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
2637 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
2638 jit_tls->ex_ctx = *ctx;
2640 mono_arch_setup_async_callback (ctx, async_cb, user_data);
2641 #else
2642 g_error ("This target doesn't support mono_arch_setup_async_callback");
2643 #endif