2 * mini-exceptions.c: generic exception support
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Mono Team (mono-list@lists.ximian.com)
8 * Copyright 2001-2003 Ximian, Inc.
9 * Copyright 2003-2008 Ximian, Inc.
17 #ifdef HAVE_EXECINFO_H
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
25 #ifdef HAVE_SYS_WAIT_H
33 #ifdef HAVE_SYS_SYSCALL_H
34 #include <sys/syscall.h>
37 #include <mono/metadata/appdomain.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/threads-types.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include <mono/metadata/exception.h>
43 #include <mono/metadata/gc-internal.h>
44 #include <mono/metadata/mono-debug.h>
45 #include <mono/metadata/profiler.h>
46 #include <mono/utils/mono-mmap.h>
49 #include "debug-mini.h"
51 #include "debugger-agent.h"
53 #ifndef MONO_ARCH_CONTEXT_DEF
54 #define MONO_ARCH_CONTEXT_DEF
57 static gpointer restore_context_func
, call_filter_func
;
58 static gpointer throw_exception_func
, rethrow_exception_func
;
59 static gpointer throw_exception_by_name_func
, throw_corlib_exception_func
;
61 static gpointer try_more_restore_tramp
= NULL
;
62 static gpointer restore_stack_protection_tramp
= NULL
;
64 static void try_more_restore (void);
65 static void restore_stack_protection (void);
66 static void mono_walk_stack_full (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoContext
*start_ctx
, MonoStackFrameWalk func
, gboolean use_new_ctx
, gpointer user_data
);
69 mono_exceptions_init (void)
71 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
76 restore_context_func
= mono_aot_get_named_code ("restore_context");
77 call_filter_func
= mono_aot_get_named_code ("call_filter");
78 throw_exception_func
= mono_aot_get_named_code ("throw_exception");
79 rethrow_exception_func
= mono_aot_get_named_code ("rethrow_exception");
81 restore_context_func
= mono_arch_get_restore_context_full (&code_size
, &ji
, FALSE
);
82 call_filter_func
= mono_arch_get_call_filter_full (&code_size
, &ji
, FALSE
);
83 throw_exception_func
= mono_arch_get_throw_exception_full (&code_size
, &ji
, FALSE
);
84 rethrow_exception_func
= mono_arch_get_rethrow_exception_full (&code_size
, &ji
, FALSE
);
87 restore_context_func
= mono_arch_get_restore_context ();
88 call_filter_func
= mono_arch_get_call_filter ();
89 throw_exception_func
= mono_arch_get_throw_exception ();
90 rethrow_exception_func
= mono_arch_get_rethrow_exception ();
92 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
93 try_more_restore_tramp
= mono_create_specific_trampoline (try_more_restore
, MONO_TRAMPOLINE_RESTORE_STACK_PROT
, mono_domain_get (), NULL
);
94 restore_stack_protection_tramp
= mono_create_specific_trampoline (restore_stack_protection
, MONO_TRAMPOLINE_RESTORE_STACK_PROT
, mono_domain_get (), NULL
);
97 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
98 mono_arch_exceptions_init ();
103 mono_get_throw_exception (void)
105 g_assert (throw_exception_func
);
106 return throw_exception_func
;
110 mono_get_rethrow_exception (void)
112 g_assert (rethrow_exception_func
);
113 return rethrow_exception_func
;
117 mono_get_call_filter (void)
119 g_assert (call_filter_func
);
120 return call_filter_func
;
124 mono_get_restore_context (void)
126 g_assert (restore_context_func
);
127 return restore_context_func
;
131 mono_get_throw_exception_by_name (void)
133 #ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME
135 gpointer code
= NULL
;
136 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
141 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
142 if (throw_exception_by_name_func
)
143 return throw_exception_by_name_func
;
145 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
147 code
= mono_aot_get_named_code ("throw_exception_by_name");
149 code
= mono_arch_get_throw_exception_by_name_full (&code_size
, &ji
, FALSE
);
151 code
= mono_arch_get_throw_exception_by_name ();
154 mono_memory_barrier ();
156 throw_exception_by_name_func
= code
;
160 throw_exception_by_name_func
= NULL
;
162 g_assert_not_reached ();
165 return throw_exception_by_name_func
;
169 mono_get_throw_corlib_exception (void)
171 gpointer code
= NULL
;
172 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
177 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
178 if (throw_corlib_exception_func
)
179 return throw_corlib_exception_func
;
181 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
182 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
184 code
= mono_aot_get_named_code ("throw_corlib_exception");
186 code
= mono_arch_get_throw_corlib_exception_full (&code_size
, &ji
, FALSE
);
188 code
= mono_arch_get_throw_corlib_exception ();
191 g_assert_not_reached ();
194 mono_memory_barrier ();
196 throw_corlib_exception_func
= code
;
198 return throw_corlib_exception_func
;
202 is_address_protected (MonoJitInfo
*ji
, MonoJitExceptionInfo
*ei
, gpointer ip
)
204 MonoTryBlockHoleTableJitInfo
*table
;
209 /*FIXME check if under s390 it should be ei->try_start >= ip*/
210 if (ei
->try_start
> ip
|| ip
>= ei
->try_end
)
213 if (!ji
->has_try_block_holes
)
216 table
= mono_jit_info_get_try_block_hole_table_info (ji
);
217 offset
= (guint32
)((char*)ip
- (char*)ji
->code_start
);
218 clause
= (guint16
)(ei
- ji
->clauses
);
219 g_assert (clause
< ji
->num_clauses
);
221 for (i
= 0; i
< table
->num_holes
; ++i
) {
222 MonoTryBlockHoleJitInfo
*hole
= &table
->holes
[i
];
223 if (hole
->clause
== clause
&& hole
->offset
<= offset
&& hole
->offset
+ hole
->length
> offset
)
229 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
232 * find_jit_info_no_ext:
234 * If the target has the find_jit_info_ext version of this function, define the old
235 * version here which translates between the old and new APIs.
238 find_jit_info_no_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
239 MonoContext
*new_ctx
, MonoLMF
**lmf
, gboolean
*managed
)
241 StackFrameInfo frame
;
244 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
246 /* Avoid costly table lookup during stack overflow */
247 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
250 ji
= mini_jit_info_table_find (domain
, ip
, NULL
);
255 err
= mono_arch_find_jit_info_ext (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, &frame
);
259 /* Convert between the new and the old APIs */
260 switch (frame
.type
) {
261 case FRAME_TYPE_MANAGED
:
265 case FRAME_TYPE_MANAGED_TO_NATIVE
:
269 memset (res
, 0, sizeof (MonoJitInfo
));
270 res
->method
= frame
.method
;
273 case FRAME_TYPE_DEBUGGER_INVOKE
: {
277 * The normal exception handling code can't handle this frame, so just
280 ji
= find_jit_info_no_ext (domain
, jit_tls
, res
, NULL
, new_ctx
, &tmp_ctx
, lmf
, managed
);
281 memcpy (new_ctx
, &tmp_ctx
, sizeof (MonoContext
));
285 g_assert_not_reached ();
292 /* mono_find_jit_info:
294 * This function is used to gather information from @ctx. It return the
295 * MonoJitInfo of the corresponding function, unwinds one stack frame and
296 * stores the resulting context into @new_ctx. It also stores a string
297 * describing the stack location into @trace (if not NULL), and modifies
298 * the @lmf if necessary. @native_offset return the IP offset from the
299 * start of the function or -1 if that info is not available.
302 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
303 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
307 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
319 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
320 ji
= find_jit_info_no_ext (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
322 ji
= mono_arch_find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
325 if (ji
== (gpointer
)-1)
328 if (managed2
|| (ji
&& ji
->method
->wrapper_type
)) {
329 const char *real_ip
, *start
;
332 start
= (const char *)ji
->code_start
;
334 /* ctx->ip points into native code */
335 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
337 real_ip
= (const char*)ip
;
339 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
340 offset
= real_ip
- start
;
345 *native_offset
= offset
;
348 if (!ji
->method
->wrapper_type
)
352 *trace
= mono_debug_print_stack_frame (ji
->method
, offset
, domain
);
355 char *fname
= mono_method_full_name (res
->method
, TRUE
);
356 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
364 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
367 * mono_find_jit_info_ext:
369 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
373 mono_find_jit_info_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
374 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
375 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
376 StackFrameInfo
*frame
)
379 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
381 MonoDomain
*target_domain
;
386 /* Avoid costly table lookup during stack overflow */
387 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
390 ji
= mini_jit_info_table_find (domain
, ip
, &target_domain
);
393 target_domain
= domain
;
395 err
= mono_arch_find_jit_info_ext (target_domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, frame
);
399 frame
->native_offset
= -1;
400 frame
->domain
= target_domain
;
404 if (ji
&& (frame
->managed
|| ji
->method
->wrapper_type
)) {
405 const char *real_ip
, *start
;
407 start
= (const char *)ji
->code_start
;
409 /* ctx->ip points into native code */
410 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
412 real_ip
= (const char*)ip
;
414 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
415 frame
->native_offset
= real_ip
- start
;
417 frame
->native_offset
= -1;
420 *trace
= mono_debug_print_stack_frame (ji
->method
, frame
->native_offset
, domain
);
422 if (trace
&& frame
->method
) {
423 char *fname
= mono_method_full_name (frame
->method
, TRUE
);
424 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
432 #endif /* MONO_ARCH_HAVE_FIND_JIT_INFO_EXT */
435 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
437 MonoGenericJitInfo
*gi
;
440 if (!ji
->has_generic_jit_info
)
442 gi
= mono_jit_info_get_generic_jit_info (ji
);
447 info
= mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
449 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
451 if (mono_method_get_context (ji
->method
)->method_inst
) {
453 } else if ((ji
->method
->flags
& METHOD_ATTRIBUTE_STATIC
) || ji
->method
->klass
->valuetype
) {
456 /* Avoid returning a managed object */
457 MonoObject
*this_obj
= info
;
459 return this_obj
->vtable
->klass
;
463 static MonoGenericContext
464 get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
466 MonoGenericContext context
= { NULL
, NULL
};
467 MonoClass
*class, *method_container_class
;
469 g_assert (generic_info
);
471 g_assert (ji
->method
->is_inflated
);
472 if (mono_method_get_context (ji
->method
)->method_inst
) {
473 MonoMethodRuntimeGenericContext
*mrgctx
= generic_info
;
475 class = mrgctx
->class_vtable
->klass
;
476 context
.method_inst
= mrgctx
->method_inst
;
477 g_assert (context
.method_inst
);
478 } else if ((ji
->method
->flags
& METHOD_ATTRIBUTE_STATIC
) || ji
->method
->klass
->valuetype
) {
479 MonoVTable
*vtable
= generic_info
;
481 class = vtable
->klass
;
483 class = generic_info
;
486 //g_assert (!ji->method->klass->generic_container);
487 if (ji
->method
->klass
->generic_class
)
488 method_container_class
= ji
->method
->klass
->generic_class
->container_class
;
490 method_container_class
= ji
->method
->klass
;
492 /* class might refer to a subclass of ji->method's class */
493 while (class->generic_class
&& class->generic_class
->container_class
!= method_container_class
) {
494 class = class->parent
;
498 if (class->generic_class
|| class->generic_container
)
499 context
.class_inst
= mini_class_get_context (class)->class_inst
;
501 if (class->generic_class
)
502 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class
->container_class
, method_container_class
));
504 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class
));
510 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
512 MonoGenericContext context
;
515 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
517 context
= get_generic_context_from_stack_frame (ji
, generic_info
);
519 method
= mono_method_get_declaring_generic_method (ji
->method
);
520 method
= mono_class_inflate_generic_method (method
, &context
);
526 ves_icall_System_Exception_get_trace (MonoException
*ex
)
528 MonoDomain
*domain
= mono_domain_get ();
530 MonoArray
*ta
= ex
->trace_ips
;
535 /* Exception is not thrown yet */
538 len
= mono_array_length (ta
) >> 1;
539 trace_str
= g_string_new ("");
540 for (i
= 0; i
< len
; i
++) {
542 gpointer ip
= mono_array_get (ta
, gpointer
, i
* 2 + 0);
543 gpointer generic_info
= mono_array_get (ta
, gpointer
, i
* 2 + 1);
545 ji
= mono_jit_info_table_find (domain
, ip
);
547 /* Unmanaged frame */
548 g_string_append_printf (trace_str
, "in (unmanaged) %p\n", ip
);
552 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
554 address
= (char *)ip
- (char *)ji
->code_start
;
555 location
= mono_debug_print_stack_frame (
556 method
, address
, ex
->object
.vtable
->domain
);
558 g_string_append_printf (trace_str
, "%s\n", location
);
563 res
= mono_string_new (ex
->object
.vtable
->domain
, trace_str
->str
);
564 g_string_free (trace_str
, TRUE
);
570 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
572 MonoDomain
*domain
= mono_domain_get ();
574 MonoArray
*ta
= exc
->trace_ips
;
575 MonoDebugSourceLocation
*location
;
579 /* Exception is not thrown yet */
580 return mono_array_new (domain
, mono_defaults
.stack_frame_class
, 0);
583 len
= mono_array_length (ta
) >> 1;
585 res
= mono_array_new (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0);
587 for (i
= skip
; i
< len
; i
++) {
589 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new (domain
, mono_defaults
.stack_frame_class
);
590 gpointer ip
= mono_array_get (ta
, gpointer
, i
* 2 + 0);
591 gpointer generic_info
= mono_array_get (ta
, gpointer
, i
* 2 + 1);
594 ji
= mono_jit_info_table_find (domain
, ip
);
596 /* Unmanaged frame */
597 mono_array_setref (res
, i
, sf
);
601 g_assert (ji
!= NULL
);
603 method
= get_method_from_stack_frame (ji
, generic_info
);
604 if (ji
->method
->wrapper_type
) {
608 s
= mono_method_full_name (method
, TRUE
);
609 MONO_OBJECT_SETREF (sf
, internal_method_name
, mono_string_new (domain
, s
));
613 MONO_OBJECT_SETREF (sf
, method
, mono_method_get_object (domain
, method
, NULL
));
614 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
617 * mono_debug_lookup_source_location() returns both the file / line number information
618 * and the IL offset. Note that computing the IL offset is already an expensive
619 * operation, so we shouldn't call this method twice.
621 location
= mono_debug_lookup_source_location (ji
->method
, sf
->native_offset
, domain
);
623 sf
->il_offset
= location
->il_offset
;
627 if (need_file_info
) {
628 if (location
&& location
->source_file
) {
629 MONO_OBJECT_SETREF (sf
, filename
, mono_string_new (domain
, location
->source_file
));
630 sf
->line
= location
->row
;
631 sf
->column
= location
->column
;
633 sf
->line
= sf
->column
= 0;
638 mono_debug_free_source_location (location
);
639 mono_array_setref (res
, i
, sf
);
647 * @domain: starting appdomain
648 * @jit_tls: JIT data for the thread
649 * @start_ctx: starting state of the stack frame
650 * @func: callback to call for each stack frame
651 * @user_data: data passed to the callback
653 * This function walks the stack of a thread, starting from the state
654 * represented by jit_tls and start_ctx. For each frame the callback
655 * function is called with the relevant info. The walk ends when no more
656 * managed stack frames are found or when the callback returns a TRUE value.
657 * Note that the function can be used to walk the stack of a thread
658 * different from the current.
661 mono_walk_stack (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoContext
*start_ctx
, MonoStackFrameWalk func
, gpointer user_data
)
663 mono_walk_stack_full (domain
, jit_tls
, start_ctx
, func
, TRUE
, user_data
);
667 mono_walk_stack_full (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoContext
*start_ctx
, MonoStackFrameWalk func
, gboolean use_new_ctx
, gpointer user_data
)
669 MonoLMF
*lmf
= mono_get_lmf ();
670 MonoJitInfo
*ji
, rji
;
673 MonoContext ctx
, new_ctx
;
677 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
679 * FIXME: mono_find_jit_info () will need to be able to return a different
680 * MonoDomain when apddomain transitions are found on the stack.
682 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
683 if (!ji
|| ji
== (gpointer
)-1)
686 if (func (domain
, use_new_ctx
? &new_ctx
: &ctx
, ji
, user_data
))
694 mono_jit_walk_stack_from_ctx (MonoStackWalk func
, MonoContext
*start_ctx
, gboolean do_il_offset
, gpointer user_data
)
696 MonoDomain
*domain
= mono_domain_get ();
697 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
698 MonoLMF
*lmf
= mono_get_lmf ();
699 MonoJitInfo
*ji
, rji
;
700 gint native_offset
, il_offset
;
702 MonoContext ctx
, new_ctx
;
704 MONO_ARCH_CONTEXT_DEF
706 mono_arch_flush_register_windows ();
709 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
711 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
712 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
714 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_jit_walk_stack_from_ctx
);
718 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
719 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
722 if (ji
== (gpointer
)-1)
726 MonoDebugSourceLocation
*source
;
728 source
= mono_debug_lookup_source_location (ji
->method
, native_offset
, domain
);
729 il_offset
= source
? source
->il_offset
: -1;
730 mono_debug_free_source_location (source
);
734 if (func (ji
->method
, native_offset
, il_offset
, managed
, user_data
))
742 mono_jit_walk_stack (MonoStackWalk func
, gboolean do_il_offset
, gpointer user_data
)
744 mono_jit_walk_stack_from_ctx (func
, NULL
, do_il_offset
, user_data
);
748 mono_jit_walk_stack_from_ctx_in_thread (MonoJitStackWalk func
, MonoDomain
*domain
, MonoContext
*start_ctx
, gboolean do_il_offset
, MonoInternalThread
*thread
, MonoLMF
*lmf
, gpointer user_data
)
750 MonoJitTlsData
*jit_tls
= thread
->jit_data
;
752 MonoContext ctx
, new_ctx
;
753 StackFrameInfo frame
;
754 #ifndef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
757 MonoJitInfo
*ji
, rji
;
762 MONO_ARCH_CONTEXT_DEF
764 mono_arch_flush_register_windows ();
767 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
769 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
770 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
772 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_jit_walk_stack_from_ctx
);
774 g_assert (thread
== mono_thread_internal_current ());
777 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
779 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
780 res
= mono_find_jit_info_ext (domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &frame
);
784 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
786 frame
.type
= FRAME_TYPE_MANAGED
;
788 frame
.managed
= managed
;
789 frame
.native_offset
= native_offset
;
791 if (ji
== (gpointer
)-1)
795 if (do_il_offset
&& frame
.ji
) {
796 MonoDebugSourceLocation
*source
;
798 source
= mono_debug_lookup_source_location (frame
.ji
->method
, frame
.native_offset
, domain
);
799 il_offset
= source
? source
->il_offset
: -1;
800 mono_debug_free_source_location (source
);
804 frame
.il_offset
= il_offset
;
806 if (func (&frame
, &ctx
, user_data
))
815 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
816 MonoReflectionMethod
**method
,
817 gint32
*iloffset
, gint32
*native_offset
,
818 MonoString
**file
, gint32
*line
, gint32
*column
)
820 MonoDomain
*domain
= mono_domain_get ();
821 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
822 MonoLMF
*lmf
= mono_get_lmf ();
823 MonoJitInfo
*ji
, rji
;
824 MonoContext ctx
, new_ctx
, ji_ctx
;
825 MonoDebugSourceLocation
*location
;
826 MonoMethod
*last_method
= NULL
, *actual_method
;
828 MONO_ARCH_CONTEXT_DEF
;
830 mono_arch_flush_register_windows ();
832 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
833 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
835 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
840 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, (int*) native_offset
, NULL
);
843 if (ji
&& ji
!= (gpointer
)-1 &&
844 MONO_CONTEXT_GET_IP (&ctx
) >= ji
->code_start
&&
845 (guint8
*)MONO_CONTEXT_GET_IP (&ctx
) < (guint8
*)ji
->code_start
+ ji
->code_size
) {
849 if (!ji
|| ji
== (gpointer
)-1 || MONO_CONTEXT_GET_SP (&ctx
) >= jit_tls
->end_of_stack
)
852 /* skip all wrappers ??*/
853 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
854 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
855 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
856 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
857 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
||
858 ji
->method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
)
861 if (ji
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
&& ji
->method
== last_method
) {
863 * FIXME: Native-to-managed wrappers sometimes show up twice.
864 * Probably the whole mono_find_jit_info () stuff needs to be fixed so this
870 last_method
= ji
->method
;
876 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &ji_ctx
));
878 mono_gc_wbarrier_generic_store (method
, (MonoObject
*) mono_method_get_object (domain
, actual_method
, NULL
));
880 location
= mono_debug_lookup_source_location (ji
->method
, *native_offset
, domain
);
882 *iloffset
= location
->il_offset
;
886 if (need_file_info
) {
888 mono_gc_wbarrier_generic_store (file
, (MonoObject
*) mono_string_new (domain
, location
->source_file
));
889 *line
= location
->row
;
890 *column
= location
->column
;
897 mono_debug_free_source_location (location
);
904 MonoSecurityFrame
*frame
;
905 } MonoFrameSecurityInfo
;
908 callback_get_first_frame_security_info (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
910 MonoFrameSecurityInfo
*si
= (MonoFrameSecurityInfo
*) data
;
912 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
913 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
914 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
915 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
916 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
917 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
) {
926 si
->frame
= mono_declsec_create_frame (domain
, ji
);
928 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
933 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
934 * @skip: the number of stack frames to skip
936 * This function returns a the security informations of a single stack frame
937 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
938 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
942 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip
)
944 MonoDomain
*domain
= mono_domain_get ();
945 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
946 MonoFrameSecurityInfo si
;
949 MONO_ARCH_CONTEXT_DEF
951 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
952 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
954 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_System_Security_SecurityFrame_GetSecurityFrame
);
957 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
963 mono_walk_stack (domain
, jit_tls
, &ctx
, callback_get_first_frame_security_info
, (gpointer
)&si
);
965 return (si
.skips
== 0) ? si
.frame
: NULL
;
977 grow_array (MonoSecurityStack
*stack
)
979 MonoDomain
*domain
= mono_domain_get ();
980 guint32 newsize
= (stack
->maximum
<< 1);
981 MonoArray
*newstack
= mono_array_new (domain
, mono_defaults
.runtimesecurityframe_class
, newsize
);
983 for (i
=0; i
< stack
->maximum
; i
++) {
984 gpointer frame
= mono_array_get (stack
->stack
, gpointer
, i
);
985 mono_array_setref (newstack
, i
, frame
);
987 stack
->maximum
= newsize
;
988 stack
->stack
= newstack
;
992 callback_get_stack_frames_security_info (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
994 MonoSecurityStack
*ss
= (MonoSecurityStack
*) data
;
996 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
997 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
998 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
999 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
1000 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
1001 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
) {
1005 if (ss
->skips
> 0) {
1010 if (ss
->count
== ss
->maximum
)
1013 mono_array_setref (ss
->stack
, ss
->count
++, mono_declsec_create_frame (domain
, ji
));
1015 /* continue down the stack */
1020 glist_to_array (GList
*list
, MonoClass
*eclass
)
1022 MonoDomain
*domain
= mono_domain_get ();
1029 len
= g_list_length (list
);
1030 res
= mono_array_new (domain
, eclass
, len
);
1032 for (i
= 0; list
; list
= list
->next
, i
++)
1033 mono_array_set (res
, gpointer
, i
, list
->data
);
1039 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
1040 * @skip: the number of stack frames to skip
1042 * This function returns an managed array of containing the security
1043 * informations for each frame (after the skipped ones). This is used for
1044 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
1048 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip
)
1050 MonoDomain
*domain
= mono_domain_get ();
1051 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1052 MonoSecurityStack ss
;
1055 MONO_ARCH_CONTEXT_DEF
1057 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1058 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
1060 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_System_Security_SecurityFrame_GetSecurityStack
);
1063 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
1069 ss
.maximum
= MONO_CAS_INITIAL_STACK_SIZE
;
1070 ss
.stack
= mono_array_new (domain
, mono_defaults
.runtimesecurityframe_class
, ss
.maximum
);
1071 mono_walk_stack (domain
, jit_tls
, &ctx
, callback_get_stack_frames_security_info
, (gpointer
)&ss
);
1072 /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
1077 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
1079 MonoClass
*catch_class
= ei
->data
.catch_class
;
1080 MonoType
*inflated_type
;
1081 MonoGenericContext context
;
1083 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1084 if (!catch_class
|| ei
->flags
!= MONO_EXCEPTION_CLAUSE_NONE
)
1087 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
1089 context
= get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
1091 /* FIXME: we shouldn't inflate but instead put the
1092 type in the rgctx and fetch it from there. It
1093 might be a good idea to do this lazily, i.e. only
1094 when the exception is actually thrown, so as not to
1095 waste space for exception clauses which might never
1097 inflated_type
= mono_class_inflate_generic_type (&catch_class
->byval_arg
, &context
);
1098 catch_class
= mono_class_from_mono_type (inflated_type
);
1099 mono_metadata_free_type (inflated_type
);
1105 * mini_jit_info_table_find:
1107 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1108 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1109 * OUT_DOMAIN if it is not NULL.
1112 mini_jit_info_table_find (MonoDomain
*domain
, char *addr
, MonoDomain
**out_domain
)
1115 MonoInternalThread
*t
= mono_thread_internal_current ();
1121 ji
= mono_jit_info_table_find (domain
, addr
);
1124 *out_domain
= domain
;
1128 /* maybe it is shared code, so we also search in the root domain */
1129 if (domain
!= mono_get_root_domain ()) {
1130 ji
= mono_jit_info_table_find (mono_get_root_domain (), addr
);
1133 *out_domain
= mono_get_root_domain ();
1138 for (l
= t
->appdomain_refs
; l
; l
= l
->next
) {
1139 if (l
->data
!= domain
) {
1140 ji
= mono_jit_info_table_find ((MonoDomain
*)l
->data
, addr
);
1143 *out_domain
= (MonoDomain
*)l
->data
;
1153 * mono_handle_exception_internal:
1154 * @ctx: saved processor state
1155 * @obj: the exception object
1156 * @test_only: only test if the exception is caught, but dont call handlers
1157 * @out_filter_idx: out parameter. if test_only is true, set to the index of
1158 * the first filter clause which caught the exception.
1159 * @resume: whenever to resume unwinding based on the state in MonoJitTlsData.
1162 mono_handle_exception_internal (MonoContext
*ctx
, gpointer obj
, gpointer original_ip
, gboolean test_only
, gboolean resume
, gint32
*out_filter_idx
, MonoJitInfo
**out_ji
)
1164 MonoDomain
*domain
= mono_domain_get ();
1165 MonoJitInfo
*ji
, rji
;
1166 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
1167 static void (*restore_context
) (void *);
1168 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1169 MonoLMF
*lmf
= mono_get_lmf ();
1170 MonoArray
*initial_trace_ips
= NULL
;
1171 GList
*trace_ips
= NULL
;
1172 MonoException
*mono_ex
;
1173 gboolean stack_overflow
= FALSE
;
1174 MonoContext initial_ctx
;
1175 int frame_count
= 0;
1176 gboolean has_dynamic_methods
= FALSE
;
1177 gint32 filter_idx
, first_filter_idx
;
1180 g_assert (ctx
!= NULL
);
1182 MonoException
*ex
= mono_get_exception_null_reference ();
1183 MONO_OBJECT_SETREF (ex
, message
, mono_string_new (domain
, "Object reference not set to an instance of an object"));
1184 obj
= (MonoObject
*)ex
;
1188 * Allocate a new exception object instead of the preconstructed ones.
1190 if (obj
== domain
->stack_overflow_ex
) {
1192 * It is not a good idea to try and put even more pressure on the little stack available.
1193 * obj = mono_get_exception_stack_overflow ();
1195 stack_overflow
= TRUE
;
1197 else if (obj
== domain
->null_reference_ex
) {
1198 obj
= mono_get_exception_null_reference ();
1201 if (mono_object_isinst (obj
, mono_defaults
.exception_class
)) {
1202 mono_ex
= (MonoException
*)obj
;
1203 initial_trace_ips
= mono_ex
->trace_ips
;
1208 if (mono_ex
&& jit_tls
->class_cast_from
&& !strcmp (mono_ex
->object
.vtable
->klass
->name
, "InvalidCastException")) {
1209 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
1210 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
1211 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
1212 mono_ex
->message
= mono_string_new (domain
, msg
);
1219 call_filter
= mono_get_call_filter ();
1221 if (!restore_context
)
1222 restore_context
= mono_get_restore_context ();
1224 g_assert (jit_tls
->end_of_stack
);
1225 g_assert (jit_tls
->abort_func
);
1228 MonoContext ctx_cp
= *ctx
;
1229 if (mono_trace_is_enabled ()) {
1230 MonoMethod
*system_exception_get_message
= mono_class_get_method_from_name (mono_defaults
.exception_class
, "get_Message", 0);
1231 MonoMethod
*get_message
= system_exception_get_message
== NULL
? NULL
: mono_object_get_virtual_method (obj
, system_exception_get_message
);
1232 MonoObject
*message
;
1233 const char *type_name
= mono_class_get_name (mono_object_class (mono_ex
));
1235 MonoObject
*exc
= NULL
;
1236 if (get_message
== NULL
) {
1238 } else if (!strcmp (type_name
, "OutOfMemoryException") || !strcmp (type_name
, "StackOverflowException")) {
1240 msg
= g_strdup_printf ("(No exception message for: %s)\n", type_name
);
1242 message
= mono_runtime_invoke (get_message
, obj
, NULL
, &exc
);
1246 msg
= message
? mono_string_to_utf8 ((MonoString
*) message
) : g_strdup ("(System.Exception.Message property not available)");
1248 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj
)->name_space
, mono_object_class (obj
)->name
, msg
);
1250 if (mono_ex
&& mono_trace_eval_exception (mono_object_class (mono_ex
)))
1251 mono_print_thread_dump_from_ctx (ctx
);
1253 mono_profiler_exception_thrown (obj
);
1254 if (!mono_handle_exception_internal (&ctx_cp
, obj
, original_ip
, TRUE
, FALSE
, &first_filter_idx
, out_ji
)) {
1255 if (mono_break_on_exc
)
1257 mono_debugger_agent_handle_exception (obj
, ctx
, NULL
);
1258 // FIXME: This runs managed code so it might cause another stack overflow when
1259 // we are handling a stack overflow
1260 mono_unhandled_exception (obj
);
1262 mono_debugger_agent_handle_exception (obj
, ctx
, &ctx_cp
);
1267 *out_filter_idx
= -1;
1272 memset (&rji
, 0, sizeof (rji
));
1275 MonoContext new_ctx
;
1278 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, &rji
, ctx
, &new_ctx
,
1279 NULL
, &lmf
, NULL
, NULL
);
1281 g_warning ("Exception inside function without unwind info");
1282 g_assert_not_reached ();
1285 if (ji
!= (gpointer
)-1 && !(ji
->code_start
<= MONO_CONTEXT_GET_IP (ctx
) && (((guint8
*)ji
->code_start
+ ji
->code_size
>= (guint8
*)MONO_CONTEXT_GET_IP (ctx
))))) {
1287 * The exception was raised in native code and we got back to managed code
1294 if (ji
!= (gpointer
)-1) {
1296 //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
1298 if (test_only
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
1300 * Avoid overwriting the stack trace if the exception is
1301 * rethrown. Also avoid giant stack traces during a stack
1304 if (!initial_trace_ips
&& (frame_count
< 1000)) {
1305 trace_ips
= g_list_prepend (trace_ips
, MONO_CONTEXT_GET_IP (ctx
));
1306 trace_ips
= g_list_prepend (trace_ips
,
1307 get_generic_info_from_stack_frame (ji
, ctx
));
1311 if (ji
->method
->dynamic
)
1312 has_dynamic_methods
= TRUE
;
1315 #ifndef MONO_ARCH_STACK_GROWS_UP
1316 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
1318 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (ctx
));
1321 free_stack
= 0xffffff;
1324 * During stack overflow, wait till the unwinding frees some stack
1325 * space before running handlers/finalizers.
1327 if ((free_stack
> (64 * 1024)) && ji
->num_clauses
) {
1330 for (i
= 0; i
< ji
->num_clauses
; i
++) {
1331 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
1332 gboolean filtered
= FALSE
;
1334 #if defined(__s390__)
1336 * This is required in cases where a try block starts immediately after
1337 * a call which causes an exception. Testcase: tests/exception8.cs.
1338 * FIXME: Clean this up.
1340 if (ei
->try_start
< MONO_CONTEXT_GET_IP (ctx
) && MONO_CONTEXT_GET_IP (ctx
) <= ei
->try_end
) {
1342 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (ctx
))) {
1345 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
1347 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
)) {
1348 if (ji
->from_llvm
) {
1349 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1350 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, obj
);
1352 g_assert_not_reached ();
1355 /* store the exception object in bp + ei->exvar_offset */
1356 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = obj
;
1360 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
1362 mono_perfcounters
->exceptions_filters
++;
1363 mono_debugger_call_exception_handler (ei
->data
.filter
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1364 filtered
= call_filter (ctx
, ei
->data
.filter
);
1365 if (filtered
&& out_filter_idx
)
1366 *out_filter_idx
= filter_idx
;
1372 * Filter clauses should only be run in the
1373 * first pass of exception handling.
1375 filtered
= (filter_idx
== first_filter_idx
);
1380 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
1381 mono_object_isinst (obj
, catch_class
)) || filtered
) {
1383 if (mono_ex
&& !initial_trace_ips
) {
1384 trace_ips
= g_list_reverse (trace_ips
);
1385 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, glist_to_array (trace_ips
, mono_defaults
.int_class
));
1386 if (has_dynamic_methods
)
1387 /* These methods could go away anytime, so compute the stack trace now */
1388 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, ves_icall_System_Exception_get_trace (mono_ex
));
1390 g_list_free (trace_ips
);
1395 * This guards against the situation that we abort a thread that is executing a finally clause
1396 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
1397 * check for this situation here and resume interruption if we are below the guarded block.
1399 if (G_UNLIKELY (jit_tls
->handler_block_return_address
)) {
1400 gboolean is_outside
= FALSE
;
1401 gpointer prot_bp
= MONO_CONTEXT_GET_BP (&jit_tls
->ex_ctx
);
1402 gpointer catch_bp
= MONO_CONTEXT_GET_BP (ctx
);
1403 //FIXME make this stack direction aware
1404 if (catch_bp
> prot_bp
) {
1406 } else if (catch_bp
== prot_bp
) {
1407 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
1408 * So we check if the catch handler_start is protected by the guarded handler protected region
1411 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
1412 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
1413 * There aren't any further finally/fault handler blocks down the stack over this exception.
1414 * This must be ensured by the code that installs the guard trampoline.
1416 g_assert (ji
== mini_jit_info_table_find (domain
, MONO_CONTEXT_GET_IP (&jit_tls
->ex_ctx
), NULL
));
1418 if (!is_address_protected (ji
, jit_tls
->handler_block
, ei
->handler_start
)) {
1423 jit_tls
->handler_block_return_address
= NULL
;
1424 jit_tls
->handler_block
= NULL
;
1425 mono_thread_resume_interruption (); /*We ignore the exception here, it will be raised later*/
1429 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1430 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1431 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1432 mono_debugger_call_exception_handler (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1433 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
1434 *(mono_get_lmf_addr ()) = lmf
;
1435 mono_perfcounters
->exceptions_depth
+= frame_count
;
1436 if (obj
== domain
->stack_overflow_ex
)
1437 jit_tls
->handling_stack_ovf
= FALSE
;
1441 if (!test_only
&& is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (ctx
)) &&
1442 (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
)) {
1443 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1444 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1445 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1446 mono_debugger_call_exception_handler (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1447 call_filter (ctx
, ei
->handler_start
);
1449 if (!test_only
&& is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (ctx
)) &&
1450 (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
)) {
1451 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1452 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1453 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1454 mono_debugger_call_exception_handler (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1455 mono_perfcounters
->exceptions_finallys
++;
1456 *(mono_get_lmf_addr ()) = lmf
;
1457 if (ji
->from_llvm
) {
1459 * LLVM compiled finally handlers follow the design
1460 * of the c++ ehabi, i.e. they call a resume function
1461 * at the end instead of returning to the caller.
1462 * So save the exception handling state,
1463 * mono_resume_unwind () will call us again to continue
1466 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
1467 *(mono_get_lmf_addr ()) = lmf
;
1468 jit_tls
->ex_ctx
= new_ctx
;
1469 jit_tls
->ex_obj
= obj
;
1472 call_filter (ctx
, ei
->handler_start
);
1480 mono_profiler_exception_method_leave (ji
->method
);
1485 if (ji
== (gpointer
)-1) {
1488 *(mono_get_lmf_addr ()) = lmf
;
1490 jit_tls
->abort_func (obj
);
1491 g_assert_not_reached ();
1493 if (mono_ex
&& !initial_trace_ips
) {
1494 trace_ips
= g_list_reverse (trace_ips
);
1495 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, glist_to_array (trace_ips
, mono_defaults
.int_class
));
1496 if (has_dynamic_methods
)
1497 /* These methods could go away anytime, so compute the stack trace now */
1498 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, ves_icall_System_Exception_get_trace (mono_ex
));
1500 g_list_free (trace_ips
);
1506 g_assert_not_reached ();
1510 * mono_debugger_handle_exception:
1512 * Notify the debugger about exceptions. Returns TRUE if the debugger wants us to stop
1513 * at the exception and FALSE to resume with the normal exception handling.
1515 * The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
1516 * MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
1517 * `callq throw' instruction.
1520 mono_debugger_handle_exception (MonoContext
*ctx
, MonoObject
*obj
)
1522 MonoDebuggerExceptionAction action
;
1524 if (!mono_debug_using_mono_debugger ())
1528 MonoException
*ex
= mono_get_exception_null_reference ();
1529 MONO_OBJECT_SETREF (ex
, message
, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
1530 obj
= (MonoObject
*)ex
;
1533 action
= _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx
), MONO_CONTEXT_GET_SP (ctx
), obj
);
1535 if (action
== MONO_DEBUGGER_EXCEPTION_ACTION_STOP
) {
1537 * The debugger wants us to stop on the `throw' instruction.
1538 * By the time we get here, it already inserted a breakpoint there.
1541 } else if (action
== MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED
) {
1542 MonoContext ctx_cp
= *ctx
;
1543 MonoJitInfo
*ji
= NULL
;
1547 * The debugger wants us to stop only if this exception is user-unhandled.
1550 ret
= mono_handle_exception_internal (&ctx_cp
, obj
, MONO_CONTEXT_GET_IP (ctx
), TRUE
, FALSE
, NULL
, &ji
);
1551 if (ret
&& (ji
!= NULL
) && (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
)) {
1553 * The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
1554 * inside the method being invoked, so we handle it like a user-unhandled exception.
1561 * The exception is user-unhandled - tell the debugger to stop.
1563 return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx
), MONO_CONTEXT_GET_SP (ctx
), obj
);
1567 * The exception is catched somewhere - resume with the normal exception handling and don't
1568 * stop in the debugger.
1576 * mono_debugger_run_finally:
1577 * @start_ctx: saved processor state
1579 * This method is called by the Mono Debugger to call all `finally' clauses of the
1580 * current stack frame. It's used when the user issues a `return' command to make
1581 * the current stack frame return. After returning from this method, the debugger
1582 * unwinds the stack one frame and gives control back to the user.
1584 * NOTE: This method is only used when running inside the Mono Debugger.
1587 mono_debugger_run_finally (MonoContext
*start_ctx
)
1589 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
1590 MonoDomain
*domain
= mono_domain_get ();
1591 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1592 MonoLMF
*lmf
= mono_get_lmf ();
1593 MonoContext ctx
, new_ctx
;
1594 MonoJitInfo
*ji
, rji
;
1599 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
1600 if (!ji
|| ji
== (gpointer
)-1)
1604 call_filter
= mono_get_call_filter ();
1606 for (i
= 0; i
< ji
->num_clauses
; i
++) {
1607 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
1609 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (&ctx
)) &&
1610 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
1611 call_filter (&ctx
, ei
->handler_start
);
1617 * mono_handle_exception:
1618 * @ctx: saved processor state
1619 * @obj: the exception object
1620 * @test_only: only test if the exception is caught, but dont call handlers
1623 mono_handle_exception (MonoContext
*ctx
, gpointer obj
, gpointer original_ip
, gboolean test_only
)
1626 mono_perfcounters
->exceptions_thrown
++;
1628 return mono_handle_exception_internal (ctx
, obj
, original_ip
, test_only
, FALSE
, NULL
, NULL
);
1631 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1633 #ifndef MONO_ARCH_USE_SIGACTION
1634 #error "Can't use sigaltstack without sigaction"
1637 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1640 mono_setup_altstack (MonoJitTlsData
*tls
)
1643 struct sigaltstack sa
;
1644 guint8
*staddr
= NULL
;
1646 if (mono_running_on_valgrind ())
1649 mono_thread_get_stack_bounds (&staddr
, &stsize
);
1653 tls
->end_of_stack
= staddr
+ stsize
;
1655 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1657 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
1658 tls
->stack_ovf_guard_size
= ALIGN_TO (8 * 4096, mono_pagesize ());
1660 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
1661 /* mprotect can fail for the main thread stack */
1662 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
);
1663 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
1664 tls
->stack_ovf_valloced
= TRUE
;
1668 * threads created by nptl does not seem to have a guard page, and
1669 * since the main thread is not created by us, we can't even set one.
1670 * Increasing stsize fools the SIGSEGV signal handler into thinking this
1671 * is a stack overflow exception.
1673 tls
->stack_size
= stsize
+ mono_pagesize ();
1675 /* Setup an alternate signal stack */
1676 tls
->signal_stack
= mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MMAP_READ
|MONO_MMAP_WRITE
|MONO_MMAP_PRIVATE
|MONO_MMAP_ANON
);
1677 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1679 g_assert (tls
->signal_stack
);
1681 sa
.ss_sp
= tls
->signal_stack
;
1682 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1683 sa
.ss_flags
= SS_ONSTACK
;
1684 sigaltstack (&sa
, NULL
);
1688 mono_free_altstack (MonoJitTlsData
*tls
)
1690 struct sigaltstack sa
;
1693 sa
.ss_sp
= tls
->signal_stack
;
1694 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1695 sa
.ss_flags
= SS_DISABLE
;
1696 err
= sigaltstack (&sa
, NULL
);
1697 g_assert (err
== 0);
1699 if (tls
->signal_stack
)
1700 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
);
1701 if (tls
->stack_ovf_valloced
)
1702 mono_vfree (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
);
1704 mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
1707 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1710 mono_setup_altstack (MonoJitTlsData
*tls
)
1715 mono_free_altstack (MonoJitTlsData
*tls
)
1719 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1722 try_restore_stack_protection (MonoJitTlsData
*jit_tls
, int extra_bytes
)
1724 gint32 unprotect_size
= jit_tls
->stack_ovf_guard_size
;
1725 /* we need to leave some room for throwing the exception */
1726 while (unprotect_size
>= 0 && (char*)jit_tls
->stack_ovf_guard_base
+ unprotect_size
> ((char*)&unprotect_size
- extra_bytes
))
1727 unprotect_size
-= mono_pagesize ();
1728 /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1729 * is sufficient stack
1731 //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);
1733 mono_mprotect (jit_tls
->stack_ovf_guard_base
, unprotect_size
, MONO_MMAP_NONE
);
1734 return unprotect_size
== jit_tls
->stack_ovf_guard_size
;
1738 try_more_restore (void)
1740 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1741 if (try_restore_stack_protection (jit_tls
, 500))
1742 jit_tls
->restore_stack_prot
= NULL
;
1746 restore_stack_protection (void)
1748 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1749 MonoException
*ex
= mono_domain_get ()->stack_overflow_ex
;
1750 /* if we can't restore the stack protection, keep a callback installed so
1751 * we'll try to restore as much stack as we can at each return from unmanaged
1754 if (try_restore_stack_protection (jit_tls
, 4096))
1755 jit_tls
->restore_stack_prot
= NULL
;
1757 jit_tls
->restore_stack_prot
= try_more_restore_tramp
;
1758 /* here we also throw a stack overflow exception */
1759 ex
->trace_ips
= NULL
;
1760 ex
->stack_trace
= NULL
;
1761 mono_raise_exception (ex
);
1765 mono_altstack_restore_prot (mgreg_t
*regs
, guint8
*code
, gpointer
*tramp_data
, guint8
* tramp
)
1767 void (*func
)(void) = (gpointer
)tramp_data
;
1773 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, guint8
* fault_addr
)
1775 /* we got a stack overflow in the soft-guard pages
1776 * There are two cases:
1777 * 1) managed code caused the overflow: we unprotect the soft-guard page
1778 * and let the arch-specific code trigger the exception handling mechanism
1779 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1780 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1781 * and hope we can continue with those enabled, at least until the hard-guard page
1782 * is hit. The alternative to continuing here is to just print a message and abort.
1783 * We may add in the future the code to protect the pages again in the codepath
1784 * when we return from unmanaged to managed code.
1786 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
1787 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
1788 /* we unprotect the minimum amount we can */
1790 gboolean handled
= FALSE
;
1792 guard_size
= jit_tls
->stack_ovf_guard_size
- (mono_pagesize () * SIZEOF_VOID_P
/ 4);
1793 while (guard_size
&& fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ guard_size
) {
1794 guard_size
-= mono_pagesize ();
1796 guard_size
= jit_tls
->stack_ovf_guard_size
- guard_size
;
1797 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
1798 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
);
1799 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1801 mono_arch_handle_altstack_exception (ctx
, fault_addr
, TRUE
);
1806 /* We print a message: after this even managed stack overflows
1807 * may crash the runtime
1809 fprintf (stderr
, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx
), fault_addr
);
1810 if (!jit_tls
->handling_stack_ovf
) {
1811 jit_tls
->restore_stack_prot
= restore_stack_protection_tramp
;
1812 jit_tls
->handling_stack_ovf
= 1;
1814 /*fprintf (stderr, "Already handling stack overflow\n");*/
1823 print_stack_frame (MonoMethod
*method
, gint32 native_offset
, gint32 il_offset
, gboolean managed
, gpointer data
)
1825 FILE *stream
= (FILE*)data
;
1828 gchar
*location
= mono_debug_print_stack_frame (method
, native_offset
, mono_domain_get ());
1829 fprintf (stream
, " %s\n", location
);
1832 fprintf (stream
, " at <unknown> <0x%05x>\n", native_offset
);
1837 static G_GNUC_UNUSED gboolean
1838 print_stack_frame_to_string (MonoMethod
*method
, gint32 native_offset
, gint32 il_offset
, gboolean managed
,
1841 GString
*p
= (GString
*)data
;
1844 gchar
*location
= mono_debug_print_stack_frame (method
, native_offset
, mono_domain_get ());
1845 g_string_append_printf (p
, " %s\n", location
);
1848 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", native_offset
);
1853 static gboolean handling_sigsegv
= FALSE
;
1856 * mono_handle_native_sigsegv:
1858 * Handle a SIGSEGV received while in native code by printing diagnostic
1859 * information and aborting.
1862 mono_handle_native_sigsegv (int signal
, void *ctx
)
1864 #ifdef MONO_ARCH_USE_SIGACTION
1865 struct sigaction sa
;
1867 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1869 if (handling_sigsegv
)
1872 if (mini_get_debug_options ()->suspend_on_sigsegv
) {
1873 fprintf (stderr
, "Received SIGSEGV, suspending...");
1878 /* To prevent infinite loops when the stack walk causes a crash */
1879 handling_sigsegv
= TRUE
;
1881 /* !jit_tls means the thread was not registered with the runtime */
1882 if (jit_tls
&& mono_thread_internal_current ()) {
1883 fprintf (stderr
, "Stacktrace:\n\n");
1885 mono_jit_walk_stack (print_stack_frame
, TRUE
, stderr
);
1890 #ifdef HAVE_BACKTRACE_SYMBOLS
1895 const char *signal_str
= (signal
== SIGSEGV
) ? "SIGSEGV" : "SIGABRT";
1897 fprintf (stderr
, "\nNative stacktrace:\n\n");
1899 size
= backtrace (array
, 256);
1900 names
= backtrace_symbols (array
, size
);
1901 for (i
=0; i
< size
; ++i
) {
1902 fprintf (stderr
, "\t%s\n", names
[i
]);
1908 /* Try to get more meaningful information using gdb */
1910 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
1911 if (!mini_get_debug_options ()->no_gdb_backtrace
&& !mono_debug_using_mono_debugger ()) {
1912 /* From g_spawn_command_line_sync () in eglib */
1914 int stdout_pipe
[2] = { -1, -1 };
1919 res
= pipe (stdout_pipe
);
1920 g_assert (res
!= -1);
1924 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1925 * it will deadlock. Call the syscall directly instead.
1927 pid
= mono_runtime_syscall_fork ();
1930 close (stdout_pipe
[0]);
1931 dup2 (stdout_pipe
[1], STDOUT_FILENO
);
1933 for (i
= getdtablesize () - 1; i
>= 3; i
--)
1936 if (!mono_gdb_render_native_backtraces ())
1937 close (STDOUT_FILENO
);
1942 close (stdout_pipe
[1]);
1944 fprintf (stderr
, "\nDebug info from gdb:\n\n");
1947 int nread
= read (stdout_pipe
[0], buffer
, 1024);
1951 write (STDERR_FILENO
, buffer
, nread
);
1954 waitpid (pid
, &status
, WNOHANG
);
1958 * A SIGSEGV indicates something went very wrong so we can no longer depend
1959 * on anything working. So try to print out lots of diagnostics, starting
1960 * with ones which have a greater chance of working.
1964 "=================================================================\n"
1965 "Got a %s while executing native code. This usually indicates\n"
1966 "a fatal error in the mono runtime or one of the native libraries \n"
1967 "used by your application.\n"
1968 "=================================================================\n"
1974 #ifdef MONO_ARCH_USE_SIGACTION
1976 /* Remove our SIGABRT handler */
1977 sa
.sa_handler
= SIG_DFL
;
1978 sigemptyset (&sa
.sa_mask
);
1981 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
1989 mono_print_thread_dump_internal (void *sigctx
, MonoContext
*start_ctx
)
1991 MonoInternalThread
*thread
= mono_thread_internal_current ();
1992 #if defined(__i386__) || defined(__x86_64__)
1995 GString
* text
= g_string_new (0);
1996 char *name
, *wapi_desc
;
1997 GError
*error
= NULL
;
2000 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &error
);
2002 g_string_append_printf (text
, "\n\"%s\"", name
);
2005 else if (thread
->threadpool_thread
)
2006 g_string_append (text
, "\n\"<threadpool thread>\"");
2008 g_string_append (text
, "\n\"<unnamed thread>\"");
2011 wapi_desc
= wapi_current_thread_desc ();
2012 g_string_append_printf (text
, " tid=0x%p this=0x%p %s\n", (gpointer
)(gsize
)thread
->tid
, thread
, wapi_desc
);
2016 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2018 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
2020 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
2022 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
2024 mono_jit_walk_stack_from_ctx (print_stack_frame_to_string
, &ctx
, TRUE
, text
);
2026 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
2029 fprintf (stdout
, "%s", text
->str
);
2030 g_string_free (text
, TRUE
);
2035 * mono_print_thread_dump:
2037 * Print information about the current thread to stdout.
2038 * SIGCTX can be NULL, allowing this to be called from gdb.
2041 mono_print_thread_dump (void *sigctx
)
2043 mono_print_thread_dump_internal (sigctx
, NULL
);
2047 mono_print_thread_dump_from_ctx (MonoContext
*ctx
)
2049 mono_print_thread_dump_internal (NULL
, ctx
);
2053 * mono_resume_unwind:
2055 * This is called by code at the end of LLVM compiled finally clauses to continue
2059 mono_resume_unwind (void)
2061 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
2062 static void (*restore_context
) (MonoContext
*);
2065 memcpy (&ctx
, &jit_tls
->ex_ctx
, sizeof (MonoContext
));
2067 mono_handle_exception_internal (&ctx
, jit_tls
->ex_obj
, NULL
, FALSE
, TRUE
, NULL
, NULL
);
2069 if (!restore_context
)
2070 restore_context
= mono_get_restore_context ();
2072 restore_context (&ctx
);
2075 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
2080 MonoJitExceptionInfo
*ei
;
2081 } FindHandlerBlockData
;
2084 find_last_handler_block (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
2088 FindHandlerBlockData
*pdata
= data
;
2090 if (ji
->method
->wrapper_type
)
2093 ip
= MONO_CONTEXT_GET_IP (ctx
);
2095 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
2096 MonoJitExceptionInfo
*ei
= ji
->clauses
+ i
;
2097 if (ei
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
2099 /*If ip points to the first instruction it means the handler block didn't start
2100 so we can leave its execution to the EH machinery*/
2101 if (ei
->handler_start
< ip
&& ip
< ei
->data
.handler_end
) {
2113 install_handler_block_guard (MonoJitInfo
*ji
, MonoContext
*ctx
)
2116 MonoJitExceptionInfo
*clause
= NULL
;
2119 ip
= MONO_CONTEXT_GET_IP (ctx
);
2121 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
2122 clause
= &ji
->clauses
[i
];
2123 if (clause
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
2125 if (clause
->handler_start
< ip
&& clause
->data
.handler_end
> ip
)
2129 /*no matching finally */
2130 if (i
== ji
->num_clauses
)
2133 /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
2134 if (ip
== clause
->handler_start
)
2137 return mono_arch_install_handler_block_guard (ji
, clause
, ctx
, mono_create_handler_block_trampoline ());
2141 * Finds the bottom handler block running and install a block guard if needed.
2144 mono_install_handler_block_guard (MonoInternalThread
*thread
, MonoContext
*ctx
)
2146 FindHandlerBlockData data
= { 0 };
2147 MonoDomain
*domain
= mono_domain_get ();
2148 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
2151 if (jit_tls
->handler_block_return_address
)
2154 mono_walk_stack_full (domain
, jit_tls
, ctx
, find_last_handler_block
, FALSE
, &data
);
2159 memcpy (&jit_tls
->ex_ctx
, &data
.ctx
, sizeof (MonoContext
));
2161 resume_ip
= install_handler_block_guard (data
.ji
, &data
.ctx
);
2162 if (resume_ip
== NULL
)
2165 jit_tls
->handler_block_return_address
= resume_ip
;
2166 jit_tls
->handler_block
= data
.ei
;
2169 /*Clear current thread from been wapi interrupted otherwise things can go south*/
2170 wapi_clear_interruption ();
2177 mono_install_handler_block_guard (MonoInternalThread
*thread
, MonoContext
*ctx
)