3 * generic exception support
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Mono Team (mono-list@lists.ximian.com)
9 * Copyright 2001-2003 Ximian, Inc.
10 * Copyright 2003-2008 Novell, Inc.
11 * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_EXECINFO_H
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
31 #ifdef HAVE_SYS_WAIT_H
39 #ifdef HAVE_SYS_SYSCALL_H
40 #include <sys/syscall.h>
43 #ifdef HAVE_SYS_PRCTL_H
44 #include <sys/prctl.h>
51 #include <mono/metadata/appdomain.h>
52 #include <mono/metadata/tabledefs.h>
53 #include <mono/metadata/threads.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/exception.h>
57 #include <mono/metadata/exception-internals.h>
58 #include <mono/metadata/object-internals.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/metadata/debug-internals.h>
62 #include <mono/metadata/mono-debug.h>
63 #include <mono/metadata/profiler-private.h>
64 #include <mono/metadata/mono-endian.h>
65 #include <mono/metadata/environment.h>
66 #include <mono/metadata/mono-mlist.h>
67 #include <mono/utils/mono-merp.h>
68 #include <mono/utils/mono-mmap.h>
69 #include <mono/utils/mono-logger-internals.h>
70 #include <mono/utils/mono-error.h>
71 #include <mono/utils/mono-error-internals.h>
75 #include "debugger-agent.h"
76 #include "seq-points.h"
77 #include "llvm-runtime.h"
78 #include "mini-llvm.h"
79 #include "aot-runtime.h"
80 #include "mini-runtime.h"
81 #include "interp/interp.h"
84 #include "mini-llvm-cpp.h"
91 #ifndef MONO_ARCH_CONTEXT_DEF
92 #define MONO_ARCH_CONTEXT_DEF
96 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
97 * This structure represents one entry.
98 * This should consists of pointers only.
103 gpointer generic_info
;
104 /* Only for interpreter frames */
108 /* Number of words in trace_ips belonging to one entry */
109 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
111 static gpointer restore_context_func
, call_filter_func
;
112 static gpointer throw_exception_func
, rethrow_exception_func
;
113 static gpointer throw_corlib_exception_func
;
115 static void mono_walk_stack_full (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoLMF
*lmf
, MonoUnwindOptions unwind_options
, gpointer user_data
);
116 static void mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
);
117 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
);
118 static gboolean
mono_current_thread_has_handle_block_guard (void);
119 static gboolean
mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
);
120 static void mono_uninstall_current_handler_block_guard (void);
123 first_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer addr
)
125 gpointer
**data
= (gpointer
**)addr
;
131 // FIXME: Happens with llvm_only
136 *data
= frame
->frame_addr
;
142 mono_thread_get_managed_sp (void)
144 gpointer addr
= NULL
;
145 mono_walk_stack (first_managed
, MONO_UNWIND_SIGNAL_SAFE
, &addr
);
150 mini_clear_abort_threshold (void)
152 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
153 jit_tls
->abort_exc_stack_threshold
= NULL
;
157 mini_set_abort_threshold (StackFrameInfo
*frame
)
159 gpointer sp
= frame
->frame_addr
;
160 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
161 // Only move it up, to avoid thrown/caught
162 // exceptions lower in the stack from triggering
164 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
165 if (!jit_tls
->abort_exc_stack_threshold
|| above_threshold
) {
166 jit_tls
->abort_exc_stack_threshold
= sp
;
170 // Note: In the case that the frame is above where the thread abort
171 // was set we bump the threshold so that functions called from the new,
172 // higher threshold don't trigger the thread abort exception
173 static inline gboolean
174 mini_above_abort_threshold (void)
176 gpointer sp
= mono_thread_get_managed_sp ();
177 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*) mono_tls_get_jit_tls ();
182 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
185 jit_tls
->abort_exc_stack_threshold
= sp
;
187 return above_threshold
;
191 mono_get_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
194 if (mono_find_prev_seq_point_for_native_offset (domain
, method
, native_offset
, NULL
, &sp
))
200 mono_exceptions_init (void)
202 MonoRuntimeExceptionHandlingCallbacks cbs
;
204 restore_context_func
= mono_aot_get_trampoline ("restore_context");
205 call_filter_func
= mono_aot_get_trampoline ("call_filter");
206 throw_exception_func
= mono_aot_get_trampoline ("throw_exception");
207 rethrow_exception_func
= mono_aot_get_trampoline ("rethrow_exception");
211 restore_context_func
= mono_arch_get_restore_context (&info
, FALSE
);
212 mono_tramp_info_register (info
, NULL
);
213 call_filter_func
= mono_arch_get_call_filter (&info
, FALSE
);
214 mono_tramp_info_register (info
, NULL
);
215 throw_exception_func
= mono_arch_get_throw_exception (&info
, FALSE
);
216 mono_tramp_info_register (info
, NULL
);
217 rethrow_exception_func
= mono_arch_get_rethrow_exception (&info
, FALSE
);
218 mono_tramp_info_register (info
, NULL
);
221 mono_arch_exceptions_init ();
223 cbs
.mono_walk_stack_with_ctx
= mono_runtime_walk_stack_with_ctx
;
224 cbs
.mono_walk_stack_with_state
= mono_walk_stack_with_state
;
226 if (mono_llvm_only
) {
227 cbs
.mono_raise_exception
= mono_llvm_raise_exception
;
228 cbs
.mono_reraise_exception
= mono_llvm_reraise_exception
;
230 cbs
.mono_raise_exception
= (void (*)(MonoException
*))mono_get_throw_exception ();
231 cbs
.mono_reraise_exception
= (void (*)(MonoException
*))mono_get_rethrow_exception ();
233 cbs
.mono_raise_exception_with_ctx
= mono_raise_exception_with_ctx
;
234 cbs
.mono_exception_walk_trace
= mono_exception_walk_trace
;
235 cbs
.mono_install_handler_block_guard
= mono_install_handler_block_guard
;
236 cbs
.mono_uninstall_current_handler_block_guard
= mono_uninstall_current_handler_block_guard
;
237 cbs
.mono_current_thread_has_handle_block_guard
= mono_current_thread_has_handle_block_guard
;
238 cbs
.mono_clear_abort_threshold
= mini_clear_abort_threshold
;
239 cbs
.mono_above_abort_threshold
= mini_above_abort_threshold
;
240 mono_install_eh_callbacks (&cbs
);
241 mono_install_get_seq_point (mono_get_seq_point_for_native_offset
);
245 mono_get_throw_exception (void)
247 g_assert (throw_exception_func
);
248 return throw_exception_func
;
252 mono_get_rethrow_exception (void)
254 g_assert (rethrow_exception_func
);
255 return rethrow_exception_func
;
259 mono_get_call_filter (void)
261 g_assert (call_filter_func
);
262 return call_filter_func
;
266 mono_get_restore_context (void)
268 g_assert (restore_context_func
);
269 return restore_context_func
;
273 mono_get_throw_corlib_exception (void)
275 gpointer code
= NULL
;
278 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
279 if (throw_corlib_exception_func
)
280 return throw_corlib_exception_func
;
283 code
= mono_aot_get_trampoline ("throw_corlib_exception");
285 code
= mono_arch_get_throw_corlib_exception (&info
, FALSE
);
286 mono_tramp_info_register (info
, NULL
);
289 mono_memory_barrier ();
291 throw_corlib_exception_func
= code
;
293 return throw_corlib_exception_func
;
297 * mono_get_throw_exception_addr:
299 * Return an address which stores the result of
300 * mono_get_throw_exception.
303 mono_get_throw_exception_addr (void)
305 return &throw_exception_func
;
309 is_address_protected (MonoJitInfo
*ji
, MonoJitExceptionInfo
*ei
, gpointer ip
)
311 MonoTryBlockHoleTableJitInfo
*table
;
316 if (ei
->try_start
> ip
|| ip
>= ei
->try_end
)
319 if (!ji
->has_try_block_holes
)
322 table
= mono_jit_info_get_try_block_hole_table_info (ji
);
323 offset
= (guint32
)((char*)ip
- (char*)ji
->code_start
);
324 clause
= (guint16
)(ei
- ji
->clauses
);
325 g_assert (clause
< ji
->num_clauses
);
327 for (i
= 0; i
< table
->num_holes
; ++i
) {
328 MonoTryBlockHoleJitInfo
*hole
= &table
->holes
[i
];
329 if (hole
->clause
== clause
&& hole
->offset
<= offset
&& hole
->offset
+ hole
->length
> offset
)
335 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
338 static gboolean show_native_addresses
= TRUE
;
340 static gboolean show_native_addresses
= FALSE
;
343 static _Unwind_Reason_Code
344 build_stack_trace (struct _Unwind_Context
*frame_ctx
, void *state
)
346 MonoDomain
*domain
= mono_domain_get ();
347 uintptr_t ip
= _Unwind_GetIP (frame_ctx
);
349 if (show_native_addresses
|| mono_jit_info_table_find (domain
, (char*)ip
)) {
350 GList
**trace_ips
= (GList
**)state
;
351 *trace_ips
= g_list_prepend (*trace_ips
, (gpointer
)ip
);
354 return _URC_NO_REASON
;
358 get_unwind_backtrace (void)
362 _Unwind_Backtrace (build_stack_trace
, &ips
);
364 return g_slist_reverse (ips
);
370 get_unwind_backtrace (void)
378 arch_unwind_frame (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
379 MonoJitInfo
*ji
, MonoContext
*ctx
,
380 MonoContext
*new_ctx
, MonoLMF
**lmf
,
381 mgreg_t
**save_locations
,
382 StackFrameInfo
*frame
)
385 if (((guint64
)(*lmf
)->previous_lmf
) & 2) {
386 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
388 memset (frame
, 0, sizeof (StackFrameInfo
));
393 if (ext
->debugger_invoke
) {
395 * This LMF entry is created by the soft debug code to mark transitions to
396 * managed code done during invokes.
398 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
399 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
400 } else if (ext
->interp_exit
) {
401 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED
;
402 frame
->interp_exit_data
= ext
->interp_exit_data
;
404 g_assert_not_reached ();
407 *lmf
= (MonoLMF
*)(((guint64
)(*lmf
)->previous_lmf
) & ~3);
413 return mono_arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
419 * Translate between the mono_arch_unwind_frame function and the old API.
422 find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
423 MonoContext
*new_ctx
, MonoLMF
**lmf
, gboolean
*managed
)
425 StackFrameInfo frame
;
428 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
430 /* Avoid costly table lookup during stack overflow */
431 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
434 ji
= mini_jit_info_table_find (domain
, ip
, NULL
);
439 err
= arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, NULL
, &frame
);
441 return (MonoJitInfo
*)-1;
443 if (*lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
445 * Remove any unused lmf.
446 * Mask out the lower bits which might be used to hold additional information.
448 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(SIZEOF_VOID_P
-1));
451 /* Convert between the new and the old APIs */
452 switch (frame
.type
) {
453 case FRAME_TYPE_MANAGED
:
457 case FRAME_TYPE_TRAMPOLINE
:
459 case FRAME_TYPE_MANAGED_TO_NATIVE
:
463 memset (res
, 0, sizeof (MonoJitInfo
));
464 res
->d
.method
= frame
.method
;
467 case FRAME_TYPE_DEBUGGER_INVOKE
: {
471 * The normal exception handling code can't handle this frame, so just
474 ji
= find_jit_info (domain
, jit_tls
, res
, NULL
, new_ctx
, &tmp_ctx
, lmf
, managed
);
475 memcpy (new_ctx
, &tmp_ctx
, sizeof (MonoContext
));
479 g_assert_not_reached ();
484 /* mono_find_jit_info:
486 * This function is used to gather information from @ctx. It return the
487 * MonoJitInfo of the corresponding function, unwinds one stack frame and
488 * stores the resulting context into @new_ctx. It also stores a string
489 * describing the stack location into @trace (if not NULL), and modifies
490 * the @lmf if necessary. @native_offset return the IP offset from the
491 * start of the function or -1 if that info is not available.
494 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
495 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
499 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
501 MonoMethod
*method
= NULL
;
512 ji
= find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
514 if (ji
== (gpointer
)-1)
517 if (ji
&& !ji
->is_trampoline
)
518 method
= jinfo_get_method (ji
);
520 if (managed2
|| (method
&& method
->wrapper_type
)) {
521 const char *real_ip
, *start
;
524 start
= (const char *)ji
->code_start
;
526 /* ctx->ip points into native code */
527 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
529 real_ip
= (const char*)ip
;
531 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
532 offset
= real_ip
- start
;
537 *native_offset
= offset
;
540 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
544 *trace
= mono_debug_print_stack_frame (method
, offset
, domain
);
547 char *fname
= mono_method_full_name (jinfo_get_method (res
), TRUE
);
548 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
557 * mono_find_jit_info_ext:
559 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
561 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
562 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
563 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
564 * to obtain the last managed frame.
565 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
566 * On return, it will be filled with the locations where callee saved registers are saved
567 * by the current frame. This is returned outside of StackFrameInfo because it can be
568 * quite large on some platforms.
569 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
573 mono_find_jit_info_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
574 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
575 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
576 mgreg_t
**save_locations
,
577 StackFrameInfo
*frame
)
580 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
582 MonoDomain
*target_domain
= domain
;
583 MonoMethod
*method
= NULL
;
584 gboolean async
= mono_thread_info_is_async_context ();
589 /* Avoid costly table lookup during stack overflow */
590 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
593 ji
= mini_jit_info_table_find (domain
, ip
, &target_domain
);
596 target_domain
= domain
;
599 memset (save_locations
, 0, MONO_MAX_IREGS
* sizeof (mgreg_t
*));
601 err
= arch_unwind_frame (target_domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
605 if (frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED
&& *lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
607 * Remove any unused lmf.
608 * Mask out the lower bits which might be used to hold additional information.
610 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(SIZEOF_VOID_P
-1));
613 if (frame
->ji
&& !frame
->ji
->is_trampoline
&& !frame
->ji
->async
)
614 method
= jinfo_get_method (frame
->ji
);
616 if (frame
->type
== FRAME_TYPE_MANAGED
&& method
) {
617 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
618 frame
->managed
= TRUE
;
621 if (frame
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
) {
623 * This type of frame is just a marker, the caller should unwind once more to get the
624 * last managed frame.
627 frame
->method
= NULL
;
630 frame
->native_offset
= -1;
631 frame
->domain
= target_domain
;
632 frame
->async_context
= async
;
633 frame
->frame_addr
= MONO_CONTEXT_GET_SP (ctx
);
637 if (frame
->type
== FRAME_TYPE_MANAGED
)
638 frame
->method
= method
;
640 if (ji
&& (frame
->managed
|| (method
&& method
->wrapper_type
))) {
641 const char *real_ip
, *start
;
643 start
= (const char *)ji
->code_start
;
644 if (frame
->type
== FRAME_TYPE_MANAGED
)
645 real_ip
= (const char*)ip
;
647 /* ctx->ip points into native code */
648 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
650 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
651 frame
->native_offset
= real_ip
- start
;
653 frame
->native_offset
= -1;
657 *trace
= mono_debug_print_stack_frame (method
, frame
->native_offset
, domain
);
659 if (trace
&& frame
->method
) {
660 char *fname
= mono_method_full_name (frame
->method
, TRUE
);
661 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
671 MonoInterpStackIter interp_iter
;
672 gpointer last_frame_addr
;
676 unwinder_init (Unwinder
*unwinder
)
678 memset (unwinder
, 0, sizeof (Unwinder
));
681 #if defined(__GNUC__) && defined(TARGET_ARM64)
682 /* gcc 4.9.2 seems to miscompile this on arm64 */
683 static __attribute__((optimize("O0"))) gboolean
687 unwinder_unwind_frame (Unwinder
*unwinder
,
688 MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
689 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
690 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
691 mgreg_t
**save_locations
,
692 StackFrameInfo
*frame
)
695 if (unwinder
->in_interp
) {
696 memcpy (new_ctx
, ctx
, sizeof (MonoContext
));
698 /* Process debugger invokes */
699 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
700 if (unwinder
->last_frame_addr
> (gpointer
)(*lmf
)) {
701 if (((guint64
)(*lmf
)->previous_lmf
) & 2) {
702 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
703 if (ext
->debugger_invoke
) {
704 *lmf
= (MonoLMF
*)(((guint64
)(*lmf
)->previous_lmf
) & ~7);
705 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
711 unwinder
->in_interp
= mini_get_interp_callbacks ()->frame_iter_next (&unwinder
->interp_iter
, frame
);
712 if (frame
->type
== FRAME_TYPE_INTERP
) {
713 parent
= mini_get_interp_callbacks ()->frame_get_parent (frame
->interp_frame
);
714 unwinder
->last_frame_addr
= parent
;
716 if (!unwinder
->in_interp
)
717 return unwinder_unwind_frame (unwinder
, domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
, save_locations
, frame
);
720 gboolean res
= mono_find_jit_info_ext (domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
,
721 save_locations
, frame
);
724 if (frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED
) {
725 unwinder
->in_interp
= TRUE
;
726 mini_get_interp_callbacks ()->frame_iter_init (&unwinder
->interp_iter
, frame
->interp_exit_data
);
728 unwinder
->last_frame_addr
= frame
->frame_addr
;
734 * This function is async-safe.
737 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
739 MonoGenericJitInfo
*gi
;
743 if (!ji
->has_generic_jit_info
)
745 gi
= mono_jit_info_get_generic_jit_info (ji
);
751 * Search location list if available, it contains the precise location of the
752 * argument for every pc offset, even if the method was interrupted while it was in
756 int offset
= (mgreg_t
)MONO_CONTEXT_GET_IP (ctx
) - (mgreg_t
)ji
->code_start
;
759 for (i
= 0; i
< gi
->nlocs
; ++i
) {
760 MonoDwarfLocListEntry
*entry
= &gi
->locations
[i
];
762 if (offset
>= entry
->from
&& (offset
< entry
->to
|| entry
->to
== 0)) {
764 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, entry
->reg
);
766 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, entry
->reg
) + entry
->offset
);
770 g_assert (i
< gi
->nlocs
);
773 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
775 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
779 method
= jinfo_get_method (ji
);
780 if (mono_method_get_context (method
)->method_inst
) {
781 /* A MonoMethodRuntimeGenericContext* */
783 } else if ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) || m_class_is_valuetype (method
->klass
)) {
787 /* Avoid returning a managed object */
788 MonoObject
*this_obj
= (MonoObject
*)info
;
790 return this_obj
->vtable
;
795 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
797 static MonoGenericContext
798 get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
800 MonoGenericContext context
= { NULL
, NULL
};
801 MonoClass
*klass
, *method_container_class
;
804 g_assert (generic_info
);
806 method
= jinfo_get_method (ji
);
807 g_assert (method
->is_inflated
);
808 if (mono_method_get_context (method
)->method_inst
) {
809 MonoMethodRuntimeGenericContext
*mrgctx
= (MonoMethodRuntimeGenericContext
*)generic_info
;
811 klass
= mrgctx
->class_vtable
->klass
;
812 context
.method_inst
= mrgctx
->method_inst
;
813 g_assert (context
.method_inst
);
815 MonoVTable
*vtable
= (MonoVTable
*)generic_info
;
817 klass
= vtable
->klass
;
820 //g_assert (!mono_class_is_gtd (method->klass));
821 if (mono_class_is_ginst (method
->klass
))
822 method_container_class
= mono_class_get_generic_class (method
->klass
)->container_class
;
824 method_container_class
= method
->klass
;
826 /* class might refer to a subclass of method's class */
827 while (!(klass
== method
->klass
|| (mono_class_is_ginst (klass
) && mono_class_get_generic_class (klass
)->container_class
== method_container_class
))) {
828 klass
= m_class_get_parent (klass
);
832 if (mono_class_is_ginst (klass
) || mono_class_is_gtd (klass
))
833 context
.class_inst
= mini_class_get_context (klass
)->class_inst
;
835 if (mono_class_is_ginst (klass
))
836 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass
)->container_class
, method_container_class
));
838 g_assert (mono_class_has_parent_and_ignore_generics (klass
, method_container_class
));
844 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
847 MonoGenericContext context
;
850 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
851 return jinfo_get_method (ji
);
852 context
= get_generic_context_from_stack_frame (ji
, generic_info
);
854 method
= jinfo_get_method (ji
);
855 method
= mono_method_get_declaring_generic_method (method
);
856 method
= mono_class_inflate_generic_method_checked (method
, &context
, error
);
857 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
863 * mono_exception_walk_native_trace:
864 * \param ex The exception object whose frames should be walked
865 * \param func callback to call for each stack frame
866 * \param user_data data passed to the callback
867 * This function walks the stacktrace of an exception. For
868 * each frame the callback function is called with the relevant info.
869 * The walk ends when no more stack frames are found or when the callback
870 * returns a TRUE value.
874 mono_exception_walk_trace (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
876 MONO_REQ_GC_UNSAFE_MODE
;
878 MonoDomain
*domain
= mono_domain_get ();
879 MonoArray
*ta
= ex
->trace_ips
;
885 len
= mono_array_length (ta
) / TRACE_IP_ENTRY_SIZE
;
886 for (i
= 0; i
< len
; i
++) {
887 ExceptionTraceIp trace_ip
;
889 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
890 gpointer ip
= trace_ip
.ip
;
891 gpointer generic_info
= trace_ip
.generic_info
;
892 MonoJitInfo
*ji
= mono_jit_info_table_find (domain
, ip
);
895 if (func (NULL
, ip
, 0, FALSE
, user_data
))
898 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
899 if (func (method
, ji
->code_start
, (char *) ip
- (char *) ji
->code_start
, TRUE
, user_data
))
908 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
911 MonoDomain
*domain
= mono_domain_get ();
913 MonoArray
*ta
= exc
->trace_ips
;
914 MonoDebugSourceLocation
*location
;
918 /* Exception is not thrown yet */
919 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, 0, error
);
920 mono_error_set_pending_exception (error
);
924 len
= mono_array_length (ta
) / TRACE_IP_ENTRY_SIZE
;
926 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0, error
);
927 if (mono_error_set_pending_exception (error
))
930 for (i
= skip
; i
< len
; i
++) {
932 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
933 if (!mono_error_ok (error
)) {
934 mono_error_set_pending_exception (error
);
937 ExceptionTraceIp trace_ip
;
938 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
939 gpointer ip
= trace_ip
.ip
;
940 gpointer generic_info
= trace_ip
.generic_info
;
946 ji
= mono_jit_info_table_find (domain
, ip
);
948 /* Unmanaged frame */
949 mono_array_setref (res
, i
, sf
);
954 g_assert (ji
!= NULL
);
956 if (mono_llvm_only
|| !generic_info
)
957 /* Can't resolve actual method */
958 method
= jinfo_get_method (ji
);
960 method
= get_method_from_stack_frame (ji
, generic_info
);
961 if (jinfo_get_method (ji
)->wrapper_type
) {
965 s
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_REFLECTION
);
966 MonoString
*name
= mono_string_new_checked (domain
, s
, error
);
968 if (!is_ok (error
)) {
969 mono_error_set_pending_exception (error
);
972 MONO_OBJECT_SETREF (sf
, internal_method_name
, name
);
975 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
976 if (!mono_error_ok (error
)) {
977 mono_error_set_pending_exception (error
);
980 MONO_OBJECT_SETREF (sf
, method
, rm
);
983 sf
->method_index
= ji
->from_aot
? mono_aot_find_method_index (method
) : 0xffffff;
984 sf
->method_address
= (gsize
) ji
->code_start
;
985 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
988 * mono_debug_lookup_source_location() returns both the file / line number information
989 * and the IL offset. Note that computing the IL offset is already an expensive
990 * operation, so we shouldn't call this method twice.
992 location
= mono_debug_lookup_source_location (jinfo_get_method (ji
), sf
->native_offset
, domain
);
994 sf
->il_offset
= location
->il_offset
;
997 if (mono_find_prev_seq_point_for_native_offset (domain
, jinfo_get_method (ji
), sf
->native_offset
, NULL
, &sp
))
998 sf
->il_offset
= sp
.il_offset
;
1003 if (need_file_info
) {
1004 if (location
&& location
->source_file
) {
1005 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1006 if (!is_ok (error
)) {
1007 mono_error_set_pending_exception (error
);
1010 MONO_OBJECT_SETREF (sf
, filename
, filename
);
1011 sf
->line
= location
->row
;
1012 sf
->column
= location
->column
;
1014 sf
->line
= sf
->column
= 0;
1015 sf
->filename
= NULL
;
1019 mono_debug_free_source_location (location
);
1020 mono_array_setref (res
, i
, sf
);
1027 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1030 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
1031 if (jit_tls
&& jit_tls
->orig_ex_ctx_set
)
1032 start_ctx
= &jit_tls
->orig_ex_ctx
;
1034 mono_walk_stack_with_ctx (func
, start_ctx
, unwind_options
, user_data
);
1037 * mono_walk_stack_with_ctx:
1038 * Unwind the current thread starting at \p start_ctx.
1039 * If \p start_ctx is null, we capture the current context.
1042 mono_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1044 MonoContext extra_ctx
;
1045 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1046 MONO_ARCH_CONTEXT_DEF
1048 if (!thread
|| !thread
->jit_data
)
1052 mono_arch_flush_register_windows ();
1054 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1055 MONO_INIT_CONTEXT_FROM_CURRENT (&extra_ctx
);
1057 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx
, mono_walk_stack_with_ctx
);
1059 start_ctx
= &extra_ctx
;
1062 mono_walk_stack_full (func
, start_ctx
, mono_domain_get (), (MonoJitTlsData
*)thread
->jit_data
, mono_get_lmf (), unwind_options
, user_data
);
1066 * mono_walk_stack_with_state:
1067 * Unwind a thread described by \p state.
1069 * State must be valid (state->valid == TRUE).
1071 * If you are using this function to unwind another thread, make sure it is suspended.
1073 * If \p state is null, we capture the current context.
1076 mono_walk_stack_with_state (MonoJitStackWalk func
, MonoThreadUnwindState
*state
, MonoUnwindOptions unwind_options
, void *user_data
)
1078 MonoThreadUnwindState extra_state
;
1080 g_assert (!mono_thread_info_is_async_context ());
1081 if (!mono_thread_state_init_from_current (&extra_state
))
1083 state
= &extra_state
;
1086 g_assert (state
->valid
);
1088 if (!state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
])
1092 mono_walk_stack_full (func
,
1094 (MonoDomain
*)state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
],
1095 (MonoJitTlsData
*)state
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
],
1096 (MonoLMF
*)state
->unwind_data
[MONO_UNWIND_DATA_LMF
],
1097 unwind_options
, user_data
);
1101 mono_walk_stack (MonoJitStackWalk func
, MonoUnwindOptions options
, void *user_data
)
1103 MonoThreadUnwindState state
;
1104 if (!mono_thread_state_init_from_current (&state
))
1106 mono_walk_stack_with_state (func
, &state
, options
, user_data
);
1110 * mono_walk_stack_full:
1111 * \param func callback to call for each stack frame
1112 * \param domain starting appdomain, can be NULL to use the current domain
1113 * \param unwind_options what extra information the unwinder should gather
1114 * \param start_ctx starting state of the stack walk, can be NULL.
1115 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1116 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1117 * \param user_data data passed to the callback
1118 * This function walks the stack of a thread, starting from the state
1119 * represented by \p start_ctx. For each frame the callback
1120 * function is called with the relevant info. The walk ends when no more
1121 * managed stack frames are found or when the callback returns a TRUE value.
1124 mono_walk_stack_full (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoLMF
*lmf
, MonoUnwindOptions unwind_options
, gpointer user_data
)
1127 MonoContext ctx
, new_ctx
;
1128 StackFrameInfo frame
;
1130 mgreg_t
*reg_locations
[MONO_MAX_IREGS
];
1131 mgreg_t
*new_reg_locations
[MONO_MAX_IREGS
];
1132 gboolean get_reg_locations
= unwind_options
& MONO_UNWIND_REG_LOCATIONS
;
1133 gboolean async
= mono_thread_info_is_async_context ();
1137 if (mono_llvm_only
) {
1143 ips
= get_unwind_backtrace ();
1144 for (l
= ips
; l
; l
= l
->next
) {
1145 guint8
*ip
= (guint8
*)l
->data
;
1146 memset (&frame
, 0, sizeof (StackFrameInfo
));
1147 frame
.ji
= mini_jit_info_table_find (domain
, ip
, &frame
.domain
);
1148 if (!frame
.ji
|| frame
.ji
->is_trampoline
)
1150 frame
.type
= FRAME_TYPE_MANAGED
;
1151 frame
.method
= jinfo_get_method (frame
.ji
);
1152 // FIXME: Cannot lookup the actual method
1153 frame
.actual_method
= frame
.method
;
1154 if (frame
.type
== FRAME_TYPE_MANAGED
) {
1155 if (!frame
.method
->wrapper_type
|| frame
.method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1156 frame
.managed
= TRUE
;
1158 frame
.native_offset
= ip
- (guint8
*)frame
.ji
->code_start
;
1159 frame
.il_offset
= -1;
1161 if (func (&frame
, NULL
, user_data
))
1169 g_assert (start_ctx
);
1172 /*The LMF will be null if the target have no managed frames.*/
1173 /* g_assert (lmf); */
1176 g_assert (unwind_options
== MONO_UNWIND_NONE
);
1178 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
1179 memset (reg_locations
, 0, sizeof (reg_locations
));
1181 unwinder_init (&unwinder
);
1183 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
1185 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, get_reg_locations
? new_reg_locations
: NULL
, &frame
);
1189 if ((unwind_options
& MONO_UNWIND_LOOKUP_IL_OFFSET
) && frame
.ji
&& !frame
.ji
->is_trampoline
) {
1190 MonoDebugSourceLocation
*source
;
1192 source
= mono_debug_lookup_source_location (jinfo_get_method (frame
.ji
), frame
.native_offset
, domain
);
1194 il_offset
= source
->il_offset
;
1197 if (mono_find_prev_seq_point_for_native_offset (domain
, jinfo_get_method (frame
.ji
), frame
.native_offset
, NULL
, &sp
))
1198 il_offset
= sp
.il_offset
;
1202 mono_debug_free_source_location (source
);
1206 frame
.il_offset
= il_offset
;
1208 if ((unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
) && frame
.ji
&& !frame
.ji
->is_trampoline
) {
1209 frame
.actual_method
= get_method_from_stack_frame (frame
.ji
, get_generic_info_from_stack_frame (frame
.ji
, &ctx
));
1211 frame
.actual_method
= frame
.method
;
1214 if (get_reg_locations
)
1215 frame
.reg_locations
= reg_locations
;
1217 if (func (&frame
, &ctx
, user_data
))
1220 if (get_reg_locations
) {
1221 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
)
1222 if (new_reg_locations
[i
])
1223 reg_locations
[i
] = new_reg_locations
[i
];
1231 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
1232 MonoReflectionMethod
**method
,
1233 gint32
*iloffset
, gint32
*native_offset
,
1234 MonoString
**file
, gint32
*line
, gint32
*column
)
1237 MonoDomain
*domain
= mono_domain_get ();
1238 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
1239 MonoLMF
*lmf
= mono_get_lmf ();
1240 MonoJitInfo
*ji
= NULL
;
1241 MonoContext ctx
, new_ctx
;
1242 MonoDebugSourceLocation
*location
;
1243 MonoMethod
*jmethod
= NULL
, *actual_method
;
1244 StackFrameInfo frame
;
1249 MONO_ARCH_CONTEXT_DEF
;
1251 if (mono_llvm_only
) {
1253 MonoDomain
*frame_domain
;
1254 guint8
*frame_ip
= NULL
;
1256 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1258 ips
= get_unwind_backtrace ();
1259 for (l
= ips
; l
&& skip
>= 0; l
= l
->next
) {
1260 guint8
*ip
= (guint8
*)l
->data
;
1264 ji
= mini_jit_info_table_find (mono_domain_get (), ip
, &frame_domain
);
1265 if (!ji
|| ji
->is_trampoline
)
1268 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1269 jmethod
= jinfo_get_method (ji
);
1270 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1277 /* No way to resolve generic instances */
1278 actual_method
= jmethod
;
1279 *native_offset
= frame_ip
- (guint8
*)ji
->code_start
;
1281 mono_arch_flush_register_windows ();
1283 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1284 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
1286 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
1289 unwinder_init (&unwinder
);
1294 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
1297 switch (frame
.type
) {
1298 case FRAME_TYPE_MANAGED_TO_NATIVE
:
1299 case FRAME_TYPE_DEBUGGER_INVOKE
:
1300 case FRAME_TYPE_TRAMPOLINE
:
1302 case FRAME_TYPE_INTERP_TO_MANAGED
:
1304 /* gsharedvt_out_sig_wrapper from interp2jit transition */
1309 case FRAME_TYPE_INTERP
:
1310 case FRAME_TYPE_MANAGED
:
1312 *native_offset
= frame
.native_offset
;
1314 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1315 jmethod
= jinfo_get_method (ji
);
1316 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1321 g_assert_not_reached ();
1323 } while (skip
>= 0);
1325 if (frame
.type
== FRAME_TYPE_INTERP
) {
1326 jmethod
= frame
.method
;
1327 actual_method
= frame
.actual_method
;
1329 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &ctx
));
1333 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, actual_method
, NULL
, error
);
1334 if (!mono_error_ok (error
)) {
1335 mono_error_set_pending_exception (error
);
1338 mono_gc_wbarrier_generic_store (method
, (MonoObject
*) rm
);
1340 if (il_offset
!= -1) {
1341 location
= mono_debug_lookup_source_location_by_il (jmethod
, il_offset
, domain
);
1343 location
= mono_debug_lookup_source_location (jmethod
, *native_offset
, domain
);
1346 *iloffset
= location
->il_offset
;
1350 if (need_file_info
) {
1352 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1353 if (!is_ok (error
)) {
1354 mono_error_set_pending_exception (error
);
1357 mono_gc_wbarrier_generic_store (file
, (MonoObject
*)filename
);
1358 *line
= location
->row
;
1359 *column
= location
->column
;
1362 *line
= *column
= 0;
1366 mono_debug_free_source_location (location
);
1372 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
1375 MonoClass
*catch_class
= ei
->data
.catch_class
;
1376 MonoType
*inflated_type
;
1377 MonoGenericContext context
;
1379 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1380 if (!catch_class
|| ei
->flags
!= MONO_EXCEPTION_CLAUSE_NONE
)
1383 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
1385 context
= get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
1387 /* FIXME: we shouldn't inflate but instead put the
1388 type in the rgctx and fetch it from there. It
1389 might be a good idea to do this lazily, i.e. only
1390 when the exception is actually thrown, so as not to
1391 waste space for exception clauses which might never
1393 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
1394 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1396 catch_class
= mono_class_from_mono_type (inflated_type
);
1397 mono_metadata_free_type (inflated_type
);
1403 * mini_jit_info_table_find_ext:
1405 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1406 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1407 * OUT_DOMAIN if it is not NULL.
1410 mini_jit_info_table_find_ext (MonoDomain
*domain
, gpointer addr
, gboolean allow_trampolines
, MonoDomain
**out_domain
)
1413 MonoInternalThread
*t
= mono_thread_internal_current ();
1419 ji
= mono_jit_info_table_find_internal (domain
, addr
, TRUE
, allow_trampolines
);
1422 *out_domain
= domain
;
1426 /* maybe it is shared code, so we also search in the root domain */
1427 if (domain
!= mono_get_root_domain ()) {
1428 ji
= mono_jit_info_table_find_internal (mono_get_root_domain (), addr
, TRUE
, allow_trampolines
);
1431 *out_domain
= mono_get_root_domain ();
1439 refs
= (gpointer
*)((t
->appdomain_refs
) ? *(gpointer
*) t
->appdomain_refs
: NULL
);
1440 for (; refs
&& *refs
; refs
++) {
1441 if (*refs
!= domain
&& *refs
!= mono_get_root_domain ()) {
1442 ji
= mono_jit_info_table_find_internal ((MonoDomain
*) *refs
, addr
, TRUE
, allow_trampolines
);
1445 *out_domain
= (MonoDomain
*) *refs
;
1455 mini_jit_info_table_find (MonoDomain
*domain
, gpointer addr
, MonoDomain
**out_domain
)
1457 return mini_jit_info_table_find_ext (domain
, addr
, FALSE
, out_domain
);
1460 /* Class lazy loading functions */
1461 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr
, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
1464 * wrap_non_exception_throws:
1466 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
1467 * WrapNonExceptionThrows flag set.
1470 wrap_non_exception_throws (MonoMethod
*m
)
1473 MonoAssembly
*ass
= m_class_get_image (m
->klass
)->assembly
;
1474 MonoCustomAttrInfo
* attrs
;
1477 gboolean val
= FALSE
;
1479 if (m
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
1480 MonoDynamicMethod
*dm
= (MonoDynamicMethod
*)m
;
1485 if (ass
->wrap_non_exception_throws_inited
)
1486 return ass
->wrap_non_exception_throws
;
1488 klass
= mono_class_get_runtime_compat_attr_class ();
1490 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
1491 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1493 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
1494 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
1496 int num_named
, named_type
, name_len
;
1499 if (!attr
->ctor
|| attr
->ctor
->klass
!= klass
)
1501 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
1502 p
= (const char*)attr
->data
;
1503 g_assert (read16 (p
) == 0x0001);
1505 num_named
= read16 (p
);
1511 /* data_type = *p; */
1514 if (named_type
!= 0x54)
1516 name_len
= mono_metadata_decode_blob_size (p
, &p
);
1517 name
= (char *)g_malloc (name_len
+ 1);
1518 memcpy (name
, p
, name_len
);
1519 name
[name_len
] = 0;
1521 g_assert (!strcmp (name
, "WrapNonExceptionThrows"));
1523 /* The value is a BOOLEAN */
1526 mono_custom_attrs_free (attrs
);
1529 ass
->wrap_non_exception_throws
= val
;
1530 mono_memory_barrier ();
1531 ass
->wrap_non_exception_throws_inited
= TRUE
;
1536 #define MAX_UNMANAGED_BACKTRACE 128
1538 build_native_trace (MonoError
*error
)
1541 /* This puppy only makes sense on mobile, IOW, ARM. */
1542 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
1544 void *native_trace
[MAX_UNMANAGED_BACKTRACE
];
1547 size
= backtrace (native_trace
, MAX_UNMANAGED_BACKTRACE
);
1553 res
= mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, size
, error
);
1554 return_val_if_nok (error
, NULL
);
1556 for (i
= 0; i
< size
; i
++)
1557 mono_array_set (res
, gpointer
, i
, native_trace
[i
]);
1565 setup_stack_trace (MonoException
*mono_ex
, GSList
*dynamic_methods
, GList
**trace_ips
)
1568 *trace_ips
= g_list_reverse (*trace_ips
);
1570 MonoArray
*ips_arr
= mono_glist_to_array (*trace_ips
, mono_defaults
.int_class
, error
);
1571 mono_error_assert_ok (error
);
1572 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, ips_arr
);
1573 MONO_OBJECT_SETREF (mono_ex
, native_trace_ips
, build_native_trace (error
));
1574 mono_error_assert_ok (error
);
1575 if (dynamic_methods
) {
1576 /* These methods could go away anytime, so save a reference to them in the exception object */
1578 MonoMList
*list
= NULL
;
1580 for (l
= dynamic_methods
; l
; l
= l
->next
) {
1582 MonoDomain
*domain
= mono_domain_get ();
1584 if (domain
->method_to_dyn_method
) {
1585 mono_domain_lock (domain
);
1586 dis_link
= (guint32
)(size_t)g_hash_table_lookup (domain
->method_to_dyn_method
, l
->data
);
1587 mono_domain_unlock (domain
);
1589 MonoObject
*o
= mono_gchandle_get_target (dis_link
);
1591 list
= mono_mlist_prepend_checked (list
, o
, error
);
1592 mono_error_assert_ok (error
);
1598 MONO_OBJECT_SETREF (mono_ex
, dynamic_methods
, list
);
1601 g_list_free (*trace_ips
);
1606 * handle_exception_first_pass:
1608 * The first pass of exception handling. Unwind the stack until a catch clause which can catch
1609 * OBJ is found. Store the index of the filter clause which caught the exception into
1610 * OUT_FILTER_IDX. Return TRUE if the exception is caught, FALSE otherwise.
1613 handle_exception_first_pass (MonoContext
*ctx
, MonoObject
*obj
, gint32
*out_filter_idx
, MonoJitInfo
**out_ji
, MonoJitInfo
**out_prev_ji
, MonoObject
*non_exception
, StackFrameInfo
*catch_frame
)
1616 MonoDomain
*domain
= mono_domain_get ();
1617 MonoJitInfo
*ji
= NULL
;
1618 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
1619 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
1620 MonoLMF
*lmf
= mono_get_lmf ();
1621 GList
*trace_ips
= NULL
;
1622 GSList
*dynamic_methods
= NULL
;
1623 MonoException
*mono_ex
;
1624 gboolean stack_overflow
= FALSE
;
1625 MonoContext initial_ctx
;
1627 int frame_count
= 0;
1634 g_assert (ctx
!= NULL
);
1636 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
1637 stack_overflow
= TRUE
;
1639 mono_ex
= (MonoException
*)obj
;
1640 MonoArray
*initial_trace_ips
= mono_ex
->trace_ips
;
1641 if (initial_trace_ips
) {
1642 int len
= mono_array_length (initial_trace_ips
) / TRACE_IP_ENTRY_SIZE
;
1644 for (i
= 0; i
< (len
- 1); i
++) {
1645 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
1646 gpointer p
= mono_array_get (initial_trace_ips
, gpointer
, (i
* TRACE_IP_ENTRY_SIZE
) + j
);
1647 trace_ips
= g_list_prepend (trace_ips
, p
);
1652 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
1653 mono_error_assert_ok (error
);
1658 call_filter
= (int (*) (MonoContext
*, void *))mono_get_call_filter ();
1660 g_assert (jit_tls
->end_of_stack
);
1661 g_assert (jit_tls
->abort_func
);
1664 *out_filter_idx
= -1;
1668 *out_prev_ji
= NULL
;
1672 unwinder_init (&unwinder
);
1675 MonoContext new_ctx
;
1677 int clause_index_start
= 0;
1678 gboolean unwind_res
= TRUE
;
1680 StackFrameInfo frame
;
1685 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
1687 setup_stack_trace (mono_ex
, dynamic_methods
, &trace_ips
);
1688 g_slist_free (dynamic_methods
);
1692 switch (frame
.type
) {
1693 case FRAME_TYPE_DEBUGGER_INVOKE
:
1694 case FRAME_TYPE_MANAGED_TO_NATIVE
:
1695 case FRAME_TYPE_TRAMPOLINE
:
1696 case FRAME_TYPE_INTERP_TO_MANAGED
:
1699 case FRAME_TYPE_INTERP
:
1700 case FRAME_TYPE_MANAGED
:
1703 g_assert_not_reached ();
1707 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
1712 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
1714 ip
= MONO_CONTEXT_GET_IP (ctx
);
1717 method
= jinfo_get_method (ji
);
1718 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
1720 if (mini_get_debug_options ()->reverse_pinvoke_exceptions
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
1721 g_error ("A native frame was found while unwinding the stack after an exception.\n"
1722 "The native frame called the managed method:\n%s\n",
1723 mono_method_full_name (method
, TRUE
));
1726 if (method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
1727 // avoid giant stack traces during a stack overflow
1728 if (frame_count
< 1000) {
1729 trace_ips
= g_list_prepend (trace_ips
, ip
);
1730 trace_ips
= g_list_prepend (trace_ips
, get_generic_info_from_stack_frame (ji
, ctx
));
1731 trace_ips
= g_list_prepend (trace_ips
, ji
);
1735 if (method
->dynamic
)
1736 dynamic_methods
= g_slist_prepend (dynamic_methods
, method
);
1738 if (stack_overflow
) {
1739 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
1741 free_stack
= 0xffffff;
1744 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
1745 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
1746 gboolean filtered
= FALSE
;
1749 * During stack overflow, wait till the unwinding frees some stack
1750 * space before running handlers/finalizers.
1752 if (free_stack
<= (64 * 1024))
1755 if (is_address_protected (ji
, ei
, ip
)) {
1757 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
1760 * Have to unwrap RuntimeWrappedExceptions if the
1761 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1763 if (non_exception
&& !wrap_non_exception_throws (method
))
1764 ex_obj
= non_exception
;
1768 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
1769 #ifndef DISABLE_PERFCOUNTERS
1770 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_filters
);
1773 if (!ji
->is_interp
) {
1774 #ifndef MONO_CROSS_COMPILE
1775 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1777 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
1779 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
1780 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
1782 g_assert (!ji
->from_llvm
);
1783 /* store the exception object in bp + ei->exvar_offset */
1784 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
1788 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
1790 * Pass the original il clause index to the landing pad so it can
1791 * branch to the landing pad associated with the il clause.
1792 * This is needed because llvm compiled code assumes that the EH
1793 * code always branches to the innermost landing pad.
1796 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
1800 mono_debugger_agent_begin_exception_filter (mono_ex
, ctx
, &initial_ctx
);
1801 if (ji
->is_interp
) {
1802 filtered
= mini_get_interp_callbacks ()->run_filter (&frame
, (MonoException
*)ex_obj
, i
, ei
->data
.filter
);
1804 filtered
= call_filter (ctx
, ei
->data
.filter
);
1806 mono_debugger_agent_end_exception_filter (mono_ex
, ctx
, &initial_ctx
);
1807 if (filtered
&& out_filter_idx
)
1808 *out_filter_idx
= filter_idx
;
1814 setup_stack_trace (mono_ex
, dynamic_methods
, &trace_ips
);
1815 g_slist_free (dynamic_methods
);
1816 /* mono_debugger_agent_handle_exception () needs this */
1817 mini_set_abort_threshold (&frame
);
1818 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
1819 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
1820 *catch_frame
= frame
;
1825 ERROR_DECL_VALUE (isinst_error
);
1826 error_init (&isinst_error
);
1827 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (ex_obj
, catch_class
, error
)) {
1828 setup_stack_trace (mono_ex
, dynamic_methods
, &trace_ips
);
1829 g_slist_free (dynamic_methods
);
1834 /* mono_debugger_agent_handle_exception () needs this */
1836 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
1837 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
1838 *catch_frame
= frame
;
1841 mono_error_cleanup (&isinst_error
);
1848 g_assert_not_reached ();
1852 * mono_handle_exception_internal:
1853 * \param ctx saved processor state
1854 * \param obj the exception object
1855 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
1858 mono_handle_exception_internal (MonoContext
*ctx
, MonoObject
*obj
, gboolean resume
, MonoJitInfo
**out_ji
)
1861 MonoDomain
*domain
= mono_domain_get ();
1862 MonoJitInfo
*ji
, *prev_ji
;
1863 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
1864 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
1865 MonoLMF
*lmf
= mono_get_lmf ();
1866 MonoException
*mono_ex
;
1867 gboolean stack_overflow
= FALSE
;
1868 MonoContext initial_ctx
;
1870 int frame_count
= 0;
1871 gint32 filter_idx
, first_filter_idx
= 0;
1874 MonoObject
*non_exception
= NULL
;
1878 g_assert (ctx
!= NULL
);
1880 MonoException
*ex
= mono_get_exception_null_reference ();
1881 MonoString
*msg
= mono_string_new_checked (domain
, "Object reference not set to an instance of an object", error
);
1882 mono_error_assert_ok (error
);
1883 MONO_OBJECT_SETREF (ex
, message
, msg
);
1884 obj
= (MonoObject
*)ex
;
1888 * Allocate a new exception object instead of the preconstructed ones.
1890 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
) {
1892 * It is not a good idea to try and put even more pressure on the little stack available.
1893 * obj = mono_get_exception_stack_overflow ();
1895 stack_overflow
= TRUE
;
1897 else if (obj
== (MonoObject
*)domain
->null_reference_ex
) {
1898 obj
= (MonoObject
*)mono_get_exception_null_reference ();
1901 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
1902 mono_error_assert_ok (error
);
1903 non_exception
= obj
;
1904 obj
= (MonoObject
*)mono_get_exception_runtime_wrapped_checked (obj
, error
);
1905 mono_error_assert_ok (error
);
1908 mono_ex
= (MonoException
*)obj
;
1910 if (mini_get_debug_options ()->suspend_on_exception
) {
1911 mono_runtime_printf_err ("Exception thrown, suspending...");
1916 if (mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
1917 mono_ex
= (MonoException
*)obj
;
1919 mono_error_assert_ok (error
);
1923 if (mono_ex
&& jit_tls
->class_cast_from
) {
1924 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "InvalidCastException")) {
1925 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
1926 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
1927 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
1928 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
1931 if (!is_ok (error
)) {
1932 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg
);
1933 mono_error_assert_ok (error
);
1937 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "ArrayTypeMismatchException")) {
1938 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
1939 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
1940 char *msg
= g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name
, to_name
);
1941 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
1944 if (!is_ok (error
)) {
1945 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg
);
1946 mono_error_assert_ok (error
);
1953 call_filter
= (int (*)(MonoContext
*, void*))mono_get_call_filter ();
1955 g_assert (jit_tls
->end_of_stack
);
1956 g_assert (jit_tls
->abort_func
);
1959 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
1960 * end up being TRUE on any code path.
1962 memcpy (&jit_tls
->orig_ex_ctx
, ctx
, sizeof (MonoContext
));
1967 MonoContext ctx_cp
= *ctx
;
1968 if (mono_trace_is_enabled ()) {
1969 MonoMethod
*system_exception_get_message
= mono_class_get_method_from_name (mono_defaults
.exception_class
, "get_Message", 0);
1970 MonoMethod
*get_message
= system_exception_get_message
== NULL
? NULL
: mono_object_get_virtual_method (obj
, system_exception_get_message
);
1971 MonoObject
*message
;
1972 const char *type_name
= mono_class_get_name (mono_object_class (mono_ex
));
1974 if (get_message
== NULL
) {
1976 } else if (!strcmp (type_name
, "OutOfMemoryException") || !strcmp (type_name
, "StackOverflowException")) {
1978 msg
= g_strdup_printf ("(No exception message for: %s)\n", type_name
);
1980 MonoObject
*exc
= NULL
;
1981 message
= mono_runtime_try_invoke (get_message
, obj
, NULL
, &exc
, error
);
1982 g_assert (exc
== NULL
);
1983 mono_error_assert_ok (error
);
1987 msg
= mono_string_to_utf8_checked ((MonoString
*) message
, error
);
1988 if (!is_ok (error
)) {
1989 mono_error_cleanup (error
);
1990 msg
= g_strdup ("(error while display System.Exception.Message property)");
1993 msg
= g_strdup ("(System.Exception.Message property not available)");
1996 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)mono_native_thread_id_get (), m_class_get_name_space (mono_object_class (obj
)), m_class_get_name (mono_object_class (obj
)), msg
);
1998 if (mono_ex
&& mono_trace_eval_exception (mono_object_class (mono_ex
)))
1999 mono_print_thread_dump_from_ctx (ctx
);
2001 jit_tls
->orig_ex_ctx_set
= TRUE
;
2002 MONO_PROFILER_RAISE (exception_throw
, (obj
));
2003 jit_tls
->orig_ex_ctx_set
= FALSE
;
2005 StackFrameInfo catch_frame
;
2006 res
= handle_exception_first_pass (&ctx_cp
, obj
, &first_filter_idx
, &ji
, &prev_ji
, non_exception
, &catch_frame
);
2009 if (mini_get_debug_options ()->break_on_exc
)
2011 mono_debugger_agent_handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2013 if (mini_get_debug_options ()->suspend_on_unhandled
) {
2014 mono_runtime_printf_err ("Unhandled exception, suspending...");
2019 // FIXME: This runs managed code so it might cause another stack overflow when
2020 // we are handling a stack overflow
2021 mini_set_abort_threshold (&catch_frame
);
2022 mono_unhandled_exception (obj
);
2024 gboolean unhandled
= FALSE
;
2027 * The exceptions caught by the mono_runtime_invoke_checked () calls
2028 * in the threadpool needs to be treated as unhandled (#669836).
2030 * FIXME: The check below is hackish, but its hard to distinguish
2031 * these runtime invoke calls from others in the runtime.
2033 if (ji
&& jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2034 if (prev_ji
&& jinfo_get_method (prev_ji
) == mono_defaults
.threadpool_perform_wait_callback_method
)
2039 mono_debugger_agent_handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2041 mono_debugger_agent_handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2050 unwinder_init (&unwinder
);
2053 MonoContext new_ctx
;
2055 int clause_index_start
= 0;
2056 gboolean unwind_res
= TRUE
;
2057 StackFrameInfo frame
;
2062 ji
= jit_tls
->resume_state
.ji
;
2063 new_ctx
= jit_tls
->resume_state
.new_ctx
;
2064 clause_index_start
= jit_tls
->resume_state
.clause_index
;
2065 lmf
= jit_tls
->resume_state
.lmf
;
2066 first_filter_idx
= jit_tls
->resume_state
.first_filter_idx
;
2067 filter_idx
= jit_tls
->resume_state
.filter_idx
;
2070 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2072 *(mono_get_lmf_addr ()) = lmf
;
2074 jit_tls
->abort_func (obj
);
2075 g_assert_not_reached ();
2077 switch (frame
.type
) {
2078 case FRAME_TYPE_DEBUGGER_INVOKE
:
2079 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2080 case FRAME_TYPE_TRAMPOLINE
:
2083 case FRAME_TYPE_INTERP_TO_MANAGED
:
2085 case FRAME_TYPE_INTERP
:
2086 case FRAME_TYPE_MANAGED
:
2089 g_assert_not_reached ();
2092 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2097 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2099 ip
= MONO_CONTEXT_GET_IP (ctx
);
2101 method
= jinfo_get_method (ji
);
2103 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2105 if (stack_overflow
) {
2106 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2108 free_stack
= 0xffffff;
2111 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2112 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2113 gboolean filtered
= FALSE
;
2116 * During stack overflow, wait till the unwinding frees some stack
2117 * space before running handlers/finalizers.
2119 if (free_stack
<= (64 * 1024))
2122 if (is_address_protected (ji
, ei
, ip
)) {
2124 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2127 * Have to unwrap RuntimeWrappedExceptions if the
2128 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2130 if (non_exception
&& !wrap_non_exception_throws (method
))
2131 ex_obj
= non_exception
;
2135 if (((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
))) {
2136 #ifndef MONO_CROSS_COMPILE
2137 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2138 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2140 g_assert (!ji
->from_llvm
);
2141 /* store the exception object in bp + ei->exvar_offset */
2142 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2147 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2149 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2152 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2154 * Filter clauses should only be run in the
2155 * first pass of exception handling.
2157 filtered
= (filter_idx
== first_filter_idx
);
2162 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
2163 mono_object_isinst_checked (ex_obj
, catch_class
, error
)) || filtered
) {
2165 * This guards against the situation that we abort a thread that is executing a finally clause
2166 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2167 * check for this situation here and resume interruption if we are below the guarded block.
2169 if (G_UNLIKELY (jit_tls
->handler_block
)) {
2170 gboolean is_outside
= FALSE
;
2171 gpointer prot_bp
= MONO_CONTEXT_GET_BP (&jit_tls
->handler_block_context
);
2172 gpointer catch_bp
= MONO_CONTEXT_GET_BP (ctx
);
2173 //FIXME make this stack direction aware
2175 if (catch_bp
> prot_bp
) {
2177 } else if (catch_bp
== prot_bp
) {
2178 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2179 * So we check if the catch handler_start is protected by the guarded handler protected region
2182 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2183 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2184 * There aren't any further finally/fault handler blocks down the stack over this exception.
2185 * This must be ensured by the code that installs the guard trampoline.
2187 g_assert (ji
== mini_jit_info_table_find (domain
, (char *)MONO_CONTEXT_GET_IP (&jit_tls
->handler_block_context
), NULL
));
2189 if (!is_address_protected (ji
, jit_tls
->handler_block
, ei
->handler_start
)) {
2194 jit_tls
->handler_block
= NULL
;
2195 mono_thread_resume_interruption (TRUE
); /*We ignore the exception here, it will be raised later*/
2199 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2200 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2201 jit_tls
->orig_ex_ctx_set
= TRUE
;
2202 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, ei
->flags
, ex_obj
));
2203 jit_tls
->orig_ex_ctx_set
= FALSE
;
2204 mini_set_abort_threshold (&frame
);
2208 * ctx->pc points into the interpreter, after the call which transitioned to
2209 * JITted code. Store the unwind state into the
2210 * interpeter state, then resume, the interpreter will unwind itself until
2211 * it reaches the target frame and will continue execution from there.
2212 * The resuming is kinda hackish, from the native code standpoint, it looks
2213 * like the call which transitioned to JITted code has succeeded, but the
2214 * return value register etc. is not set, so we have to be careful.
2216 mini_get_interp_callbacks ()->set_resume_state (jit_tls
, mono_ex
, ei
, frame
.interp_frame
, ei
->handler_start
);
2217 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2218 /* ip == 0 means an interpreter frame */
2219 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
2220 mono_arch_undo_ip_adjustment (ctx
);
2222 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2225 #ifndef DISABLE_PERFCOUNTERS
2226 mono_atomic_fetch_add_i32 (&mono_perfcounters
->exceptions_depth
, frame_count
);
2228 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2229 jit_tls
->handling_stack_ovf
= FALSE
;
2233 mono_error_cleanup (error
);
2234 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) {
2235 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2236 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2237 jit_tls
->orig_ex_ctx_set
= TRUE
;
2238 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, ei
->flags
, ex_obj
));
2239 jit_tls
->orig_ex_ctx_set
= FALSE
;
2241 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2242 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2243 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2244 jit_tls
->orig_ex_ctx_set
= TRUE
;
2245 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, ei
->flags
, ex_obj
));
2246 jit_tls
->orig_ex_ctx_set
= FALSE
;
2247 #ifndef DISABLE_PERFCOUNTERS
2248 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_finallys
);
2251 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
|| ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2253 if (ji
->from_llvm
) {
2255 * LLVM compiled finally handlers follow the design
2256 * of the c++ ehabi, i.e. they call a resume function
2257 * at the end instead of returning to the caller.
2258 * So save the exception handling state,
2259 * mono_resume_unwind () will call us again to continue
2262 jit_tls
->resume_state
.ex_obj
= obj
;
2263 jit_tls
->resume_state
.ji
= ji
;
2264 jit_tls
->resume_state
.clause_index
= i
+ 1;
2265 jit_tls
->resume_state
.ctx
= *ctx
;
2266 jit_tls
->resume_state
.new_ctx
= new_ctx
;
2267 jit_tls
->resume_state
.lmf
= lmf
;
2268 jit_tls
->resume_state
.first_filter_idx
= first_filter_idx
;
2269 jit_tls
->resume_state
.filter_idx
= filter_idx
;
2270 mini_set_abort_threshold (&frame
);
2271 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2274 mini_set_abort_threshold (&frame
);
2276 gboolean has_ex
= mini_get_interp_callbacks ()->run_finally (&frame
, i
, ei
->handler_start
);
2280 call_filter (ctx
, ei
->handler_start
);
2287 if (MONO_PROFILER_ENABLED (method_exception_leave
) &&
2288 mono_profiler_get_call_instrumentation_flags (method
) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
) {
2289 jit_tls
->orig_ex_ctx_set
= TRUE
;
2290 MONO_PROFILER_RAISE (method_exception_leave
, (method
, ex_obj
));
2291 jit_tls
->orig_ex_ctx_set
= FALSE
;
2297 g_assert_not_reached ();
2301 * mono_debugger_run_finally:
2302 * \param start_ctx saved processor state
2303 * This method is called by the Mono Debugger to call all \c finally clauses of the
2304 * current stack frame. It's used when the user issues a \c return command to make
2305 * the current stack frame return. After returning from this method, the debugger
2306 * unwinds the stack one frame and gives control back to the user.
2307 * NOTE: This method is only used when running inside the Mono Debugger.
2310 mono_debugger_run_finally (MonoContext
*start_ctx
)
2312 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2313 MonoDomain
*domain
= mono_domain_get ();
2314 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
2315 MonoLMF
*lmf
= mono_get_lmf ();
2316 MonoContext ctx
, new_ctx
;
2317 MonoJitInfo
*ji
, rji
;
2322 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
2323 if (!ji
|| ji
== (gpointer
)-1)
2327 call_filter
= (int (*)(MonoContext
*, void *))mono_get_call_filter ();
2329 for (i
= 0; i
< ji
->num_clauses
; i
++) {
2330 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2332 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (&ctx
)) &&
2333 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
2334 call_filter (&ctx
, ei
->handler_start
);
2340 * mono_handle_exception:
2341 * \param ctx saved processor state
2342 * \param obj the exception object
2344 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
2348 mono_handle_exception (MonoContext
*ctx
, MonoObject
*obj
)
2350 MONO_REQ_GC_UNSAFE_MODE
;
2352 #ifndef DISABLE_PERFCOUNTERS
2353 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_thrown
);
2356 return mono_handle_exception_internal (ctx
, obj
, FALSE
, NULL
);
2359 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2361 #ifndef MONO_ARCH_USE_SIGACTION
2362 #error "Can't use sigaltstack without sigaction"
2366 mono_setup_altstack (MonoJitTlsData
*tls
)
2370 guint8
*staddr
= NULL
;
2372 if (mono_running_on_valgrind ())
2375 mono_thread_info_get_stack_bounds (&staddr
, &stsize
);
2379 tls
->end_of_stack
= staddr
+ stsize
;
2380 tls
->stack_size
= stsize
;
2382 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
2384 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
2385 tls
->stack_ovf_guard_size
= ALIGN_TO (8 * 4096, mono_pagesize ());
2387 g_assert ((guint8
*)&sa
>= (guint8
*)tls
->stack_ovf_guard_base
+ tls
->stack_ovf_guard_size
);
2389 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
2390 /* mprotect can fail for the main thread stack */
2391 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
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
2392 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
2393 tls
->stack_ovf_valloced
= TRUE
;
2396 /* Setup an alternate signal stack */
2397 tls
->signal_stack
= mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MMAP_READ
|MONO_MMAP_WRITE
|MONO_MMAP_PRIVATE
|MONO_MMAP_ANON
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
2398 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
2400 g_assert (tls
->signal_stack
);
2402 sa
.ss_sp
= tls
->signal_stack
;
2403 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
2405 g_assert (sigaltstack (&sa
, NULL
) == 0);
2407 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
);
2411 mono_free_altstack (MonoJitTlsData
*tls
)
2416 sa
.ss_sp
= tls
->signal_stack
;
2417 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
2418 sa
.ss_flags
= SS_DISABLE
;
2419 err
= sigaltstack (&sa
, NULL
);
2420 g_assert (err
== 0);
2422 if (tls
->signal_stack
)
2423 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
2424 if (tls
->stack_ovf_valloced
)
2425 mono_vfree (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
2427 mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
2430 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
2433 mono_setup_altstack (MonoJitTlsData
*tls
)
2438 mono_free_altstack (MonoJitTlsData
*tls
)
2442 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
2445 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*siginfo
, guint8
* fault_addr
)
2450 /* we got a stack overflow in the soft-guard pages
2451 * There are two cases:
2452 * 1) managed code caused the overflow: we unprotect the soft-guard page
2453 * and let the arch-specific code trigger the exception handling mechanism
2454 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
2455 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
2456 * and hope we can continue with those enabled, at least until the hard-guard page
2457 * is hit. The alternative to continuing here is to just print a message and abort.
2458 * We may add in the future the code to protect the pages again in the codepath
2459 * when we return from unmanaged to managed code.
2461 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
2462 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
2463 gboolean handled
= FALSE
;
2465 mono_mprotect (jit_tls
->stack_ovf_guard_base
, jit_tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
2466 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2468 mono_arch_handle_altstack_exception (ctx
, siginfo
, fault_addr
, TRUE
);
2473 /* We print a message: after this even managed stack overflows
2474 * may crash the runtime
2476 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx
), fault_addr
);
2477 if (!jit_tls
->handling_stack_ovf
) {
2478 jit_tls
->handling_stack_ovf
= 1;
2480 /*fprintf (stderr, "Already handling stack overflow\n");*/
2489 MonoMethod
*omethod
;
2491 } PrintOverflowUserData
;
2493 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2495 print_overflow_stack_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
2497 MonoMethod
*method
= NULL
;
2498 PrintOverflowUserData
*user_data
= (PrintOverflowUserData
*)data
;
2501 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
2502 method
= jinfo_get_method (frame
->ji
);
2505 if (user_data
->count
== 0) {
2506 /* The first frame is in its prolog, so a line number cannot be computed */
2507 user_data
->count
++;
2511 /* If this is a one method overflow, skip the other instances */
2512 if (method
== user_data
->omethod
)
2515 location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, mono_domain_get ());
2516 mono_runtime_printf_err (" %s", location
);
2519 if (user_data
->count
== 1) {
2520 mono_runtime_printf_err (" <...>");
2521 user_data
->omethod
= method
;
2523 user_data
->omethod
= NULL
;
2526 user_data
->count
++;
2528 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame
->native_offset
);
2535 mono_handle_hard_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, guint8
* fault_addr
)
2537 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2538 PrintOverflowUserData ud
;
2542 /* we don't do much now, but we can warn the user with a useful message */
2543 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx
), fault_addr
);
2545 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2546 mono_sigctx_to_monoctx (ctx
, &mctx
);
2548 mono_runtime_printf_err ("Stacktrace:");
2550 memset (&ud
, 0, sizeof (ud
));
2552 mono_walk_stack_with_ctx (print_overflow_stack_frame
, &mctx
, MONO_UNWIND_LOOKUP_ACTUAL_METHOD
, &ud
);
2554 if (ji
&& !ji
->is_trampoline
&& jinfo_get_method (ji
))
2555 mono_runtime_printf_err ("At %s", mono_method_full_name (jinfo_get_method (ji
), TRUE
));
2557 mono_runtime_printf_err ("At <unmanaged>.");
2564 print_stack_frame_to_stderr (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
2566 MonoMethod
*method
= NULL
;
2568 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
2569 method
= jinfo_get_method (frame
->ji
);
2572 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, mono_domain_get ());
2573 mono_runtime_printf_err (" %s", location
);
2576 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame
->native_offset
);
2581 static G_GNUC_UNUSED gboolean
2582 print_stack_frame_to_string (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
2584 GString
*p
= (GString
*)data
;
2585 MonoMethod
*method
= NULL
;
2587 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
2588 method
= jinfo_get_method (frame
->ji
);
2590 if (method
&& frame
->domain
) {
2591 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
2592 g_string_append_printf (p
, " %s\n", location
);
2595 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
2600 #ifndef MONO_CROSS_COMPILE
2602 static void print_process_map (void)
2605 FILE *fp
= fopen ("/proc/self/maps", "r");
2609 mono_runtime_printf_err ("no /proc/self/maps, not on linux?\n");
2613 mono_runtime_printf_err ("/proc/self/maps:");
2615 while (fgets (line
, sizeof (line
), fp
)) {
2617 size_t len
= strlen (line
) - 1;
2618 if (len
>= 0 && line
[len
] == '\n')
2621 mono_runtime_printf_err ("%s", line
);
2630 static gboolean handle_crash_loop
= FALSE
;
2633 * mono_handle_native_crash:
2635 * Handle a native crash (e.g. SIGSEGV) while in native code by
2636 * printing diagnostic information and aborting.
2639 mono_handle_native_crash (const char *signal
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
2641 #ifdef MONO_ARCH_USE_SIGACTION
2642 struct sigaction sa
;
2644 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
2646 if (handle_crash_loop
)
2649 if (mini_get_debug_options ()->suspend_on_native_crash
) {
2650 mono_runtime_printf_err ("Received %s, suspending...", signal
);
2661 /* prevent infinite loops in crash handling */
2662 handle_crash_loop
= TRUE
;
2664 /* !jit_tls means the thread was not registered with the runtime */
2665 if (jit_tls
&& mono_thread_internal_current ()) {
2666 mono_runtime_printf_err ("Stacktrace:\n");
2668 /* FIXME: Is MONO_UNWIND_LOOKUP_IL_OFFSET correct here? */
2669 mono_walk_stack (print_stack_frame_to_stderr
, MONO_UNWIND_LOOKUP_IL_OFFSET
, NULL
);
2672 print_process_map ();
2674 #ifdef HAVE_BACKTRACE_SYMBOLS
2680 mono_runtime_printf_err ("\nNative stacktrace:\n");
2682 size
= backtrace (array
, 256);
2683 names
= backtrace_symbols (array
, size
);
2684 for (i
=0; i
< size
; ++i
) {
2685 mono_runtime_printf_err ("\t%s", names
[i
]);
2689 /* Try to get more meaningful information using gdb */
2691 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && (defined(SYS_fork) || HAVE_FORK)
2692 if (!mini_get_debug_options ()->no_gdb_backtrace
) {
2693 /* From g_spawn_command_line_sync () in eglib */
2696 pid_t crashed_pid
= getpid ();
2699 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
2700 * it will deadlock. Call the syscall directly instead.
2702 #if defined(HOST_ANDROID)
2703 /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
2704 g_assert_not_reached ();
2705 #elif !defined(HOST_DARWIN) && defined(SYS_fork)
2706 pid
= (pid_t
) syscall (SYS_fork
);
2708 pid
= (pid_t
) fork ();
2710 g_assert_not_reached ();
2713 #if defined (HAVE_PRCTL) && defined(PR_SET_PTRACER)
2715 // Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to
2716 // a value other than 0 (the most permissive ptrace scope). Most modern Linux
2717 // distributions set the scope to 1 which allows attaching only to direct children of
2718 // the current process
2719 prctl (PR_SET_PTRACER
, pid
, 0, 0, 0);
2723 #if defined(TARGET_OSX)
2724 if (mono_merp_enabled ()) {
2728 mono_runtime_printf_err ("\nMust always pass non-null context when using merp.\n");
2732 mono_sigctx_to_monoctx (ctx
, &mctx
);
2734 intptr_t thread_pointer
= (intptr_t) MONO_CONTEXT_GET_SP (&mctx
);
2736 mono_merp_invoke (crashed_pid
, thread_pointer
, signal
);
2744 dup2 (STDERR_FILENO
, STDOUT_FILENO
);
2746 mono_gdb_render_native_backtraces (crashed_pid
);
2750 mono_runtime_printf_err ("\nDebug info from gdb:\n");
2751 waitpid (pid
, &status
, 0);
2757 /* set DUMPABLE for this process so debuggerd can attach with ptrace(2), see:
2758 * https://android.googlesource.com/platform/bionic/+/151da681000c07da3c24cd30a3279b1ca017f452/linker/debugger.cpp#206
2759 * this has changed on later versions of Android. Also, we don't want to
2760 * set this on start-up as DUMPABLE has security implications. */
2761 prctl (PR_SET_DUMPABLE
, 1);
2763 mono_runtime_printf_err ("\nNo native Android stacktrace (see debuggerd output).\n");
2768 * A SIGSEGV indicates something went very wrong so we can no longer depend
2769 * on anything working. So try to print out lots of diagnostics, starting
2770 * with ones which have a greater chance of working.
2772 mono_runtime_printf_err (
2774 "=================================================================\n"
2775 "Got a %s while executing native code. This usually indicates\n"
2776 "a fatal error in the mono runtime or one of the native libraries \n"
2777 "used by your application.\n"
2778 "=================================================================\n",
2781 #ifdef MONO_ARCH_USE_SIGACTION
2782 sa
.sa_handler
= SIG_DFL
;
2783 sigemptyset (&sa
.sa_mask
);
2786 /* Remove our SIGABRT handler */
2787 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
2789 /* On some systems we get a SIGILL when calling abort (), because it might
2790 * fail to raise SIGABRT */
2791 g_assert (sigaction (SIGILL
, &sa
, NULL
) != -1);
2794 if (!mono_do_crash_chaining
) {
2795 /*Android abort is a fluke, it doesn't abort, it triggers another segv. */
2796 #if defined (HOST_ANDROID)
2807 mono_handle_native_crash (const char *signal
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
2809 g_assert_not_reached ();
2812 #endif /* !MONO_CROSS_COMPILE */
2815 mono_print_thread_dump_internal (void *sigctx
, MonoContext
*start_ctx
)
2817 MonoInternalThread
*thread
= mono_thread_internal_current ();
2818 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2823 GError
*gerror
= NULL
;
2828 text
= g_string_new (0);
2830 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &gerror
);
2832 g_string_append_printf (text
, "\n\"%s\"", name
);
2835 else if (thread
->threadpool_thread
)
2836 g_string_append (text
, "\n\"<threadpool thread>\"");
2838 g_string_append (text
, "\n\"<unnamed thread>\"");
2840 g_string_append_printf (text
, " tid=%p this=%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
2841 mono_thread_internal_describe (thread
, text
);
2842 g_string_append (text
, "\n");
2844 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2846 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
2848 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
2850 mono_sigctx_to_monoctx (sigctx
, &ctx
);
2852 mono_walk_stack_with_ctx (print_stack_frame_to_string
, &ctx
, MONO_UNWIND_LOOKUP_ALL
, text
);
2854 mono_runtime_printf ("\t<Stack traces in thread dumps not supported on this platform>");
2857 mono_runtime_printf ("%s", text
->str
);
2859 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
2860 OutputDebugStringA(text
->str
);
2863 g_string_free (text
, TRUE
);
2864 mono_runtime_stdout_fflush ();
2868 * mono_print_thread_dump:
2870 * Print information about the current thread to stdout.
2871 * \p sigctx can be NULL, allowing this to be called from gdb.
2874 mono_print_thread_dump (void *sigctx
)
2876 mono_print_thread_dump_internal (sigctx
, NULL
);
2880 mono_print_thread_dump_from_ctx (MonoContext
*ctx
)
2882 mono_print_thread_dump_internal (NULL
, ctx
);
2886 * mono_resume_unwind:
2888 * This is called by a trampoline from LLVM compiled finally clauses to continue
2892 mono_resume_unwind (MonoContext
*ctx
)
2894 MONO_REQ_GC_UNSAFE_MODE
;
2896 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
2897 MonoContext new_ctx
;
2899 MONO_CONTEXT_SET_IP (ctx
, MONO_CONTEXT_GET_IP (&jit_tls
->resume_state
.ctx
));
2900 MONO_CONTEXT_SET_SP (ctx
, MONO_CONTEXT_GET_SP (&jit_tls
->resume_state
.ctx
));
2903 mono_handle_exception_internal (&new_ctx
, (MonoObject
*)jit_tls
->resume_state
.ex_obj
, TRUE
, NULL
);
2905 mono_restore_context (&new_ctx
);
2911 MonoJitExceptionInfo
*ei
;
2912 } FindHandlerBlockData
;
2915 find_last_handler_block (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
2919 FindHandlerBlockData
*pdata
= (FindHandlerBlockData
*)data
;
2920 MonoJitInfo
*ji
= frame
->ji
;
2925 ip
= MONO_CONTEXT_GET_IP (ctx
);
2927 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
2928 MonoJitExceptionInfo
*ei
= ji
->clauses
+ i
;
2929 if (ei
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
2931 /*If ip points to the first instruction it means the handler block didn't start
2932 so we can leave its execution to the EH machinery*/
2933 if (ei
->handler_start
<= ip
&& ip
< ei
->data
.handler_end
) {
2945 install_handler_block_guard (MonoJitInfo
*ji
, MonoContext
*ctx
)
2948 MonoJitExceptionInfo
*clause
= NULL
;
2952 ip
= MONO_CONTEXT_GET_IP (ctx
);
2954 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
2955 clause
= &ji
->clauses
[i
];
2956 if (clause
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
2958 if (clause
->handler_start
<= ip
&& clause
->data
.handler_end
> ip
)
2962 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
2963 g_assert (i
< ji
->num_clauses
);
2966 bp
= (guint8
*)MONO_CONTEXT_GET_BP (ctx
);
2967 *(bp
+ clause
->exvar_offset
) = 1;
2971 * Finds the bottom handler block running and install a block guard if needed.
2974 mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
)
2976 FindHandlerBlockData data
= { 0 };
2977 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
];
2979 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
2980 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
2982 if (!jit_tls
|| jit_tls
->handler_block
)
2985 /* Do an async safe stack walk */
2986 mono_thread_info_set_is_async_context (TRUE
);
2987 mono_walk_stack_with_state (find_last_handler_block
, ctx
, MONO_UNWIND_NONE
, &data
);
2988 mono_thread_info_set_is_async_context (FALSE
);
2993 memcpy (&jit_tls
->handler_block_context
, &data
.ctx
, sizeof (MonoContext
));
2995 install_handler_block_guard (data
.ji
, &data
.ctx
);
2997 jit_tls
->handler_block
= data
.ei
;
3003 mono_uninstall_current_handler_block_guard (void)
3005 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
3007 jit_tls
->handler_block
= NULL
;
3012 mono_current_thread_has_handle_block_guard (void)
3014 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
3015 return jit_tls
&& jit_tls
->handler_block
!= NULL
;
3019 mono_set_cast_details (MonoClass
*from
, MonoClass
*to
)
3021 MonoJitTlsData
*jit_tls
= NULL
;
3023 if (mini_get_debug_options ()->better_cast_details
) {
3024 jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
3025 jit_tls
->class_cast_from
= from
;
3026 jit_tls
->class_cast_to
= to
;
3031 /*returns false if the thread is not attached*/
3033 mono_thread_state_init_from_sigctx (MonoThreadUnwindState
*ctx
, void *sigctx
)
3035 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3036 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3043 mono_sigctx_to_monoctx (sigctx
, &ctx
->ctx
);
3045 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3046 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3047 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3050 mono_thread_state_init (ctx
);
3053 if (!ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] || !ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
])
3059 g_error ("Implement mono_arch_sigctx_to_monoctx for the current target");
3065 mono_thread_state_init (MonoThreadUnwindState
*ctx
)
3067 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3069 #if defined(MONO_CROSS_COMPILE)
3070 ctx
->valid
= FALSE
; //A cross compiler doesn't need to suspend.
3071 #elif MONO_ARCH_HAS_MONO_CONTEXT
3072 MONO_CONTEXT_GET_CURRENT (ctx
->ctx
);
3074 g_error ("Use a null sigctx requires a working mono-context");
3077 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3078 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3079 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
? thread
->jit_data
: NULL
;
3085 mono_thread_state_init_from_monoctx (MonoThreadUnwindState
*ctx
, MonoContext
*mctx
)
3087 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3094 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3095 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3096 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3101 /*returns false if the thread is not attached*/
3103 mono_thread_state_init_from_current (MonoThreadUnwindState
*ctx
)
3105 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3106 MONO_ARCH_CONTEXT_DEF
3108 mono_arch_flush_register_windows ();
3110 if (!thread
|| !thread
->jit_data
) {
3114 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
3115 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
->ctx
);
3117 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
->ctx
, mono_thread_state_init_from_current
);
3120 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3121 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3122 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3128 mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
)
3130 mono_handle_exception (ctx
, (MonoObject
*)exc
);
3131 mono_restore_context (ctx
);
3134 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3136 mono_setup_async_callback (MonoContext
*ctx
, void (*async_cb
)(void *fun
), gpointer user_data
)
3138 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3139 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_tls_get_jit_tls ();
3140 jit_tls
->ex_ctx
= *ctx
;
3142 mono_arch_setup_async_callback (ctx
, async_cb
, user_data
);
3144 g_error ("This target doesn't support mono_arch_setup_async_callback");
3149 * mono_restore_context:
3151 * Call the architecture specific restore context function.
3154 mono_restore_context (MonoContext
*ctx
)
3156 static void (*restore_context
) (MonoContext
*);
3158 if (!restore_context
)
3159 restore_context
= (void (*)(MonoContext
*))mono_get_restore_context ();
3160 restore_context (ctx
);
3161 g_assert_not_reached ();
3165 * mono_jinfo_get_unwind_info:
3167 * Return the unwind info for JI.
3170 mono_jinfo_get_unwind_info (MonoJitInfo
*ji
, guint32
*unwind_info_len
)
3172 if (ji
->has_unwind_info
) {
3173 /* The address/length in the MonoJitInfo structure itself */
3174 MonoUnwindJitInfo
*info
= mono_jit_info_get_unwind_info (ji
);
3175 *unwind_info_len
= info
->unw_info_len
;
3176 return info
->unw_info
;
3177 } else if (ji
->from_aot
)
3178 return mono_aot_get_unwind_info (ji
, unwind_info_len
);
3180 return mono_get_cached_unwind_info (ji
->unwind_info
, unwind_info_len
);
3184 mono_jinfo_get_epilog_size (MonoJitInfo
*ji
)
3186 MonoArchEHJitInfo
*info
;
3188 info
= mono_jit_info_get_arch_eh_info (ji
);
3191 return info
->epilog_size
;
3195 * LLVM/Bitcode exception handling.
3199 throw_exception (MonoObject
*ex
, gboolean rethrow
)
3201 MONO_REQ_GC_UNSAFE_MODE
;
3204 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3205 MonoException
*mono_ex
;
3207 if (!mono_object_isinst_checked (ex
, mono_defaults
.exception_class
, error
)) {
3208 mono_error_assert_ok (error
);
3209 mono_ex
= mono_get_exception_runtime_wrapped_checked (ex
, error
);
3210 mono_error_assert_ok (error
);
3211 jit_tls
->thrown_non_exc
= mono_gchandle_new (ex
, FALSE
);
3214 mono_ex
= (MonoException
*)ex
;
3217 jit_tls
->thrown_exc
= mono_gchandle_new ((MonoObject
*)mono_ex
, FALSE
);
3220 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3221 GList
*l
, *ips
= NULL
;
3224 _Unwind_Backtrace (build_stack_trace
, &ips
);
3225 /* The list contains ip-gshared info pairs */
3227 ips
= g_list_reverse (ips
);
3228 for (l
= ips
; l
; l
= l
->next
) {
3229 trace
= g_list_append (trace
, l
->data
);
3230 trace
= g_list_append (trace
, NULL
);
3231 trace
= g_list_append (trace
, NULL
);
3233 MonoArray
*ips_arr
= mono_glist_to_array (trace
, mono_defaults
.int_class
, error
);
3234 mono_error_assert_ok (error
);
3235 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, ips_arr
);
3237 g_list_free (trace
);
3241 mono_llvm_cpp_throw_exception ();
3245 mono_llvm_throw_exception (MonoObject
*ex
)
3247 throw_exception (ex
, FALSE
);
3251 mono_llvm_rethrow_exception (MonoObject
*ex
)
3253 throw_exception (ex
, TRUE
);
3257 mono_llvm_raise_exception (MonoException
*e
)
3259 mono_llvm_throw_exception ((MonoObject
*)e
);
3263 mono_llvm_reraise_exception (MonoException
*e
)
3265 mono_llvm_rethrow_exception ((MonoObject
*)e
);
3269 mono_llvm_throw_corlib_exception (guint32 ex_token_index
)
3271 guint32 ex_token
= MONO_TOKEN_TYPE_DEF
| ex_token_index
;
3274 ex
= mono_exception_from_token (m_class_get_image (mono_defaults
.exception_class
), ex_token
);
3276 mono_llvm_throw_exception ((MonoObject
*)ex
);
3280 * mono_llvm_resume_exception:
3282 * Resume exception propagation.
3285 mono_llvm_resume_exception (void)
3287 mono_llvm_cpp_throw_exception ();
3291 * mono_llvm_load_exception:
3293 * Return the currently thrown exception.
3296 mono_llvm_load_exception (void)
3299 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3301 MonoException
*mono_ex
= (MonoException
*)mono_gchandle_get_target (jit_tls
->thrown_exc
);
3303 if (mono_ex
->trace_ips
) {
3304 GList
*trace_ips
= NULL
;
3305 gpointer ip
= MONO_RETURN_ADDRESS ();
3307 size_t upper
= mono_array_length (mono_ex
->trace_ips
);
3309 for (int i
= 0; i
< upper
; i
+= TRACE_IP_ENTRY_SIZE
) {
3310 gpointer curr_ip
= mono_array_get (mono_ex
->trace_ips
, gpointer
, i
);
3311 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
3312 gpointer p
= mono_array_get (mono_ex
->trace_ips
, gpointer
, i
+ j
);
3313 trace_ips
= g_list_append (trace_ips
, p
);
3319 // FIXME: Does this work correctly for rethrows?
3320 // We may be discarding useful information
3321 // when this gets GC'ed
3322 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips
, mono_defaults
.int_class
, error
);
3323 mono_error_assert_ok (error
);
3324 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, ips_arr
);
3325 g_list_free (trace_ips
);
3328 //MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3330 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, 0, error
));
3331 mono_error_assert_ok (error
);
3332 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, mono_array_new_checked (mono_domain_get (), mono_defaults
.stack_frame_class
, 0, error
));
3333 mono_error_assert_ok (error
);
3336 return &mono_ex
->object
;
3340 * mono_llvm_clear_exception:
3342 * Mark the currently thrown exception as handled.
3345 mono_llvm_clear_exception (void)
3347 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3348 mono_gchandle_free (jit_tls
->thrown_exc
);
3349 jit_tls
->thrown_exc
= 0;
3350 if (jit_tls
->thrown_non_exc
)
3351 mono_gchandle_free (jit_tls
->thrown_non_exc
);
3352 jit_tls
->thrown_non_exc
= 0;
3354 mono_memory_barrier ();
3358 * mono_llvm_match_exception:
3360 * Return the innermost clause containing REGION_START-REGION_END which can handle
3361 * the current exception.
3364 mono_llvm_match_exception (MonoJitInfo
*jinfo
, guint32 region_start
, guint32 region_end
, gpointer rgctx
, MonoObject
*this_obj
)
3367 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3371 g_assert (jit_tls
->thrown_exc
);
3372 exc
= mono_gchandle_get_target (jit_tls
->thrown_exc
);
3373 if (jit_tls
->thrown_non_exc
) {
3375 * Have to unwrap RuntimeWrappedExceptions if the
3376 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
3378 if (!wrap_non_exception_throws (jinfo_get_method (jinfo
)))
3379 exc
= mono_gchandle_get_target (jit_tls
->thrown_non_exc
);
3382 for (int i
= 0; i
< jinfo
->num_clauses
; i
++) {
3383 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
3384 MonoClass
*catch_class
;
3386 if (! (ei
->try_offset
== region_start
&& ei
->try_offset
+ ei
->try_len
== region_end
) )
3389 catch_class
= ei
->data
.catch_class
;
3390 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class
))) {
3391 MonoGenericContext context
;
3392 MonoType
*inflated_type
;
3394 g_assert (rgctx
|| this_obj
);
3395 context
= get_generic_context_from_stack_frame (jinfo
, rgctx
? rgctx
: this_obj
->vtable
);
3396 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
3397 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
3399 catch_class
= mono_class_from_mono_type (inflated_type
);
3400 mono_metadata_free_type (inflated_type
);
3403 // FIXME: Handle edge cases handled in get_exception_catch_class
3404 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (exc
, catch_class
, error
)) {
3405 index
= ei
->clause_index
;
3408 mono_error_assert_ok (error
);
3410 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
3411 g_assert_not_reached ();
3420 mono_debug_personality (int a
, _Unwind_Action b
,
3421 uint64_t c
, struct _Unwind_Exception
*d
, struct _Unwind_Context
*e
)
3423 g_assert_not_reached ();
3427 mono_debug_personality (void);
3430 mono_debug_personality (void)
3432 g_assert_not_reached ();