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 Novell, Inc.
10 * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
18 #ifdef HAVE_EXECINFO_H
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
26 #ifdef HAVE_SYS_WAIT_H
34 #ifdef HAVE_SYS_SYSCALL_H
35 #include <sys/syscall.h>
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>
51 #include "debug-mini.h"
53 #include "debugger-agent.h"
55 #ifndef MONO_ARCH_CONTEXT_DEF
56 #define MONO_ARCH_CONTEXT_DEF
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
);
73 mono_exceptions_init (void)
75 MonoRuntimeExceptionHandlingCallbacks cbs
;
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");
84 restore_context_func
= mono_arch_get_restore_context (&info
, FALSE
);
86 mono_save_trampoline_xdebug_info (info
);
87 mono_tramp_info_free (info
);
89 call_filter_func
= mono_arch_get_call_filter (&info
, FALSE
);
91 mono_save_trampoline_xdebug_info (info
);
92 mono_tramp_info_free (info
);
94 throw_exception_func
= mono_arch_get_throw_exception (&info
, FALSE
);
96 mono_save_trampoline_xdebug_info (info
);
97 mono_tramp_info_free (info
);
99 rethrow_exception_func
= mono_arch_get_rethrow_exception (&info
, FALSE
);
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
);
110 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
111 mono_arch_exceptions_init ();
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
);
122 mono_get_throw_exception (void)
124 g_assert (throw_exception_func
);
125 return throw_exception_func
;
129 mono_get_rethrow_exception (void)
131 g_assert (rethrow_exception_func
);
132 return rethrow_exception_func
;
136 mono_get_call_filter (void)
138 g_assert (call_filter_func
);
139 return call_filter_func
;
143 mono_get_restore_context (void)
145 g_assert (restore_context_func
);
146 return restore_context_func
;
150 mono_get_throw_corlib_exception (void)
152 gpointer code
= NULL
;
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
;
160 code
= mono_aot_get_trampoline ("throw_corlib_exception");
162 code
= mono_arch_get_throw_corlib_exception (&info
, FALSE
);
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
;
177 is_address_protected (MonoJitInfo
*ji
, MonoJitExceptionInfo
*ei
, gpointer ip
)
179 MonoTryBlockHoleTableJitInfo
*table
;
184 if (ei
->try_start
> ip
|| ip
>= ei
->try_end
)
187 if (!ji
->has_try_block_holes
)
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
)
206 * Translate between the mono_arch_find_jit_info function and the old API.
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
;
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
)))
221 ji
= mini_jit_info_table_find (domain
, ip
, NULL
);
226 err
= mono_arch_find_jit_info (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, NULL
, &frame
);
230 /* Convert between the new and the old APIs */
231 switch (frame
.type
) {
232 case FRAME_TYPE_MANAGED
:
236 case FRAME_TYPE_MANAGED_TO_NATIVE
:
240 memset (res
, 0, sizeof (MonoJitInfo
));
241 res
->method
= frame
.method
;
244 case FRAME_TYPE_DEBUGGER_INVOKE
: {
248 * The normal exception handling code can't handle this frame, so just
251 ji
= find_jit_info (domain
, jit_tls
, res
, NULL
, new_ctx
, &tmp_ctx
, lmf
, managed
);
252 memcpy (new_ctx
, &tmp_ctx
, sizeof (MonoContext
));
256 g_assert_not_reached ();
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.
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
,
276 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
288 ji
= find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
290 if (ji
== (gpointer
)-1)
293 if (managed2
|| (ji
&& ji
->method
->wrapper_type
)) {
294 const char *real_ip
, *start
;
297 start
= (const char *)ji
->code_start
;
299 /* ctx->ip points into native code */
300 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
302 real_ip
= (const char*)ip
;
304 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
305 offset
= real_ip
- start
;
310 *native_offset
= offset
;
313 if (!ji
->method
->wrapper_type
|| ji
->method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
317 *trace
= mono_debug_print_stack_frame (ji
->method
, offset
, domain
);
320 char *fname
= mono_method_full_name (res
->method
, TRUE
);
321 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
330 * mono_find_jit_info_ext:
332 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
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.
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
)
351 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
353 MonoDomain
*target_domain
;
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
)))
362 ji
= mini_jit_info_table_find (domain
, ip
, &target_domain
);
365 target_domain
= domain
;
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
);
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.
385 frame
->method
= NULL
;
388 frame
->native_offset
= -1;
389 frame
->domain
= target_domain
;
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
;
401 /* ctx->ip points into native code */
402 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
404 real_ip
= (const char*)ip
;
406 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
407 frame
->native_offset
= real_ip
- start
;
409 frame
->native_offset
= -1;
412 *trace
= mono_debug_print_stack_frame (ji
->method
, frame
->native_offset
, domain
);
414 if (trace
&& frame
->method
) {
415 char *fname
= mono_method_full_name (frame
->method
, TRUE
);
416 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
425 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
427 MonoGenericJitInfo
*gi
;
430 if (!ji
->has_generic_jit_info
)
432 gi
= mono_jit_info_get_generic_jit_info (ji
);
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
443 int offset
= (mgreg_t
)MONO_CONTEXT_GET_IP (ctx
) - (mgreg_t
)ji
->code_start
;
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)) {
451 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, entry
->reg
);
453 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, entry
->reg
) + entry
->offset
);
457 g_assert (i
< gi
->nlocs
);
460 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
462 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
466 if (mono_method_get_context (ji
->method
)->method_inst
) {
468 } else if ((ji
->method
->flags
& METHOD_ATTRIBUTE_STATIC
) || ji
->method
->klass
->valuetype
) {
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
;
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
;
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
;
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
));
519 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class
));
525 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
527 MonoGenericContext context
;
530 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
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
);
541 ves_icall_System_Exception_get_trace (MonoException
*ex
)
543 MonoDomain
*domain
= mono_domain_get ();
545 MonoArray
*ta
= ex
->trace_ips
;
550 /* Exception is not thrown yet */
553 len
= mono_array_length (ta
) >> 1;
554 trace_str
= g_string_new ("");
555 for (i
= 0; i
< len
; i
++) {
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
);
562 /* Unmanaged frame */
563 g_string_append_printf (trace_str
, "in (unmanaged) %p\n", ip
);
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
);
578 res
= mono_string_new (ex
->object
.vtable
->domain
, trace_str
->str
);
579 g_string_free (trace_str
, TRUE
);
585 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
587 MonoDomain
*domain
= mono_domain_get ();
589 MonoArray
*ta
= exc
->trace_ips
;
590 MonoDebugSourceLocation
*location
;
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
++) {
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);
609 ji
= mono_jit_info_table_find (domain
, ip
);
611 /* Unmanaged frame */
612 mono_array_setref (res
, i
, sf
);
616 g_assert (ji
!= NULL
);
618 method
= get_method_from_stack_frame (ji
, generic_info
);
619 if (ji
->method
->wrapper_type
) {
623 s
= mono_method_full_name (method
, TRUE
);
624 MONO_OBJECT_SETREF (sf
, internal_method_name
, mono_string_new (domain
, s
));
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
);
638 sf
->il_offset
= location
->il_offset
;
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
;
648 sf
->line
= sf
->column
= 0;
653 mono_debug_free_source_location (location
);
654 mono_array_setref (res
, i
, sf
);
661 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
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.
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
)
688 mono_arch_flush_register_windows ();
690 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
691 MONO_INIT_CONTEXT_FROM_CURRENT (&extra_ctx
);
693 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx
, mono_walk_stack_with_ctx
);
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.
713 mono_walk_stack_with_state (MonoJitStackWalk func
, MonoThreadUnwindState
*state
, MonoUnwindOptions unwind_options
, void *user_data
)
715 MonoThreadUnwindState extra_state
;
717 if (!mono_thread_state_init_from_current (&extra_state
))
719 state
= &extra_state
;
722 g_assert (state
->valid
);
724 mono_walk_stack_full (func
,
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
);
733 mono_walk_stack (MonoJitStackWalk func
, MonoUnwindOptions options
, void *user_data
)
735 MonoThreadUnwindState state
;
736 if (!mono_thread_state_init_from_current (&state
))
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.
757 mono_walk_stack_full (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoLMF
*lmf
, MonoUnwindOptions unwind_options
, gpointer user_data
)
760 MonoContext ctx
, new_ctx
;
761 StackFrameInfo frame
;
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
);
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
) {
778 res
= mono_find_jit_info_ext (domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, get_reg_locations
? new_reg_locations
: NULL
, &frame
);
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
);
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
));
796 frame
.actual_method
= frame
.method
;
799 if (get_reg_locations
)
800 frame
.reg_locations
= reg_locations
;
802 if (func (&frame
, &ctx
, user_data
))
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
];
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
;
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
);
838 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
844 res
= mono_find_jit_info_ext (domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
848 if (frame
.type
== FRAME_TYPE_MANAGED_TO_NATIVE
|| frame
.type
== FRAME_TYPE_DEBUGGER_INVOKE
)
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
)
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
);
872 *iloffset
= location
->il_offset
;
876 if (need_file_info
) {
878 mono_gc_wbarrier_generic_store (file
, (MonoObject
*) mono_string_new (domain
, location
->source_file
));
879 *line
= location
->row
;
880 *column
= location
->column
;
887 mono_debug_free_source_location (location
);
894 MonoSecurityFrame
*frame
;
895 } MonoFrameSecurityInfo
;
898 callback_get_first_frame_security_info (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
900 MonoFrameSecurityInfo
*si
= (MonoFrameSecurityInfo
*) data
;
901 MonoJitInfo
*ji
= frame
->ji
;
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
) {
920 si
->frame
= mono_declsec_create_frame (frame
->domain
, ji
);
922 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
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
936 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip
)
938 MonoFrameSecurityInfo si
;
943 mono_walk_stack (callback_get_first_frame_security_info
, MONO_UNWIND_DEFAULT
, &si
);
945 return (si
.skips
== 0) ? si
.frame
: NULL
;
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
);
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
;
972 callback_get_stack_frames_security_info (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
974 MonoSecurityStack
*ss
= (MonoSecurityStack
*) data
;
975 MonoJitInfo
*ji
= frame
->ji
;
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
) {
994 if (ss
->count
== ss
->maximum
)
997 mono_array_setref (ss
->stack
, ss
->count
++, mono_declsec_create_frame (frame
->domain
, ji
));
999 /* continue down the stack */
1004 glist_to_array (GList
*list
, MonoClass
*eclass
)
1006 MonoDomain
*domain
= mono_domain_get ();
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
);
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
1032 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip
)
1034 MonoSecurityStack ss
;
1036 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
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); */
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
)
1060 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
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
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
);
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.
1085 mini_jit_info_table_find (MonoDomain
*domain
, char *addr
, MonoDomain
**out_domain
)
1088 MonoInternalThread
*t
= mono_thread_internal_current ();
1094 ji
= mono_jit_info_table_find (domain
, addr
);
1097 *out_domain
= domain
;
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
);
1106 *out_domain
= mono_get_root_domain ();
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
);
1117 *out_domain
= (MonoDomain
*) *refs
;
1127 * wrap_non_exception_throws:
1129 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
1130 * WrapNonExceptionThrows flag set.
1133 wrap_non_exception_throws (MonoMethod
*m
)
1135 MonoAssembly
*ass
= m
->klass
->image
->assembly
;
1136 MonoCustomAttrInfo
* attrs
;
1137 static MonoClass
*klass
;
1139 gboolean val
= FALSE
;
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
);
1149 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
1150 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
1152 int len
, num_named
, named_type
, data_type
, name_len
;
1155 if (!attr
->ctor
|| attr
->ctor
->klass
!= klass
)
1157 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
1158 len
= attr
->data_size
;
1159 p
= (const char*)attr
->data
;
1160 g_assert (read16 (p
) == 0x0001);
1162 num_named
= read16 (p
);
1171 if (named_type
!= 0x54)
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;
1178 g_assert (!strcmp (name
, "WrapNonExceptionThrows"));
1180 /* The value is a BOOLEAN */
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
;
1193 #ifndef MONO_ARCH_STACK_GROWS_UP
1194 #define DOES_STACK_GROWS_UP 1
1196 #define DOES_STACK_GROWS_UP 0
1199 #define MAX_UNMANAGED_BACKTRACE 128
1201 build_native_trace (void)
1203 /* This puppy only makes sense on mobile, IOW, ARM. */
1204 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
1206 void *native_trace
[MAX_UNMANAGED_BACKTRACE
];
1207 int size
= backtrace (native_trace
, MAX_UNMANAGED_BACKTRACE
);
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
]);
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); \
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.
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 ();
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
;
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
;
1276 call_filter
= mono_get_call_filter ();
1278 g_assert (jit_tls
->end_of_stack
);
1279 g_assert (jit_tls
->abort_func
);
1282 *out_filter_idx
= -1;
1289 MonoContext new_ctx
;
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
);
1298 if (frame
.type
== FRAME_TYPE_DEBUGGER_INVOKE
|| frame
.type
== FRAME_TYPE_MANAGED_TO_NATIVE
) {
1302 g_assert (frame
.type
== FRAME_TYPE_MANAGED
);
1307 setup_managed_stacktrace_information ();
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
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
));
1340 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (ctx
));
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))
1356 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (ctx
))) {
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
;
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.
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
);
1387 g_assert_not_reached ();
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
;
1405 setup_managed_stacktrace_information ();
1406 /* mono_debugger_agent_handle_exception () needs this */
1407 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
1412 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst (ex_obj
, catch_class
)) {
1413 setup_managed_stacktrace_information ();
1418 /* mono_debugger_agent_handle_exception () needs this */
1419 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
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.
1438 mono_handle_exception_internal (MonoContext
*ctx
, gpointer obj
, gboolean resume
, MonoJitInfo
**out_ji
)
1440 MonoDomain
*domain
= mono_domain_get ();
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
;
1453 MonoObject
*non_exception
= NULL
;
1455 g_assert (ctx
!= NULL
);
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
;
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
);
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
);
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
));
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
));
1535 MonoObject
*exc
= NULL
;
1536 if (get_message
== NULL
) {
1538 } else if (!strcmp (type_name
, "OutOfMemoryException") || !strcmp (type_name
, "StackOverflowException")) {
1540 msg
= g_strdup_printf ("(No exception message for: %s)\n", type_name
);
1542 message
= mono_runtime_invoke (get_message
, obj
, NULL
, &exc
);
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
);
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
);
1560 if (mini_get_debug_options ()->break_on_exc
)
1562 mono_debugger_agent_handle_exception (obj
, ctx
, NULL
);
1564 if (mini_get_debug_options ()->suspend_on_unhandled
) {
1565 fprintf (stderr
, "Unhandled exception, suspending...");
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
);
1575 // Treat exceptions that are "handled" by mono_runtime_invoke() as unhandled.
1578 if (ji
&& ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
)
1579 mono_debugger_agent_handle_exception (obj
, ctx
, NULL
);
1581 mono_debugger_agent_handle_exception (obj
, ctx
, &ctx_cp
);
1591 MonoContext new_ctx
;
1593 int clause_index_start
= 0;
1594 gboolean unwind_res
= TRUE
;
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
;
1605 StackFrameInfo frame
;
1607 unwind_res
= mono_find_jit_info_ext (domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
1609 if (frame
.type
== FRAME_TYPE_DEBUGGER_INVOKE
|| frame
.type
== FRAME_TYPE_MANAGED_TO_NATIVE
) {
1613 g_assert (frame
.type
== FRAME_TYPE_MANAGED
);
1619 *(mono_get_lmf_addr ()) = lmf
;
1621 jit_tls
->abort_func (obj
);
1622 g_assert_not_reached ();
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
));
1632 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (ctx
));
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))
1648 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (ctx
))) {
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
;
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
);
1666 g_assert_not_reached ();
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
);
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
) {
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
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
)) {
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
;
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
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
);
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
;
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.
1801 mono_debugger_handle_exception (MonoContext
*ctx
, MonoObject
*obj
)
1803 MonoDebuggerExceptionAction action
;
1805 if (!mono_debug_using_mono_debugger ())
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.
1822 } else if (action
== MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED
) {
1823 MonoContext ctx_cp
= *ctx
;
1824 MonoJitInfo
*ji
= NULL
;
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.
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.
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.
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
;
1880 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
1881 if (!ji
|| ji
== (gpointer
)-1)
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
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"
1916 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1919 mono_setup_altstack (MonoJitTlsData
*tls
)
1923 guint8
*staddr
= NULL
;
1925 if (mono_running_on_valgrind ())
1928 mono_thread_get_stack_bounds (&staddr
, &stsize
);
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
;
1960 sa
.ss_flags
= SS_ONSTACK
;
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
);
1968 mono_free_altstack (MonoJitTlsData
*tls
)
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
);
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 */
1990 mono_setup_altstack (MonoJitTlsData
*tls
)
1995 mono_free_altstack (MonoJitTlsData
*tls
)
1999 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
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);
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
2034 if (try_restore_stack_protection (jit_tls
, 4096))
2035 jit_tls
->restore_stack_prot
= NULL
;
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
);
2045 mono_altstack_restore_prot (mgreg_t
*regs
, guint8
*code
, gpointer
*tramp_data
, guint8
* tramp
)
2047 void (*func
)(void) = (gpointer
)tramp_data
;
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 */
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
2081 mono_arch_handle_altstack_exception (ctx
, fault_addr
, TRUE
);
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;
2094 /*fprintf (stderr, "Already handling stack overflow\n");*/
2104 MonoMethod
*omethod
;
2106 } PrintOverflowUserData
;
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
;
2117 method
= frame
->ji
->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
++;
2126 /* If this is a one method overflow, skip the other instances */
2127 if (method
== user_data
->omethod
)
2130 location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, mono_domain_get ());
2131 fprintf (stream
, " %s\n", location
);
2134 if (user_data
->count
== 1) {
2135 fprintf (stream
, " <...>\n");
2136 user_data
->omethod
= method
;
2138 user_data
->omethod
= NULL
;
2141 user_data
->count
++;
2143 fprintf (stream
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
2149 mono_handle_hard_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, guint8
* fault_addr
)
2151 PrintOverflowUserData ud
;
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
));
2165 mono_walk_stack_with_ctx (print_overflow_stack_frame
, &mctx
, MONO_UNWIND_LOOKUP_ACTUAL_METHOD
, &ud
);
2167 if (ji
&& ji
->method
)
2168 fprintf (stderr
, "At %s\n", mono_method_full_name (ji
->method
, TRUE
));
2170 fprintf (stderr
, "At <unmanaged>.\n");
2177 print_stack_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
2179 FILE *stream
= (FILE*)data
;
2180 MonoMethod
*method
= NULL
;
2182 method
= frame
->ji
->method
;
2185 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, mono_domain_get ());
2186 fprintf (stream
, " %s\n", location
);
2189 fprintf (stream
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
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
;
2200 method
= frame
->ji
->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
);
2207 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
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.
2221 mono_handle_native_sigsegv (int signal
, void *ctx
)
2223 #ifdef MONO_ARCH_USE_SIGACTION
2224 struct sigaction sa
;
2226 MonoJitTlsData
*jit_tls
= mono_native_tls_get_value (mono_jit_tls_id
);
2228 if (handling_sigsegv
)
2231 if (mini_get_debug_options ()->suspend_on_sigsegv
) {
2232 fprintf (stderr
, "Received SIGSEGV, suspending...");
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
);
2249 #ifdef HAVE_BACKTRACE_SYMBOLS
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
]);
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 */
2274 pid_t crashed_pid
= getpid ();
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 ();
2284 dup2 (STDERR_FILENO
, STDOUT_FILENO
);
2286 mono_gdb_render_native_backtraces (crashed_pid
);
2290 fprintf (stderr
, "\nDebug info from gdb:\n\n");
2291 waitpid (pid
, &status
, 0);
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.
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"
2311 #ifdef MONO_ARCH_USE_SIGACTION
2313 /* Remove our SIGABRT handler */
2314 sa
.sa_handler
= SIG_DFL
;
2315 sigemptyset (&sa
.sa_mask
);
2318 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
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
2332 GString
* text
= g_string_new (0);
2333 char *name
, *wapi_desc
;
2334 GError
*error
= NULL
;
2337 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &error
);
2339 g_string_append_printf (text
, "\n\"%s\"", name
);
2342 else if (thread
->threadpool_thread
)
2343 g_string_append (text
, "\n\"<threadpool thread>\"");
2345 g_string_append (text
, "\n\"<unnamed thread>\"");
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
);
2353 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2355 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
2357 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
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
);
2363 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
2366 fprintf (stdout
, "%s", text
->str
);
2368 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
2369 OutputDebugStringA(text
->str
);
2372 g_string_free (text
, TRUE
);
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.
2383 mono_print_thread_dump (void *sigctx
)
2385 mono_print_thread_dump_internal (sigctx
, NULL
);
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
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
));
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
2424 MonoJitExceptionInfo
*ei
;
2425 } FindHandlerBlockData
;
2428 find_last_handler_block (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
2432 FindHandlerBlockData
*pdata
= data
;
2433 MonoJitInfo
*ji
= frame
->ji
;
2438 if (ji
->method
->wrapper_type
)
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
)
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
) {
2461 install_handler_block_guard (MonoJitInfo
*ji
, MonoContext
*ctx
)
2464 MonoJitExceptionInfo
*clause
= NULL
;
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
)
2473 if (clause
->handler_start
< ip
&& clause
->data
.handler_end
> ip
)
2477 /*no matching finally */
2478 if (i
== ji
->num_clauses
)
2481 /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
2482 if (ip
== clause
->handler_start
)
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.
2493 mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
)
2495 FindHandlerBlockData data
= { 0 };
2496 MonoJitTlsData
*jit_tls
= ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
];
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
)
2509 mono_walk_stack_with_state (find_last_handler_block
, ctx
, MONO_UNWIND_SIGNAL_SAFE
, &data
);
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
)
2520 jit_tls
->handler_block_return_address
= resume_ip
;
2521 jit_tls
->handler_block
= data
.ei
;
2528 mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
)
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*/
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
) {
2560 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
->ctx
);
2562 #if MONO_ARCH_HAS_MONO_CONTEXT && !defined(MONO_CROSS_COMPILE)
2563 MONO_CONTEXT_GET_CURRENT (ctx
->ctx
);
2565 g_error ("Use a null sigctx requires a working mono-context");
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
;
2574 g_error ("Implement mono_arch_sigctx_to_monoctx for the current target");
2580 mono_thread_state_init_from_monoctx (MonoThreadUnwindState
*ctx
, MonoContext
*mctx
)
2582 MonoInternalThread
*thread
= mono_thread_internal_current ();
2583 if (!thread
|| !thread
->jit_data
) {
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
;
2596 /*returns false if the thread is not attached*/
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
) {
2609 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
2610 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
->ctx
);
2612 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
->ctx
, mono_thread_state_init_from_current
);
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
;
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 */
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
);
2642 g_error ("This target doesn't support mono_arch_setup_async_callback");