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.
20 #ifdef HAVE_EXECINFO_H
24 #ifdef HAVE_SYS_TYPES_H
25 #include <sys/types.h>
28 #ifdef HAVE_SYS_WAIT_H
36 #ifdef HAVE_SYS_SYSCALL_H
37 #include <sys/syscall.h>
40 #ifdef HAVE_SYS_PRCTL_H
41 #include <sys/prctl.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/tabledefs.h>
50 #include <mono/metadata/threads.h>
51 #include <mono/metadata/threads-types.h>
52 #include <mono/metadata/debug-helpers.h>
53 #include <mono/metadata/exception.h>
54 #include <mono/metadata/exception-internals.h>
55 #include <mono/metadata/object-internals.h>
56 #include <mono/metadata/reflection-internals.h>
57 #include <mono/metadata/gc-internals.h>
58 #include <mono/metadata/debug-internals.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/metadata/profiler-private.h>
61 #include <mono/metadata/mono-endian.h>
62 #include <mono/metadata/environment.h>
63 #include <mono/metadata/mono-mlist.h>
64 #include <mono/utils/mono-merp.h>
65 #include <mono/utils/mono-mmap.h>
66 #include <mono/utils/mono-logger-internals.h>
67 #include <mono/utils/mono-error.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/mono-state.h>
70 #include <mono/utils/mono-threads-debug.h>
74 #include "debugger-agent.h"
75 #include "seq-points.h"
76 #include "llvm-runtime.h"
77 #include "mini-llvm.h"
78 #include "aot-runtime.h"
79 #include "mini-runtime.h"
80 #include "interp/interp.h"
83 #include "mini-llvm-cpp.h"
90 #ifndef MONO_ARCH_CONTEXT_DEF
91 #define MONO_ARCH_CONTEXT_DEF
94 #if !defined(DISABLE_CRASH_REPORTING)
97 #include "mono/utils/mono-tls-inline.h"
100 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
101 * This structure represents one entry.
102 * This should consists of pointers only.
107 gpointer generic_info
;
108 /* Only for interpreter frames */
112 /* Number of words in trace_ips belonging to one entry */
113 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
115 static gpointer restore_context_func
, call_filter_func
;
116 static gpointer throw_exception_func
, rethrow_exception_func
, rethrow_preserve_exception_func
;
117 static gpointer throw_corlib_exception_func
;
119 static MonoFtnPtrEHCallback ftnptr_eh_callback
;
121 static void mono_walk_stack_full (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoLMF
*lmf
, MonoUnwindOptions unwind_options
, gpointer user_data
, gboolean crash_context
);
122 static void mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
);
123 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
);
124 static gboolean
mono_current_thread_has_handle_block_guard (void);
125 static gboolean
mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
);
126 static void mono_uninstall_current_handler_block_guard (void);
127 static gboolean
mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
);
128 static void throw_exception (MonoObject
*ex
, gboolean rethrow
);
130 static void mono_summarize_managed_stack (MonoThreadSummary
*out
);
131 static void mono_summarize_unmanaged_stack (MonoThreadSummary
*out
);
132 static void mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
);
133 static void mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
);
134 static void mono_crash_reporting_allow_all_native_libraries (void);
137 first_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer addr
)
139 gpointer
*data
= (gpointer
*)addr
;
145 // FIXME: Happens with llvm_only
150 *data
= frame
->frame_addr
;
156 mono_thread_get_managed_sp (void)
158 gpointer addr
= NULL
;
159 mono_walk_stack (first_managed
, MONO_UNWIND_SIGNAL_SAFE
, &addr
);
164 mini_clear_abort_threshold (void)
166 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
167 jit_tls
->abort_exc_stack_threshold
= NULL
;
171 mini_set_abort_threshold (StackFrameInfo
*frame
)
173 gpointer sp
= frame
->frame_addr
;
174 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
175 // Only move it up, to avoid thrown/caught
176 // exceptions lower in the stack from triggering
178 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
179 if (!jit_tls
->abort_exc_stack_threshold
|| above_threshold
) {
180 jit_tls
->abort_exc_stack_threshold
= sp
;
184 // Note: In the case that the frame is above where the thread abort
185 // was set we bump the threshold so that functions called from the new,
186 // higher threshold don't trigger the thread abort exception
188 mini_above_abort_threshold (void)
190 gpointer sp
= mono_thread_get_managed_sp ();
191 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
196 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
199 jit_tls
->abort_exc_stack_threshold
= sp
;
201 return above_threshold
;
205 mono_get_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
208 if (mono_find_prev_seq_point_for_native_offset (domain
, method
, native_offset
, NULL
, &sp
))
214 mono_exceptions_init (void)
216 MonoRuntimeExceptionHandlingCallbacks cbs
;
217 if (mono_ee_features
.use_aot_trampolines
) {
218 restore_context_func
= mono_aot_get_trampoline ("restore_context");
219 call_filter_func
= mono_aot_get_trampoline ("call_filter");
220 throw_exception_func
= mono_aot_get_trampoline ("throw_exception");
221 rethrow_exception_func
= mono_aot_get_trampoline ("rethrow_exception");
222 rethrow_preserve_exception_func
= mono_aot_get_trampoline ("rethrow_preserve_exception");
223 } else if (!mono_llvm_only
) {
226 restore_context_func
= mono_arch_get_restore_context (&info
, FALSE
);
227 mono_tramp_info_register (info
, NULL
);
228 call_filter_func
= mono_arch_get_call_filter (&info
, FALSE
);
229 mono_tramp_info_register (info
, NULL
);
230 throw_exception_func
= mono_arch_get_throw_exception (&info
, FALSE
);
231 mono_tramp_info_register (info
, NULL
);
232 rethrow_exception_func
= mono_arch_get_rethrow_exception (&info
, FALSE
);
233 mono_tramp_info_register (info
, NULL
);
234 rethrow_preserve_exception_func
= mono_arch_get_rethrow_preserve_exception (&info
, FALSE
);
235 mono_tramp_info_register (info
, NULL
);
238 mono_arch_exceptions_init ();
240 cbs
.mono_walk_stack_with_ctx
= mono_runtime_walk_stack_with_ctx
;
241 cbs
.mono_walk_stack_with_state
= mono_walk_stack_with_state
;
242 cbs
.mono_summarize_managed_stack
= mono_summarize_managed_stack
;
243 cbs
.mono_summarize_unmanaged_stack
= mono_summarize_unmanaged_stack
;
244 cbs
.mono_summarize_exception
= mono_summarize_exception
;
245 cbs
.mono_register_native_library
= mono_crash_reporting_register_native_library
;
246 cbs
.mono_allow_all_native_libraries
= mono_crash_reporting_allow_all_native_libraries
;
248 if (mono_llvm_only
) {
249 cbs
.mono_raise_exception
= mono_llvm_raise_exception
;
250 cbs
.mono_reraise_exception
= mono_llvm_reraise_exception
;
252 cbs
.mono_raise_exception
= (void (*)(MonoException
*))mono_get_throw_exception ();
253 cbs
.mono_reraise_exception
= (void (*)(MonoException
*))mono_get_rethrow_exception ();
255 cbs
.mono_raise_exception_with_ctx
= mono_raise_exception_with_ctx
;
256 cbs
.mono_exception_walk_trace
= mono_exception_walk_trace
;
257 cbs
.mono_install_handler_block_guard
= mono_install_handler_block_guard
;
258 cbs
.mono_uninstall_current_handler_block_guard
= mono_uninstall_current_handler_block_guard
;
259 cbs
.mono_current_thread_has_handle_block_guard
= mono_current_thread_has_handle_block_guard
;
260 cbs
.mono_clear_abort_threshold
= mini_clear_abort_threshold
;
261 cbs
.mono_above_abort_threshold
= mini_above_abort_threshold
;
262 mono_install_eh_callbacks (&cbs
);
263 mono_install_get_seq_point (mono_get_seq_point_for_native_offset
);
267 mono_get_throw_exception (void)
269 g_assert (throw_exception_func
);
270 return throw_exception_func
;
274 mono_get_rethrow_exception (void)
276 g_assert (rethrow_exception_func
);
277 return rethrow_exception_func
;
281 mono_get_rethrow_preserve_exception (void)
283 g_assert (rethrow_preserve_exception_func
);
284 return rethrow_preserve_exception_func
;
288 no_call_filter (void)
290 g_assert_not_reached ();
294 mono_get_call_filter (void)
296 /* This is called even in llvmonly mode etc. */
297 if (!call_filter_func
)
298 return (gpointer
)no_call_filter
;
299 return call_filter_func
;
303 mono_get_restore_context (void)
305 g_assert (restore_context_func
);
306 return restore_context_func
;
310 mono_get_throw_corlib_exception (void)
312 gpointer code
= NULL
;
315 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
316 if (throw_corlib_exception_func
)
317 return throw_corlib_exception_func
;
319 if (mono_ee_features
.use_aot_trampolines
)
320 code
= mono_aot_get_trampoline ("throw_corlib_exception");
322 code
= mono_arch_get_throw_corlib_exception (&info
, FALSE
);
323 mono_tramp_info_register (info
, NULL
);
326 mono_memory_barrier ();
328 throw_corlib_exception_func
= code
;
330 return throw_corlib_exception_func
;
334 * mono_get_throw_exception_addr:
336 * Return an address which stores the result of
337 * mono_get_throw_exception.
340 mono_get_throw_exception_addr (void)
342 return &throw_exception_func
;
346 mono_get_rethrow_preserve_exception_addr (void)
348 return &rethrow_preserve_exception_func
;
352 is_address_protected (MonoJitInfo
*ji
, MonoJitExceptionInfo
*ei
, gpointer ip
)
354 MonoTryBlockHoleTableJitInfo
*table
;
359 if (ei
->try_start
> ip
|| ip
>= ei
->try_end
)
362 if (!ji
->has_try_block_holes
)
365 table
= mono_jit_info_get_try_block_hole_table_info (ji
);
366 offset
= (guint32
)((char*)ip
- (char*)ji
->code_start
);
367 clause
= (guint16
)(ei
- ji
->clauses
);
368 g_assert (clause
< ji
->num_clauses
);
370 for (i
= 0; i
< table
->num_holes
; ++i
) {
371 MonoTryBlockHoleJitInfo
*hole
= &table
->holes
[i
];
372 if (hole
->clause
== clause
&& hole
->offset
<= offset
&& hole
->offset
+ hole
->length
> offset
)
378 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
381 static gboolean show_native_addresses
= TRUE
;
383 static gboolean show_native_addresses
= FALSE
;
386 static _Unwind_Reason_Code
387 build_stack_trace (struct _Unwind_Context
*frame_ctx
, void *state
)
389 MonoDomain
*domain
= mono_domain_get ();
390 uintptr_t ip
= _Unwind_GetIP (frame_ctx
);
392 if (show_native_addresses
|| mono_jit_info_table_find (domain
, (char*)ip
)) {
393 GList
**trace_ips
= (GList
**)state
;
394 *trace_ips
= g_list_prepend (*trace_ips
, (gpointer
)ip
);
397 return _URC_NO_REASON
;
401 get_unwind_backtrace (void)
405 _Unwind_Backtrace (build_stack_trace
, &ips
);
407 return g_slist_reverse (ips
);
413 get_unwind_backtrace (void)
421 arch_unwind_frame (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
422 MonoJitInfo
*ji
, MonoContext
*ctx
,
423 MonoContext
*new_ctx
, MonoLMF
**lmf
,
424 host_mgreg_t
**save_locations
,
425 StackFrameInfo
*frame
)
428 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
429 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
431 memset (frame
, 0, sizeof (StackFrameInfo
));
436 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
438 * This LMF entry is created by the soft debug code to mark transitions to
439 * managed code done during invokes.
441 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
442 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
443 } else if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT
|| ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
444 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED
;
445 frame
->interp_exit_data
= ext
->interp_exit_data
;
446 if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
447 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
448 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
451 g_assert_not_reached ();
454 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~3);
460 return mono_arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
466 * Translate between the mono_arch_unwind_frame function and the old API.
469 find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
470 MonoContext
*new_ctx
, MonoLMF
**lmf
, gboolean
*managed
)
472 StackFrameInfo frame
;
475 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
477 /* Avoid costly table lookup during stack overflow */
478 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
481 ji
= mini_jit_info_table_find (domain
, ip
, NULL
);
486 err
= arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, NULL
, &frame
);
488 return (MonoJitInfo
*)-1;
490 if (*lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
492 * Remove any unused lmf.
493 * Mask out the lower bits which might be used to hold additional information.
495 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
498 /* Convert between the new and the old APIs */
499 switch (frame
.type
) {
500 case FRAME_TYPE_MANAGED
:
504 case FRAME_TYPE_TRAMPOLINE
:
506 case FRAME_TYPE_MANAGED_TO_NATIVE
:
510 memset (res
, 0, sizeof (MonoJitInfo
));
511 res
->d
.method
= frame
.method
;
514 case FRAME_TYPE_DEBUGGER_INVOKE
: {
518 * The normal exception handling code can't handle this frame, so just
521 ji
= find_jit_info (domain
, jit_tls
, res
, NULL
, new_ctx
, &tmp_ctx
, lmf
, managed
);
522 memcpy (new_ctx
, &tmp_ctx
, sizeof (MonoContext
));
526 g_assert_not_reached ();
531 /* mono_find_jit_info:
533 * This function is used to gather information from @ctx. It return the
534 * MonoJitInfo of the corresponding function, unwinds one stack frame and
535 * stores the resulting context into @new_ctx. It also stores a string
536 * describing the stack location into @trace (if not NULL), and modifies
537 * the @lmf if necessary. @native_offset return the IP offset from the
538 * start of the function or -1 if that info is not available.
541 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
542 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
546 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
548 MonoMethod
*method
= NULL
;
559 ji
= find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
561 if (ji
== (gpointer
)-1)
564 if (ji
&& !ji
->is_trampoline
)
565 method
= jinfo_get_method (ji
);
567 if (managed2
|| (method
&& method
->wrapper_type
)) {
568 const char *real_ip
, *start
;
571 start
= (const char *)ji
->code_start
;
573 /* ctx->ip points into native code */
574 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
576 real_ip
= (const char*)ip
;
578 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
579 offset
= real_ip
- start
;
584 *native_offset
= offset
;
587 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
591 *trace
= mono_debug_print_stack_frame (method
, offset
, domain
);
594 char *fname
= mono_method_full_name (jinfo_get_method (res
), TRUE
);
595 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
604 * mono_find_jit_info_ext:
606 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
608 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
609 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
610 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
611 * to obtain the last managed frame.
612 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
613 * On return, it will be filled with the locations where callee saved registers are saved
614 * by the current frame. This is returned outside of StackFrameInfo because it can be
615 * quite large on some platforms.
616 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
620 mono_find_jit_info_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
621 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
622 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
623 host_mgreg_t
**save_locations
,
624 StackFrameInfo
*frame
)
627 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
629 MonoDomain
*target_domain
= domain
;
630 MonoMethod
*method
= NULL
;
631 gboolean async
= mono_thread_info_is_async_context ();
636 /* Avoid costly table lookup during stack overflow */
637 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
640 ji
= mini_jit_info_table_find_ext (domain
, ip
, TRUE
, &target_domain
);
643 target_domain
= domain
;
646 memset (save_locations
, 0, MONO_MAX_IREGS
* sizeof (host_mgreg_t
*));
648 err
= arch_unwind_frame (target_domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
652 gboolean not_i2m
= frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED
&& frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
654 if (not_i2m
&& *lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
656 * Remove any unused lmf.
657 * Mask out the lower bits which might be used to hold additional information.
659 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
662 if (frame
->ji
&& !frame
->ji
->is_trampoline
&& !frame
->ji
->async
)
663 method
= jinfo_get_method (frame
->ji
);
665 if (frame
->type
== FRAME_TYPE_MANAGED
&& method
) {
666 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
667 frame
->managed
= TRUE
;
670 if (frame
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
) {
672 * This type of frame is just a marker, the caller should unwind once more to get the
673 * last managed frame.
676 frame
->method
= NULL
;
679 frame
->native_offset
= -1;
680 frame
->domain
= target_domain
;
681 frame
->async_context
= async
;
682 frame
->frame_addr
= MONO_CONTEXT_GET_SP (ctx
);
686 if (frame
->type
== FRAME_TYPE_MANAGED
)
687 frame
->method
= method
;
689 if (ji
&& (frame
->managed
|| (method
&& method
->wrapper_type
))) {
690 const char *real_ip
, *start
;
692 start
= (const char *)ji
->code_start
;
693 if (frame
->type
== FRAME_TYPE_MANAGED
)
694 real_ip
= (const char*)ip
;
696 /* ctx->ip points into native code */
697 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
699 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
700 frame
->native_offset
= real_ip
- start
;
702 frame
->native_offset
= -1;
706 *trace
= mono_debug_print_stack_frame (method
, frame
->native_offset
, domain
);
708 if (trace
&& frame
->method
) {
709 char *fname
= mono_method_full_name (frame
->method
, TRUE
);
710 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
720 MonoInterpStackIter interp_iter
;
721 gpointer last_frame_addr
;
725 unwinder_init (Unwinder
*unwinder
)
727 memset (unwinder
, 0, sizeof (Unwinder
));
730 #if defined(__GNUC__) && defined(TARGET_ARM64)
731 /* gcc 4.9.2 seems to miscompile this on arm64 */
732 static __attribute__((optimize("O0"))) gboolean
736 unwinder_unwind_frame (Unwinder
*unwinder
,
737 MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
738 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
739 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
740 host_mgreg_t
**save_locations
,
741 StackFrameInfo
*frame
)
744 if (unwinder
->in_interp
) {
745 memcpy (new_ctx
, ctx
, sizeof (MonoContext
));
747 /* Process debugger invokes */
748 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
749 if (unwinder
->last_frame_addr
< (gpointer
)(*lmf
)) {
750 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
751 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
752 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
753 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~7);
754 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
760 unwinder
->in_interp
= mini_get_interp_callbacks ()->frame_iter_next (&unwinder
->interp_iter
, frame
);
761 if (frame
->type
== FRAME_TYPE_INTERP
) {
762 parent
= mini_get_interp_callbacks ()->frame_get_parent (frame
->interp_frame
);
763 unwinder
->last_frame_addr
= parent
;
765 if (!unwinder
->in_interp
)
766 return unwinder_unwind_frame (unwinder
, domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
, save_locations
, frame
);
769 gboolean res
= mono_find_jit_info_ext (domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
,
770 save_locations
, frame
);
773 if (frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
) {
774 unwinder
->in_interp
= TRUE
;
775 mini_get_interp_callbacks ()->frame_iter_init (&unwinder
->interp_iter
, frame
->interp_exit_data
);
777 unwinder
->last_frame_addr
= frame
->frame_addr
;
783 * This function is async-safe.
786 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
788 MonoGenericJitInfo
*gi
;
792 if (!ji
->has_generic_jit_info
)
794 gi
= mono_jit_info_get_generic_jit_info (ji
);
800 * Search location list if available, it contains the precise location of the
801 * argument for every pc offset, even if the method was interrupted while it was in
805 int offset
= (gsize
)MONO_CONTEXT_GET_IP (ctx
) - (gsize
)ji
->code_start
;
808 for (i
= 0; i
< gi
->nlocs
; ++i
) {
809 MonoDwarfLocListEntry
*entry
= &gi
->locations
[i
];
811 if (offset
>= entry
->from
&& (offset
< entry
->to
|| entry
->to
== 0)) {
813 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, entry
->reg
);
815 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, entry
->reg
) + entry
->offset
);
819 g_assert (i
< gi
->nlocs
);
822 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
824 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
828 method
= jinfo_get_method (ji
);
829 if (mono_method_get_context (method
)->method_inst
) {
830 /* A MonoMethodRuntimeGenericContext* */
832 } else if ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) || m_class_is_valuetype (method
->klass
)) {
836 /* Avoid returning a managed object */
837 MonoObject
*this_obj
= (MonoObject
*)info
;
839 return this_obj
->vtable
;
844 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
846 static MonoGenericContext
847 get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
849 MonoGenericContext context
= { NULL
, NULL
};
850 MonoClass
*klass
, *method_container_class
;
853 g_assert (generic_info
);
855 method
= jinfo_get_method (ji
);
856 g_assert (method
->is_inflated
);
857 if (mono_method_get_context (method
)->method_inst
) {
858 MonoMethodRuntimeGenericContext
*mrgctx
= (MonoMethodRuntimeGenericContext
*)generic_info
;
860 klass
= mrgctx
->class_vtable
->klass
;
861 context
.method_inst
= mrgctx
->method_inst
;
862 g_assert (context
.method_inst
);
864 MonoVTable
*vtable
= (MonoVTable
*)generic_info
;
866 klass
= vtable
->klass
;
869 //g_assert (!mono_class_is_gtd (method->klass));
870 if (mono_class_is_ginst (method
->klass
))
871 method_container_class
= mono_class_get_generic_class (method
->klass
)->container_class
;
873 method_container_class
= method
->klass
;
875 /* class might refer to a subclass of method's class */
876 while (!(klass
== method
->klass
|| (mono_class_is_ginst (klass
) && mono_class_get_generic_class (klass
)->container_class
== method_container_class
))) {
877 klass
= m_class_get_parent (klass
);
881 if (mono_class_is_ginst (klass
) || mono_class_is_gtd (klass
))
882 context
.class_inst
= mini_class_get_context (klass
)->class_inst
;
884 if (mono_class_is_ginst (klass
))
885 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass
)->container_class
, method_container_class
));
887 g_assert (mono_class_has_parent_and_ignore_generics (klass
, method_container_class
));
893 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
896 MonoGenericContext context
;
899 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
900 return jinfo_get_method (ji
);
901 context
= get_generic_context_from_stack_frame (ji
, generic_info
);
903 method
= jinfo_get_method (ji
);
904 method
= mono_method_get_declaring_generic_method (method
);
905 method
= mono_class_inflate_generic_method_checked (method
, &context
, error
);
906 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
912 * mono_exception_walk_native_trace:
913 * \param ex The exception object whose frames should be walked
914 * \param func callback to call for each stack frame
915 * \param user_data data passed to the callback
916 * This function walks the stacktrace of an exception. For
917 * each frame the callback function is called with the relevant info.
918 * The walk ends when no more stack frames are found or when the callback
919 * returns a TRUE value.
923 mono_exception_walk_trace (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
927 MONO_ENTER_GC_UNSAFE
;
928 res
= mono_exception_walk_trace_internal (ex
, func
, user_data
);
934 mono_exception_stackframe_obj_walk (MonoStackFrame
*captured_frame
, MonoExceptionFrameWalk func
, gpointer user_data
)
939 gpointer ip
= (gpointer
) (captured_frame
->method_address
+ captured_frame
->native_offset
);
940 MonoJitInfo
*ji
= mono_jit_info_table_find_internal (mono_domain_get (), ip
, TRUE
, TRUE
);
942 // Other domain maybe?
945 MonoMethod
*method
= jinfo_get_method (ji
);
947 gboolean r
= func (method
, (gpointer
) captured_frame
->method_address
, captured_frame
->native_offset
, TRUE
, user_data
);
955 mono_exception_stacktrace_obj_walk (MonoStackTrace
*st
, MonoExceptionFrameWalk func
, gpointer user_data
)
957 int num_captured
= st
->captured_traces
? mono_array_length_internal (st
->captured_traces
) : 0;
958 for (int i
=0; i
< num_captured
; i
++) {
959 MonoStackTrace
*curr_trace
= mono_array_get_fast (st
->captured_traces
, MonoStackTrace
*, i
);
960 mono_exception_stacktrace_obj_walk (curr_trace
, func
, user_data
);
963 int num_frames
= st
->frames
? mono_array_length_internal (st
->frames
) : 0;
964 for (int frame
= 0; frame
< num_frames
; frame
++) {
965 gboolean r
= mono_exception_stackframe_obj_walk (mono_array_get_fast (st
->frames
, MonoStackFrame
*, frame
), func
, user_data
);
974 mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
976 MONO_REQ_GC_UNSAFE_MODE
;
978 MonoDomain
*domain
= mono_domain_get ();
979 MonoArray
*ta
= ex
->trace_ips
;
981 /* Exception is not thrown yet */
985 int len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
986 gboolean otherwise_has_traces
= len
> 0;
988 for (int i
= 0; i
< len
; i
++) {
989 ExceptionTraceIp trace_ip
;
991 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
992 gpointer ip
= trace_ip
.ip
;
993 gpointer generic_info
= trace_ip
.generic_info
;
995 MonoJitInfo
*ji
= NULL
;
999 ji
= mono_jit_info_table_find (domain
, ip
);
1005 r
= func (NULL
, ip
, 0, FALSE
, user_data
);
1010 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
1011 if (func (method
, ji
->code_start
, (char *) ip
- (char *) ji
->code_start
, TRUE
, user_data
))
1016 ta
= (MonoArray
*) ex
->captured_traces
;
1017 len
= ta
? mono_array_length_internal (ta
) : 0;
1018 gboolean captured_has_traces
= len
> 0;
1020 for (int i
= 0; i
< len
; i
++) {
1021 MonoStackTrace
*captured_trace
= mono_array_get_fast (ta
, MonoStackTrace
*, i
);
1022 if (!captured_trace
)
1025 mono_exception_stacktrace_obj_walk (captured_trace
, func
, user_data
);
1028 return captured_has_traces
|| otherwise_has_traces
;
1032 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
1035 MonoDomain
*domain
= mono_domain_get ();
1037 MonoArray
*ta
= exc
->trace_ips
;
1038 MonoDebugSourceLocation
*location
;
1042 /* Exception is not thrown yet */
1043 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, 0, error
);
1044 mono_error_set_pending_exception (error
);
1048 len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
1050 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0, error
);
1051 if (mono_error_set_pending_exception (error
))
1054 for (i
= skip
; i
< len
; i
++) {
1056 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
1057 if (!is_ok (error
)) {
1058 mono_error_set_pending_exception (error
);
1061 ExceptionTraceIp trace_ip
;
1062 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
1063 gpointer ip
= trace_ip
.ip
;
1064 gpointer generic_info
= trace_ip
.generic_info
;
1070 ji
= mono_jit_info_table_find (domain
, ip
);
1072 /* Unmanaged frame */
1073 mono_array_setref_internal (res
, i
, sf
);
1078 g_assert (ji
!= NULL
);
1080 if (mono_llvm_only
|| !generic_info
)
1081 /* Can't resolve actual method */
1082 method
= jinfo_get_method (ji
);
1084 method
= get_method_from_stack_frame (ji
, generic_info
);
1085 if (jinfo_get_method (ji
)->wrapper_type
) {
1089 s
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_REFLECTION
);
1090 MonoString
*name
= mono_string_new_checked (domain
, s
, error
);
1092 if (!is_ok (error
)) {
1093 mono_error_set_pending_exception (error
);
1096 MONO_OBJECT_SETREF_INTERNAL (sf
, internal_method_name
, name
);
1099 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
1100 if (!is_ok (error
)) {
1101 mono_error_set_pending_exception (error
);
1104 MONO_OBJECT_SETREF_INTERNAL (sf
, method
, rm
);
1107 sf
->method_index
= ji
->from_aot
? mono_aot_find_method_index (method
) : 0xffffff;
1108 sf
->method_address
= (gsize
) ji
->code_start
;
1109 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
1112 * mono_debug_lookup_source_location() returns both the file / line number information
1113 * and the IL offset. Note that computing the IL offset is already an expensive
1114 * operation, so we shouldn't call this method twice.
1116 location
= mono_debug_lookup_source_location (jinfo_get_method (ji
), sf
->native_offset
, domain
);
1118 sf
->il_offset
= location
->il_offset
;
1121 if (mono_find_prev_seq_point_for_native_offset (domain
, jinfo_get_method (ji
), sf
->native_offset
, NULL
, &sp
))
1122 sf
->il_offset
= sp
.il_offset
;
1127 if (need_file_info
) {
1128 if (location
&& location
->source_file
) {
1129 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1130 if (!is_ok (error
)) {
1131 mono_error_set_pending_exception (error
);
1134 MONO_OBJECT_SETREF_INTERNAL (sf
, filename
, filename
);
1135 sf
->line
= location
->row
;
1136 sf
->column
= location
->column
;
1138 sf
->line
= sf
->column
= 0;
1139 sf
->filename
= NULL
;
1143 mono_debug_free_source_location (location
);
1144 mono_array_setref_internal (res
, i
- skip
, sf
);
1151 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1154 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1155 if (jit_tls
&& jit_tls
->orig_ex_ctx_set
)
1156 start_ctx
= &jit_tls
->orig_ex_ctx
;
1158 mono_walk_stack_with_ctx (func
, start_ctx
, unwind_options
, user_data
);
1161 * mono_walk_stack_with_ctx:
1162 * Unwind the current thread starting at \p start_ctx.
1163 * If \p start_ctx is null, we capture the current context.
1166 mono_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1168 MonoContext extra_ctx
;
1169 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1170 MONO_ARCH_CONTEXT_DEF
1172 if (!thread
|| !thread
->jit_data
)
1176 mono_arch_flush_register_windows ();
1177 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx
, mono_walk_stack_with_ctx
);
1178 start_ctx
= &extra_ctx
;
1181 mono_walk_stack_full (func
, start_ctx
, mono_domain_get (), thread
->jit_data
, mono_get_lmf (), unwind_options
, user_data
, FALSE
);
1185 * mono_walk_stack_with_state:
1186 * Unwind a thread described by \p state.
1188 * State must be valid (state->valid == TRUE).
1190 * If you are using this function to unwind another thread, make sure it is suspended.
1192 * If \p state is null, we capture the current context.
1195 mono_walk_stack_with_state (MonoJitStackWalk func
, MonoThreadUnwindState
*state
, MonoUnwindOptions unwind_options
, void *user_data
)
1197 MonoThreadUnwindState extra_state
;
1199 g_assert (!mono_thread_info_is_async_context ());
1200 if (!mono_thread_state_init_from_current (&extra_state
))
1202 state
= &extra_state
;
1205 g_assert (state
->valid
);
1207 if (!state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
])
1211 mono_walk_stack_full (func
,
1213 (MonoDomain
*)state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
],
1214 (MonoJitTlsData
*)state
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
],
1215 (MonoLMF
*)state
->unwind_data
[MONO_UNWIND_DATA_LMF
],
1216 unwind_options
, user_data
, FALSE
);
1220 mono_walk_stack (MonoJitStackWalk func
, MonoUnwindOptions options
, void *user_data
)
1222 MonoThreadUnwindState state
;
1223 if (!mono_thread_state_init_from_current (&state
))
1225 mono_walk_stack_with_state (func
, &state
, options
, user_data
);
1229 * mono_walk_stack_full:
1230 * \param func callback to call for each stack frame
1231 * \param domain starting appdomain, can be NULL to use the current domain
1232 * \param unwind_options what extra information the unwinder should gather
1233 * \param start_ctx starting state of the stack walk, can be NULL.
1234 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1235 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1236 * \param user_data data passed to the callback
1237 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1238 * This function walks the stack of a thread, starting from the state
1239 * represented by \p start_ctx. For each frame the callback
1240 * function is called with the relevant info. The walk ends when no more
1241 * managed stack frames are found or when the callback returns a TRUE value.
1244 mono_walk_stack_full (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoLMF
*lmf
, MonoUnwindOptions unwind_options
, gpointer user_data
, gboolean crash_context
)
1247 MonoContext ctx
, new_ctx
;
1248 StackFrameInfo frame
;
1250 host_mgreg_t
*reg_locations
[MONO_MAX_IREGS
];
1251 host_mgreg_t
*new_reg_locations
[MONO_MAX_IREGS
];
1252 gboolean get_reg_locations
= unwind_options
& MONO_UNWIND_REG_LOCATIONS
;
1253 gboolean async
= mono_thread_info_is_async_context ();
1256 memset (&frame
, 0, sizeof (StackFrameInfo
));
1259 if (mono_llvm_only
) {
1265 ips
= get_unwind_backtrace ();
1266 for (l
= ips
; l
; l
= l
->next
) {
1267 guint8
*ip
= (guint8
*)l
->data
;
1268 memset (&frame
, 0, sizeof (StackFrameInfo
));
1269 frame
.ji
= mini_jit_info_table_find (domain
, ip
, &frame
.domain
);
1270 if (!frame
.ji
|| frame
.ji
->is_trampoline
)
1272 frame
.type
= FRAME_TYPE_MANAGED
;
1273 frame
.method
= jinfo_get_method (frame
.ji
);
1274 // FIXME: Cannot lookup the actual method
1275 frame
.actual_method
= frame
.method
;
1276 if (frame
.type
== FRAME_TYPE_MANAGED
) {
1277 if (!frame
.method
->wrapper_type
|| frame
.method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1278 frame
.managed
= TRUE
;
1280 frame
.native_offset
= ip
- (guint8
*)frame
.ji
->code_start
;
1281 frame
.il_offset
= -1;
1283 if (func (&frame
, NULL
, user_data
))
1292 g_warning ("start_ctx required for stack walk");
1297 g_warning ("domain required for stack walk");
1302 g_warning ("jit_tls required for stack walk");
1306 /*The LMF will be null if the target have no managed frames.*/
1307 /* g_assert (lmf); */
1308 if (async
&& (unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
)) {
1309 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1313 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
1314 memset (reg_locations
, 0, sizeof (reg_locations
));
1316 unwinder_init (&unwinder
);
1318 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
1320 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, get_reg_locations
? new_reg_locations
: NULL
, &frame
);
1324 if (frame
.type
== FRAME_TYPE_TRAMPOLINE
)
1327 if ((unwind_options
& MONO_UNWIND_LOOKUP_IL_OFFSET
) && frame
.ji
) {
1328 MonoDebugSourceLocation
*source
= NULL
;
1330 // Don't do this when we can be in a signal handler
1332 source
= mono_debug_lookup_source_location (jinfo_get_method (frame
.ji
), frame
.native_offset
, domain
);
1334 il_offset
= source
->il_offset
;
1336 MonoSeqPointInfo
*seq_points
= NULL
;
1338 // It's more reliable to look into the global cache if possible
1340 seq_points
= (MonoSeqPointInfo
*) frame
.ji
->seq_points
;
1342 seq_points
= mono_get_seq_points (domain
, jinfo_get_method (frame
.ji
));
1345 if (seq_points
&& mono_seq_point_find_prev_by_native_offset (seq_points
, frame
.native_offset
, &sp
))
1346 il_offset
= sp
.il_offset
;
1350 mono_debug_free_source_location (source
);
1354 frame
.il_offset
= il_offset
;
1356 if ((unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
) && frame
.ji
) {
1357 frame
.actual_method
= get_method_from_stack_frame (frame
.ji
, get_generic_info_from_stack_frame (frame
.ji
, &ctx
));
1359 frame
.actual_method
= frame
.method
;
1362 if (get_reg_locations
)
1363 frame
.reg_locations
= reg_locations
;
1365 if (func (&frame
, &ctx
, user_data
))
1369 if (get_reg_locations
) {
1370 for (int i
= 0; i
< MONO_MAX_IREGS
; ++i
)
1371 if (new_reg_locations
[i
])
1372 reg_locations
[i
] = new_reg_locations
[i
];
1379 #ifdef DISABLE_CRASH_REPORTING
1382 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1388 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1394 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1400 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1406 mono_crash_reporting_allow_all_native_libraries ()
1415 MonoFrameSummary
*frames
;
1418 MonoStackHash
*hashes
;
1420 } MonoSummarizeUserData
;
1423 copy_summary_string_safe (char *dest
, const char *src
)
1425 g_strlcpy (dest
, src
, MONO_MAX_SUMMARY_NAME_LEN
);
1429 fill_frame_managed_info (MonoFrameSummary
*frame
, MonoMethod
* method
)
1431 MonoImage
*image
= mono_class_get_image (method
->klass
);
1432 // Used for hashing, more stable across rebuilds than using GUID
1433 copy_summary_string_safe (frame
->str_descr
, image
->assembly_name
);
1435 frame
->managed_data
.guid
= image
->guid
;
1436 frame
->managed_data
.token
= method
->token
;
1437 frame
->managed_data
.filename
= image
->module_name
;
1439 MonoDotNetHeader
*header
= &image
->image_info
->cli_header
;
1440 frame
->managed_data
.image_size
= header
->nt
.pe_image_size
;
1441 frame
->managed_data
.time_date_stamp
= image
->time_date_stamp
;
1446 char *exported_name
;
1447 } MonoLibWhitelistEntry
;
1449 static GList
*native_library_whitelist
;
1450 static gboolean allow_all_native_libraries
= FALSE
;
1453 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1455 // Examples: libsystem_pthread.dylib -> "pthread"
1456 // Examples: libsystem_platform.dylib -> "platform"
1457 // Examples: mono-sgen -> "mono" from above line
1458 MonoLibWhitelistEntry
*entry
= g_new0 (MonoLibWhitelistEntry
, 1);
1459 entry
->suffix
= g_strdup (module_path
);
1460 entry
->exported_name
= g_strdup (module_name
);
1461 native_library_whitelist
= g_list_append (native_library_whitelist
, entry
);
1465 mono_crash_reporting_allow_all_native_libraries ()
1467 allow_all_native_libraries
= TRUE
;
1471 check_whitelisted_module (const char *in_name
, const char **out_module
)
1473 #ifndef MONO_PRIVATE_CRASHES
1476 if (g_str_has_suffix (in_name
, "mono-sgen")) {
1478 copy_summary_string_safe ((char *) *out_module
, "mono");
1481 if (allow_all_native_libraries
) {
1483 /* for a module name, use the basename of the full path in in_name */
1484 char *basename
= (char *) in_name
, *p
= (char *) in_name
;
1485 while (*p
!= '\0') {
1491 copy_summary_string_safe ((char *) *out_module
, basename
);
1493 copy_summary_string_safe ((char *) *out_module
, "unknown");
1499 for (GList
*cursor
= native_library_whitelist
; cursor
; cursor
= cursor
->next
) {
1500 MonoLibWhitelistEntry
*iter
= (MonoLibWhitelistEntry
*) cursor
->data
;
1501 if (!g_str_has_suffix (in_name
, iter
->suffix
))
1504 copy_summary_string_safe ((char *) *out_module
, iter
->exported_name
);
1513 mono_make_portable_ip (intptr_t in_ip
, intptr_t module_base
)
1515 // FIXME: Make generalize away from llvm tools?
1516 // So lldb starts the pointer base at 0x100000000
1517 // and expects to get pointers as (offset + constant)
1520 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1521 // *CoreSymbolicationDT.framework version: 63750*/
1522 intptr_t offset
= in_ip
- module_base
;
1523 intptr_t magic_value
= offset
+ 0x100000000;
1528 mono_get_portable_ip (intptr_t in_ip
, intptr_t *out_ip
, gint32
*out_offset
, const char **out_module
, char *out_name
)
1530 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1531 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1532 // non-recursive lock twice on this thread, and will deadlock.
1533 char sname
[256], fname
[256];
1534 void *saddr
= NULL
, *fbase
= NULL
;
1535 gboolean success
= g_module_address ((void*)in_ip
, fname
, 256, &fbase
, sname
, 256, &saddr
);
1539 if (!check_whitelisted_module (fname
, out_module
))
1542 *out_ip
= mono_make_portable_ip ((intptr_t) saddr
, (intptr_t) fbase
);
1543 *out_offset
= in_ip
- (intptr_t) saddr
;
1545 if (saddr
&& out_name
)
1546 copy_summary_string_safe (out_name
, sname
);
1551 summarize_offset_free_hash (guint64 accum
, MonoFrameSummary
*frame
)
1553 if (!frame
->is_managed
)
1556 // See: mono_ptrarray_hash
1557 guint64 hash_accum
= accum
;
1559 // The assembly and the method token, no offsets
1560 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1561 hash_accum
+= frame
->managed_data
.token
;
1567 summarize_offset_rich_hash (guint64 accum
, MonoFrameSummary
*frame
)
1569 // See: mono_ptrarray_hash
1570 guint64 hash_accum
= accum
;
1572 if (!frame
->is_managed
) {
1573 hash_accum
+= frame
->unmanaged_data
.ip
;
1575 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1576 hash_accum
+= frame
->managed_data
.token
;
1577 hash_accum
+= frame
->managed_data
.il_offset
;
1584 summarize_frame_internal (MonoMethod
*method
, gpointer ip
, size_t native_offset
, int il_offset
, gboolean managed
, gpointer user_data
)
1586 MonoSummarizeUserData
*ud
= (MonoSummarizeUserData
*) user_data
;
1588 gboolean valid_state
= ud
->num_frames
+ 1 < ud
->max_frames
;
1590 ud
->error
= "Exceeded the maximum number of frames";
1594 MonoFrameSummary
*dest
= &ud
->frames
[ud
->num_frames
];
1596 dest
->unmanaged_data
.ip
= (intptr_t) ip
;
1597 dest
->is_managed
= managed
;
1598 dest
->unmanaged_data
.module
[0] = '\0';
1600 if (!managed
&& method
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
&& method
->wrapper_type
< MONO_WRAPPER_NUM
) {
1601 dest
->is_managed
= FALSE
;
1602 dest
->unmanaged_data
.has_name
= TRUE
;
1603 copy_summary_string_safe (dest
->str_descr
, mono_wrapper_type_to_str (method
->wrapper_type
));
1606 #ifndef MONO_PRIVATE_CRASHES
1608 dest
->managed_data
.name
= (char *) method
->name
;
1613 ud
->error
= "Managed method frame, but no provided managed method";
1616 fill_frame_managed_info (dest
, method
);
1617 dest
->managed_data
.native_offset
= native_offset
;
1618 dest
->managed_data
.il_offset
= il_offset
;
1620 dest
->managed_data
.token
= -1;
1624 ud
->hashes
->offset_free_hash
= summarize_offset_free_hash (ud
->hashes
->offset_free_hash
, dest
);
1625 ud
->hashes
->offset_rich_hash
= summarize_offset_rich_hash (ud
->hashes
->offset_rich_hash
, dest
);
1627 // We return FALSE, so we're continuing walking
1628 // And we increment the pointer because we're done with this cell in the array
1634 summarize_frame_managed_walk (MonoMethod
*method
, gpointer ip
, size_t frame_native_offset
, gboolean managed
, gpointer user_data
)
1638 if (managed
&& method
) {
1639 MonoDebugSourceLocation
*location
= mono_debug_lookup_source_location (method
, frame_native_offset
, mono_domain_get ());
1641 il_offset
= location
->il_offset
;
1642 mono_debug_free_source_location (location
);
1646 intptr_t portable_ip
= 0;
1648 mono_get_portable_ip ((intptr_t) ip
, &portable_ip
, &offset
, NULL
, NULL
);
1650 return summarize_frame_internal (method
, (gpointer
) portable_ip
, frame_native_offset
, il_offset
, managed
, user_data
);
1655 summarize_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
1657 // Don't record trampolines between managed frames
1658 if (frame
->ji
&& frame
->ji
->is_trampoline
)
1661 if (frame
->ji
&& (frame
->ji
->is_trampoline
|| frame
->ji
->async
))
1662 return FALSE
; // Keep unwinding
1666 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx
), &ip
, &offset
, NULL
, NULL
);
1667 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1669 gboolean is_managed
= (frame
->type
== FRAME_TYPE_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP
);
1670 MonoMethod
*method
= NULL
;
1671 if (frame
&& frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
1672 method
= jinfo_get_method (frame
->ji
);
1675 method
= jinfo_get_method (frame
->ji
);
1677 return summarize_frame_internal (method
, (gpointer
) ip
, offset
, frame
->il_offset
, is_managed
, data
);
1681 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1683 memset (out
, 0, sizeof (MonoThreadSummary
));
1685 MonoException
*inner_exc
= exc
;
1688 for (exc_index
= 0; exc_index
< MONO_MAX_SUMMARY_EXCEPTIONS
; exc_index
++) {
1689 if (inner_exc
== NULL
)
1692 // Set up state to walk this MonoException's stack
1693 MonoSummarizeUserData data
;
1694 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1695 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1696 data
.num_frames
= 0;
1697 data
.frames
= out
->exceptions
[exc_index
].managed_frames
;
1699 // Accumulate all hashes from all exceptions in traveral order
1700 data
.hashes
= &out
->hashes
;
1702 mono_exception_walk_trace (inner_exc
, summarize_frame_managed_walk
, &data
);
1704 // Save per-MonoException info
1705 out
->exceptions
[exc_index
].managed_exc_type
= inner_exc
->object
.vtable
->klass
;
1706 out
->exceptions
[exc_index
].num_managed_frames
= data
.num_frames
;
1708 // Continue to traverse nesting of exceptions
1709 inner_exc
= (MonoException
*) inner_exc
->inner_ex
;
1712 out
->num_exceptions
= exc_index
;
1717 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1719 MonoSummarizeUserData data
;
1720 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1721 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1722 data
.num_frames
= 0;
1723 data
.frames
= out
->managed_frames
;
1724 data
.hashes
= &out
->hashes
;
1726 // FIXME: collect stack pointer for both and sort frames by SP
1727 // so people can see relative ordering of both managed and unmanaged frames.
1730 // Summarize managed stack
1732 mono_walk_stack_full (summarize_frame
, out
->ctx
, out
->domain
, out
->jit_tls
, out
->lmf
, MONO_UNWIND_LOOKUP_IL_OFFSET
, &data
, TRUE
);
1733 out
->num_managed_frames
= data
.num_frames
;
1735 if (data
.error
!= NULL
)
1736 out
->error_msg
= data
.error
;
1737 out
->is_managed
= (out
->num_managed_frames
!= 0);
1740 // Always runs on the dumped thread
1742 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1744 MONO_ARCH_CONTEXT_DEF
1746 // Summarize unmanaged stack
1748 #ifdef HAVE_BACKTRACE_SYMBOLS
1749 intptr_t frame_ips
[MONO_MAX_SUMMARY_FRAMES
];
1751 out
->num_unmanaged_frames
= backtrace ((void **)frame_ips
, MONO_MAX_SUMMARY_FRAMES
);
1753 for (int i
=0; i
< out
->num_unmanaged_frames
; ++i
) {
1754 intptr_t ip
= frame_ips
[i
];
1755 MonoFrameSummary
*frame
= &out
->unmanaged_frames
[i
];
1756 const char* module_buf
= frame
->unmanaged_data
.module
;
1757 int success
= mono_get_portable_ip (ip
, &frame
->unmanaged_data
.ip
, &frame
->unmanaged_data
.offset
, &module_buf
, (char *) frame
->str_descr
);
1759 /* attempt to look up any managed method at that ip */
1760 /* TODO: Trampolines - follow examples from mono_print_method_from_ip() */
1763 MonoDomain
*domain
= mono_domain_get ();
1764 MonoDomain
*target_domain
;
1765 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
1767 frame
->is_managed
= TRUE
;
1768 if (!ji
->async
&& !ji
->is_trampoline
) {
1769 MonoMethod
*method
= jinfo_get_method (ji
);
1770 fill_frame_managed_info (frame
, method
);
1771 #ifndef MONO_PRIVATE_CRASHES
1772 frame
->managed_data
.name
= method
->name
;
1777 if (!success
&& !ji
) {
1778 frame
->unmanaged_data
.ip
= ip
;
1782 if (out
->unmanaged_frames
[i
].str_descr
[0] != '\0')
1783 out
->unmanaged_frames
[i
].unmanaged_data
.has_name
= TRUE
;
1787 out
->lmf
= mono_get_lmf ();
1789 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1790 out
->info_addr
= (intptr_t) thread
;
1791 out
->jit_tls
= thread
->jit_data
;
1792 out
->domain
= mono_domain_get ();
1795 out
->ctx
= &out
->ctx_mem
;
1796 mono_arch_flush_register_windows ();
1797 MONO_INIT_CONTEXT_FROM_FUNC (out
->ctx
, mono_summarize_unmanaged_stack
);
1806 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
1807 MonoReflectionMethod
**method
,
1808 gint32
*iloffset
, gint32
*native_offset
,
1809 MonoString
**file
, gint32
*line
, gint32
*column
)
1812 MonoDomain
*domain
= mono_domain_get ();
1813 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1814 MonoLMF
*lmf
= mono_get_lmf ();
1815 MonoJitInfo
*ji
= NULL
;
1816 MonoContext ctx
, new_ctx
;
1817 MonoDebugSourceLocation
*location
;
1818 MonoMethod
*jmethod
= NULL
, *actual_method
;
1819 StackFrameInfo frame
;
1824 MONO_ARCH_CONTEXT_DEF
;
1826 g_assert (skip
>= 0);
1828 if (mono_llvm_only
) {
1830 MonoDomain
*frame_domain
;
1831 guint8
*frame_ip
= NULL
;
1833 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1835 ips
= get_unwind_backtrace ();
1836 for (l
= ips
; l
&& skip
>= 0; l
= l
->next
) {
1837 guint8
*ip
= (guint8
*)l
->data
;
1841 ji
= mini_jit_info_table_find (mono_domain_get (), ip
, &frame_domain
);
1842 if (!ji
|| ji
->is_trampoline
)
1845 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1846 jmethod
= jinfo_get_method (ji
);
1847 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1854 /* No way to resolve generic instances */
1855 actual_method
= jmethod
;
1856 *native_offset
= frame_ip
- (guint8
*)ji
->code_start
;
1858 mono_arch_flush_register_windows ();
1859 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
1861 unwinder_init (&unwinder
);
1866 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
1869 switch (frame
.type
) {
1870 case FRAME_TYPE_MANAGED_TO_NATIVE
:
1871 case FRAME_TYPE_DEBUGGER_INVOKE
:
1872 case FRAME_TYPE_TRAMPOLINE
:
1873 case FRAME_TYPE_INTERP_TO_MANAGED
:
1874 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
1876 case FRAME_TYPE_INTERP
:
1877 case FRAME_TYPE_MANAGED
:
1879 *native_offset
= frame
.native_offset
;
1881 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1882 jmethod
= jinfo_get_method (ji
);
1883 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1888 g_assert_not_reached ();
1890 } while (skip
>= 0);
1892 if (frame
.type
== FRAME_TYPE_INTERP
) {
1893 jmethod
= frame
.method
;
1894 actual_method
= frame
.actual_method
;
1896 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &ctx
));
1900 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, actual_method
, NULL
, error
);
1901 if (!is_ok (error
)) {
1902 mono_error_set_pending_exception (error
);
1905 mono_gc_wbarrier_generic_store_internal (method
, (MonoObject
*) rm
);
1907 if (il_offset
!= -1) {
1908 location
= mono_debug_lookup_source_location_by_il (jmethod
, il_offset
, domain
);
1910 location
= mono_debug_lookup_source_location (jmethod
, *native_offset
, domain
);
1913 *iloffset
= location
->il_offset
;
1917 if (need_file_info
) {
1919 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1920 if (!is_ok (error
)) {
1921 mono_error_set_pending_exception (error
);
1924 mono_gc_wbarrier_generic_store_internal (file
, (MonoObject
*)filename
);
1925 *line
= location
->row
;
1926 *column
= location
->column
;
1929 *line
= *column
= 0;
1933 mono_debug_free_source_location (location
);
1939 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
1942 MonoClass
*catch_class
= ei
->data
.catch_class
;
1943 MonoType
*inflated_type
;
1944 MonoGenericContext context
;
1946 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1947 if (!catch_class
|| ei
->flags
!= MONO_EXCEPTION_CLAUSE_NONE
)
1950 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
1952 context
= get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
1954 /* FIXME: we shouldn't inflate but instead put the
1955 type in the rgctx and fetch it from there. It
1956 might be a good idea to do this lazily, i.e. only
1957 when the exception is actually thrown, so as not to
1958 waste space for exception clauses which might never
1960 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
1961 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1963 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
1964 mono_metadata_free_type (inflated_type
);
1970 * mini_jit_info_table_find_ext:
1972 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1973 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1974 * OUT_DOMAIN if it is not NULL.
1977 mini_jit_info_table_find_ext (MonoDomain
*domain
, gpointer addr
, gboolean allow_trampolines
, MonoDomain
**out_domain
)
1980 MonoInternalThread
*t
= mono_thread_internal_current ();
1986 ji
= mono_jit_info_table_find_internal (domain
, addr
, TRUE
, allow_trampolines
);
1989 *out_domain
= domain
;
1993 /* maybe it is shared code, so we also search in the root domain */
1994 if (domain
!= mono_get_root_domain ()) {
1995 ji
= mono_jit_info_table_find_internal (mono_get_root_domain (), addr
, TRUE
, allow_trampolines
);
1998 *out_domain
= mono_get_root_domain ();
2006 refs
= (gpointer
*)((t
->appdomain_refs
) ? *(gpointer
*) t
->appdomain_refs
: NULL
);
2007 for (; refs
&& *refs
; refs
++) {
2008 if (*refs
!= domain
&& *refs
!= mono_get_root_domain ()) {
2009 ji
= mono_jit_info_table_find_internal ((MonoDomain
*) *refs
, addr
, TRUE
, allow_trampolines
);
2012 *out_domain
= (MonoDomain
*) *refs
;
2022 mini_jit_info_table_find (MonoDomain
*domain
, gpointer addr
, MonoDomain
**out_domain
)
2024 return mini_jit_info_table_find_ext (domain
, addr
, FALSE
, out_domain
);
2027 /* Class lazy loading functions */
2028 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr
, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
2031 * wrap_non_exception_throws:
2033 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
2034 * WrapNonExceptionThrows flag set.
2037 wrap_non_exception_throws (MonoMethod
*m
)
2040 MonoAssembly
*ass
= m_class_get_image (m
->klass
)->assembly
;
2041 MonoCustomAttrInfo
* attrs
;
2044 gboolean val
= FALSE
;
2046 if (m
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
2047 MonoDynamicMethod
*dm
= (MonoDynamicMethod
*)m
;
2052 if (ass
->wrap_non_exception_throws_inited
)
2053 return ass
->wrap_non_exception_throws
;
2055 klass
= mono_class_get_runtime_compat_attr_class ();
2057 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
2058 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2060 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
2061 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
2063 int num_named
, named_type
, name_len
;
2066 if (!attr
->ctor
|| attr
->ctor
->klass
!= klass
)
2068 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2069 p
= (const char*)attr
->data
;
2070 g_assert (read16 (p
) == 0x0001);
2072 num_named
= read16 (p
);
2078 /* data_type = *p; */
2081 if (named_type
!= 0x54)
2083 name_len
= mono_metadata_decode_blob_size (p
, &p
);
2084 name
= (char *)g_malloc (name_len
+ 1);
2085 memcpy (name
, p
, name_len
);
2086 name
[name_len
] = 0;
2088 g_assert (!strcmp (name
, "WrapNonExceptionThrows"));
2090 /* The value is a BOOLEAN */
2093 mono_custom_attrs_free (attrs
);
2096 ass
->wrap_non_exception_throws
= val
;
2097 mono_memory_barrier ();
2098 ass
->wrap_non_exception_throws_inited
= TRUE
;
2103 #define MAX_UNMANAGED_BACKTRACE 128
2105 build_native_trace (MonoError
*error
)
2108 /* This puppy only makes sense on mobile, IOW, ARM. */
2109 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2111 void *native_trace
[MAX_UNMANAGED_BACKTRACE
];
2114 size
= backtrace (native_trace
, MAX_UNMANAGED_BACKTRACE
);
2120 res
= mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, size
, error
);
2121 return_val_if_nok (error
, NULL
);
2123 for (i
= 0; i
< size
; i
++)
2124 mono_array_set_internal (res
, gpointer
, i
, native_trace
[i
]);
2132 remove_wrappers_from_trace (GList
**trace_ips_p
)
2134 GList
*trace_ips
= *trace_ips_p
;
2135 GList
*p
= trace_ips
;
2137 /* jit info, generic info, ip */
2139 MonoJitInfo
*jinfo
= (MonoJitInfo
*) p
->data
;
2140 GList
*next_p
= p
->next
->next
->next
;
2141 /* FIXME Maybe remove more wrapper types */
2142 if (jinfo
->d
.method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2143 trace_ips
= g_list_delete_link (trace_ips
, p
->next
->next
);
2144 trace_ips
= g_list_delete_link (trace_ips
, p
->next
);
2145 trace_ips
= g_list_delete_link (trace_ips
, p
);
2150 *trace_ips_p
= trace_ips
;
2153 /* This can be called more than once on a MonoException. */
2155 setup_stack_trace (MonoException
*mono_ex
, GSList
**dynamic_methods
, GList
*trace_ips
, gboolean remove_wrappers
)
2158 GList
*trace_ips_copy
= g_list_copy (trace_ips
);
2159 if (remove_wrappers
)
2160 remove_wrappers_from_trace (&trace_ips_copy
);
2161 trace_ips_copy
= g_list_reverse (trace_ips_copy
);
2163 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips_copy
, mono_defaults
.int_class
, error
);
2164 mono_error_assert_ok (error
);
2165 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
2166 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, native_trace_ips
, build_native_trace (error
));
2167 mono_error_assert_ok (error
);
2168 if (*dynamic_methods
) {
2169 /* These methods could go away anytime, so save a reference to them in the exception object */
2171 MonoMList
*list
= (MonoMList
*)mono_ex
->dynamic_methods
;
2173 for (l
= *dynamic_methods
; l
; l
= l
->next
) {
2175 MonoDomain
*domain
= mono_domain_get ();
2177 if (domain
->method_to_dyn_method
) {
2178 mono_domain_lock (domain
);
2179 dis_link
= (guint32
)(size_t)g_hash_table_lookup (domain
->method_to_dyn_method
, l
->data
);
2180 mono_domain_unlock (domain
);
2182 MonoObject
*o
= mono_gchandle_get_target_internal (dis_link
);
2184 list
= mono_mlist_prepend_checked (list
, o
, error
);
2185 mono_error_assert_ok (error
);
2191 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, dynamic_methods
, list
);
2193 g_slist_free (*dynamic_methods
);
2194 *dynamic_methods
= NULL
;
2197 g_list_free (trace_ips_copy
);
2202 MONO_FIRST_PASS_UNHANDLED
,
2203 MONO_FIRST_PASS_CALLBACK_TO_NATIVE
,
2204 MONO_FIRST_PASS_HANDLED
,
2205 } MonoFirstPassResult
;
2208 * handle_exception_first_pass:
2210 * The first pass of exception handling. Unwind the stack until a catch
2211 * clause which can catch OBJ is found. Store the index of the filter clause
2212 * which caught the exception into OUT_FILTER_IDX. Return
2213 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2214 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2215 * wrapper and an exception handling callback is installed (in which case
2216 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2218 static MonoFirstPassResult
2219 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
, gboolean
*last_mono_wrapper_runtime_invoke
)
2222 MonoDomain
*domain
= mono_domain_get ();
2223 MonoJitInfo
*ji
= NULL
;
2224 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2225 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2226 MonoLMF
*lmf
= mono_get_lmf ();
2227 GList
*trace_ips
= NULL
;
2228 GSList
*dynamic_methods
= NULL
;
2229 MonoException
*mono_ex
;
2230 gboolean stack_overflow
= FALSE
;
2231 MonoContext initial_ctx
;
2233 int frame_count
= 0;
2240 MonoFirstPassResult result
= MONO_FIRST_PASS_UNHANDLED
;
2242 g_assert (ctx
!= NULL
);
2243 *last_mono_wrapper_runtime_invoke
= TRUE
;
2244 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2245 stack_overflow
= TRUE
;
2247 mono_ex
= (MonoException
*)obj
;
2248 MonoArray
*initial_trace_ips
= mono_ex
->trace_ips
;
2249 if (initial_trace_ips
) {
2250 int len
= mono_array_length_internal (initial_trace_ips
) / TRACE_IP_ENTRY_SIZE
;
2252 // If we catch in managed/non-wrapper, we don't save the catching frame
2253 if (!mono_ex
->caught_in_unmanaged
)
2256 for (i
= 0; i
< len
; i
++) {
2257 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
2258 gpointer p
= mono_array_get_internal (initial_trace_ips
, gpointer
, (i
* TRACE_IP_ENTRY_SIZE
) + j
);
2259 trace_ips
= g_list_prepend (trace_ips
, p
);
2264 // Reset the state because we're making it be caught somewhere
2265 if (mono_ex
->caught_in_unmanaged
)
2266 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, caught_in_unmanaged
, 0);
2268 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2269 mono_error_assert_ok (error
);
2274 call_filter
= (int (*) (MonoContext
*, void *))mono_get_call_filter ();
2276 g_assert (jit_tls
->end_of_stack
);
2277 g_assert (jit_tls
->abort_func
);
2280 *out_filter_idx
= -1;
2284 *out_prev_ji
= NULL
;
2288 unwinder_init (&unwinder
);
2291 MonoContext new_ctx
;
2293 int clause_index_start
= 0;
2294 gboolean unwind_res
= TRUE
;
2296 StackFrameInfo frame
;
2301 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2303 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2304 g_list_free (trace_ips
);
2308 switch (frame
.type
) {
2309 case FRAME_TYPE_DEBUGGER_INVOKE
:
2310 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2311 case FRAME_TYPE_TRAMPOLINE
:
2312 case FRAME_TYPE_INTERP_TO_MANAGED
:
2313 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2316 case FRAME_TYPE_INTERP
:
2317 case FRAME_TYPE_MANAGED
:
2320 g_assert_not_reached ();
2324 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2329 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2331 ip
= MONO_CONTEXT_GET_IP (ctx
);
2334 method
= jinfo_get_method (ji
);
2335 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2337 if (mini_debug_options
.reverse_pinvoke_exceptions
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2338 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2339 "The native frame called the managed method:\n%s\n",
2340 mono_method_full_name (method
, TRUE
));
2343 if (method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
2344 // avoid giant stack traces during a stack overflow
2345 if (frame_count
< 1000) {
2346 trace_ips
= g_list_prepend (trace_ips
, ip
);
2347 trace_ips
= g_list_prepend (trace_ips
, get_generic_info_from_stack_frame (ji
, ctx
));
2348 trace_ips
= g_list_prepend (trace_ips
, ji
);
2352 if (method
->dynamic
)
2353 dynamic_methods
= g_slist_prepend (dynamic_methods
, method
);
2355 if (stack_overflow
) {
2356 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2358 free_stack
= 0xffffff;
2361 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2362 result
= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
;
2366 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2367 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2368 gboolean filtered
= FALSE
;
2371 * During stack overflow, wait till the unwinding frees some stack
2372 * space before running handlers/finalizers.
2374 if (free_stack
<= (64 * 1024))
2377 if (is_address_protected (ji
, ei
, ip
)) {
2379 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2382 * Have to unwrap RuntimeWrappedExceptions if the
2383 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2385 if (non_exception
&& !wrap_non_exception_throws (method
))
2386 ex_obj
= non_exception
;
2390 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2391 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2393 #ifndef DISABLE_PERFCOUNTERS
2394 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_filters
);
2397 if (!ji
->is_interp
) {
2398 #ifndef MONO_CROSS_COMPILE
2399 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2401 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2403 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2404 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2406 g_assert (!ji
->from_llvm
);
2407 /* store the exception object in bp + ei->exvar_offset */
2408 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2412 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2414 * Pass the original il clause index to the landing pad so it can
2415 * branch to the landing pad associated with the il clause.
2416 * This is needed because llvm compiled code assumes that the EH
2417 * code always branches to the innermost landing pad.
2420 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2424 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2426 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2427 jit_tls
->orig_ex_ctx_set
= TRUE
;
2428 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2429 jit_tls
->orig_ex_ctx_set
= FALSE
;
2432 if (ji
->is_interp
) {
2433 /* The filter ends where the exception handler starts */
2434 filtered
= mini_get_interp_callbacks ()->run_filter (&frame
, (MonoException
*)ex_obj
, i
, ei
->data
.filter
, ei
->handler_start
);
2436 filtered
= call_filter (ctx
, ei
->data
.filter
);
2438 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2439 if (filtered
&& out_filter_idx
)
2440 *out_filter_idx
= filter_idx
;
2446 g_list_free (trace_ips
);
2447 /* mono_debugger_agent_handle_exception () needs this */
2448 mini_set_abort_threshold (&frame
);
2449 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2450 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2451 *catch_frame
= frame
;
2452 result
= MONO_FIRST_PASS_HANDLED
;
2457 ERROR_DECL (isinst_error
); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2458 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (ex_obj
, catch_class
, error
)) {
2459 /* runtime invokes catch even unhandled exceptions */
2460 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
);
2461 g_list_free (trace_ips
);
2466 /* mono_debugger_agent_handle_exception () needs this */
2468 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2469 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2470 *catch_frame
= frame
;
2471 result
= MONO_FIRST_PASS_HANDLED
;
2472 if (method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2473 //try to find threadpool_perform_wait_callback_method
2474 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &new_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2475 while (unwind_res
) {
2476 if (frame
.ji
&& !frame
.ji
->is_trampoline
&& jinfo_get_method (frame
.ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2477 *last_mono_wrapper_runtime_invoke
= FALSE
;
2480 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &new_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2485 mono_error_cleanup (isinst_error
);
2492 g_assert_not_reached ();
2496 * We implement delaying of aborts when in finally blocks by reusing the
2497 * abort protected block mechanism. The problem is that when throwing an
2498 * exception in a finally block we don't get to exit the protected block.
2499 * We exit it here when unwinding. Given that the order of the clauses
2500 * in the jit info is from inner clauses to the outer clauses, when we
2501 * want to exit the finally blocks inner to the clause that handles the
2502 * exception, we need to search up to its index.
2504 * FIXME We should do this inside interp, but with mixed mode we can
2505 * resume directly, without giving control back to the interp.
2508 interp_exit_finally_abort_blocks (MonoJitInfo
*ji
, int start_clause
, int end_clause
, gpointer ip
)
2511 for (i
= start_clause
; i
< end_clause
; i
++) {
2512 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2513 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
&&
2514 ip
>= ei
->handler_start
&&
2515 ip
< ei
->data
.handler_end
) {
2516 mono_threads_end_abort_protected_block ();
2521 static MonoException
*
2522 mono_get_exception_runtime_wrapped_checked (MonoObject
*wrapped_exception_raw
, MonoError
*error
)
2524 HANDLE_FUNCTION_ENTER ();
2525 MONO_HANDLE_DCL (MonoObject
, wrapped_exception
);
2526 MonoExceptionHandle ret
= mono_get_exception_runtime_wrapped_handle (wrapped_exception
, error
);
2527 HANDLE_FUNCTION_RETURN_OBJ (ret
);
2531 * mono_handle_exception_internal:
2532 * \param ctx saved processor state
2533 * \param obj the exception object
2534 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2537 mono_handle_exception_internal (MonoContext
*ctx
, MonoObject
*obj
, gboolean resume
, MonoJitInfo
**out_ji
)
2540 MonoDomain
*domain
= mono_domain_get ();
2541 MonoJitInfo
*ji
, *prev_ji
;
2542 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2543 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2544 MonoLMF
*lmf
= mono_get_lmf ();
2545 MonoException
*mono_ex
;
2546 gboolean stack_overflow
= FALSE
;
2547 MonoContext initial_ctx
;
2549 int frame_count
= 0;
2550 gint32 filter_idx
, first_filter_idx
= 0;
2552 MonoObject
*ex_obj
= NULL
;
2553 MonoObject
*non_exception
= NULL
;
2556 gboolean is_caught_unmanaged
= FALSE
;
2557 gboolean last_mono_wrapper_runtime_invoke
= TRUE
;
2559 g_assert (ctx
!= NULL
);
2561 MonoException
*ex
= mono_get_exception_null_reference ();
2562 MonoString
*msg
= mono_string_new_checked (domain
, "Object reference not set to an instance of an object", error
);
2563 mono_error_assert_ok (error
);
2564 MONO_OBJECT_SETREF_INTERNAL (ex
, message
, msg
);
2565 obj
= (MonoObject
*)ex
;
2569 * Allocate a new exception object instead of the preconstructed ones.
2571 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
) {
2573 * It is not a good idea to try and put even more pressure on the little stack available.
2574 * obj = mono_get_exception_stack_overflow ();
2576 stack_overflow
= TRUE
;
2578 else if (obj
== (MonoObject
*)domain
->null_reference_ex
) {
2579 obj
= (MonoObject
*)mono_get_exception_null_reference ();
2582 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2583 mono_error_assert_ok (error
);
2584 non_exception
= obj
;
2585 obj
= (MonoObject
*)mono_get_exception_runtime_wrapped_checked (obj
, error
);
2586 mono_error_assert_ok (error
);
2589 mono_ex
= (MonoException
*)obj
;
2591 if (mini_debug_options
.suspend_on_exception
) {
2592 mono_runtime_printf_err ("Exception thrown, suspending...");
2597 if (mono_ex
->caught_in_unmanaged
)
2598 is_caught_unmanaged
= TRUE
;
2601 if (mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2602 mono_ex
= (MonoException
*)obj
;
2604 mono_error_assert_ok (error
);
2608 if (mono_ex
&& jit_tls
->class_cast_from
) {
2609 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "InvalidCastException")) {
2610 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2611 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2612 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
2613 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2616 if (!is_ok (error
)) {
2617 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg
);
2618 mono_error_assert_ok (error
);
2622 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "ArrayTypeMismatchException")) {
2623 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2624 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2625 char *msg
= g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name
, to_name
);
2626 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2629 if (!is_ok (error
)) {
2630 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg
);
2631 mono_error_assert_ok (error
);
2638 call_filter
= (int (*)(MonoContext
*, void*))mono_get_call_filter ();
2640 g_assert (jit_tls
->end_of_stack
);
2641 g_assert (jit_tls
->abort_func
);
2644 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2645 * end up being TRUE on any code path.
2647 memcpy (&jit_tls
->orig_ex_ctx
, ctx
, sizeof (MonoContext
));
2650 MonoContext ctx_cp
= *ctx
;
2651 if (mono_trace_is_enabled ()) {
2653 MonoMethod
*system_exception_get_message
= mono_class_get_method_from_name_checked (mono_defaults
.exception_class
, "get_Message", 0, 0, error
);
2654 mono_error_cleanup (error
);
2656 MonoMethod
*get_message
= system_exception_get_message
== NULL
? NULL
: mono_object_get_virtual_method_internal (obj
, system_exception_get_message
);
2657 MonoObject
*message
;
2658 const char *type_name
= m_class_get_name (mono_object_class (mono_ex
));
2660 if (get_message
== NULL
) {
2662 } else if (!strcmp (type_name
, "OutOfMemoryException") || !strcmp (type_name
, "StackOverflowException")) {
2664 msg
= g_strdup_printf ("(No exception message for: %s)\n", type_name
);
2666 MonoObject
*exc
= NULL
;
2667 message
= mono_runtime_try_invoke (get_message
, obj
, NULL
, &exc
, error
);
2668 g_assert (exc
== NULL
);
2669 mono_error_assert_ok (error
);
2673 msg
= mono_string_to_utf8_checked_internal ((MonoString
*) message
, error
);
2674 if (!is_ok (error
)) {
2675 mono_error_cleanup (error
);
2676 msg
= g_strdup ("(error while display System.Exception.Message property)");
2679 msg
= g_strdup ("(System.Exception.Message property not available)");
2682 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
);
2684 if (mono_ex
&& mono_trace_eval_exception (mono_object_class (mono_ex
)))
2685 mono_print_thread_dump_from_ctx (ctx
);
2687 jit_tls
->orig_ex_ctx_set
= TRUE
;
2688 MONO_PROFILER_RAISE (exception_throw
, (obj
));
2689 jit_tls
->orig_ex_ctx_set
= FALSE
;
2691 StackFrameInfo catch_frame
;
2692 MonoFirstPassResult res
;
2693 res
= handle_exception_first_pass (&ctx_cp
, obj
, &first_filter_idx
, &ji
, &prev_ji
, non_exception
, &catch_frame
, &last_mono_wrapper_runtime_invoke
);
2695 if (res
== MONO_FIRST_PASS_UNHANDLED
) {
2696 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2697 /* Reached the top interpreted frames, but there might be native frames above us */
2698 throw_exception (obj
, TRUE
);
2699 g_assert_not_reached ();
2701 if (mini_debug_options
.break_on_exc
)
2703 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2705 if (mini_debug_options
.suspend_on_unhandled
&& mono_object_class (obj
) != mono_defaults
.threadabortexception_class
) {
2706 mono_runtime_printf_err ("Unhandled exception, suspending...");
2711 // FIXME: This runs managed code so it might cause another stack overflow when
2712 // we are handling a stack overflow
2713 mini_set_abort_threshold (&catch_frame
);
2714 mono_unhandled_exception_internal (obj
);
2716 gboolean unhandled
= FALSE
;
2719 * The exceptions caught by the mono_runtime_invoke_checked () calls
2720 * in the threadpool needs to be treated as unhandled (#669836).
2722 * FIXME: The check below is hackish, but its hard to distinguish
2723 * these runtime invoke calls from others in the runtime.
2725 #ifndef ENABLE_NETCORE
2726 if (ji
&& jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2727 if (prev_ji
&& jinfo_get_method (prev_ji
) == mono_defaults
.threadpool_perform_wait_callback_method
)
2733 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2734 else if (!ji
|| (jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
)) {
2735 if (last_mono_wrapper_runtime_invoke
&& mono_thread_get_main () && (mono_thread_internal_current () == mono_thread_get_main ()->internal_thread
))
2736 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2738 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2740 else if (res
!= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
)
2741 if (!is_caught_unmanaged
)
2742 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2751 unwinder_init (&unwinder
);
2754 MonoContext new_ctx
;
2756 int clause_index_start
= 0;
2757 gboolean unwind_res
= TRUE
;
2758 StackFrameInfo frame
;
2763 ji
= jit_tls
->resume_state
.ji
;
2764 new_ctx
= jit_tls
->resume_state
.new_ctx
;
2765 clause_index_start
= jit_tls
->resume_state
.clause_index
;
2766 lmf
= jit_tls
->resume_state
.lmf
;
2767 first_filter_idx
= jit_tls
->resume_state
.first_filter_idx
;
2768 filter_idx
= jit_tls
->resume_state
.filter_idx
;
2771 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2773 *(mono_get_lmf_addr ()) = lmf
;
2775 jit_tls
->abort_func (obj
);
2776 g_assert_not_reached ();
2778 switch (frame
.type
) {
2779 case FRAME_TYPE_DEBUGGER_INVOKE
:
2780 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2781 case FRAME_TYPE_TRAMPOLINE
:
2782 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2785 case FRAME_TYPE_INTERP_TO_MANAGED
:
2787 case FRAME_TYPE_INTERP
:
2788 case FRAME_TYPE_MANAGED
:
2791 g_assert_not_reached ();
2794 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2799 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2801 ip
= MONO_CONTEXT_GET_IP (ctx
);
2803 method
= jinfo_get_method (ji
);
2805 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2807 if (stack_overflow
) {
2808 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2810 free_stack
= 0xffffff;
2813 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2814 guint32 handle
= mono_gchandle_new_internal (obj
, FALSE
);
2815 MONO_STACKDATA (stackptr
);
2817 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr
);
2819 ftnptr_eh_callback (handle
);
2820 g_error ("Did not expect ftnptr_eh_callback to return.");
2823 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2824 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2825 gboolean filtered
= FALSE
;
2828 * During stack overflow, wait till the unwinding frees some stack
2829 * space before running handlers/finalizers.
2831 if (free_stack
<= (64 * 1024))
2834 if (is_address_protected (ji
, ei
, ip
)) {
2836 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2839 * Have to unwrap RuntimeWrappedExceptions if the
2840 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2842 if (non_exception
&& !wrap_non_exception_throws (method
))
2843 ex_obj
= non_exception
;
2847 if (((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
))) {
2848 #ifndef MONO_CROSS_COMPILE
2849 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2850 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2852 g_assert (!ji
->from_llvm
);
2853 /* store the exception object in bp + ei->exvar_offset */
2854 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2859 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2861 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2864 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2866 * Filter clauses should only be run in the
2867 * first pass of exception handling.
2869 filtered
= (filter_idx
== first_filter_idx
);
2874 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
2875 mono_object_isinst_checked (ex_obj
, catch_class
, error
)) || filtered
) {
2877 * This guards against the situation that we abort a thread that is executing a finally clause
2878 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2879 * check for this situation here and resume interruption if we are below the guarded block.
2881 if (G_UNLIKELY (jit_tls
->handler_block
)) {
2882 gboolean is_outside
= FALSE
;
2883 gpointer prot_bp
= MONO_CONTEXT_GET_BP (&jit_tls
->handler_block_context
);
2884 gpointer catch_bp
= MONO_CONTEXT_GET_BP (ctx
);
2885 //FIXME make this stack direction aware
2887 if (catch_bp
> prot_bp
) {
2889 } else if (catch_bp
== prot_bp
) {
2890 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2891 * So we check if the catch handler_start is protected by the guarded handler protected region
2894 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2895 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2896 * There aren't any further finally/fault handler blocks down the stack over this exception.
2897 * This must be ensured by the code that installs the guard trampoline.
2899 g_assert (ji
== mini_jit_info_table_find (domain
, (char *)MONO_CONTEXT_GET_IP (&jit_tls
->handler_block_context
), NULL
));
2901 if (!is_address_protected (ji
, jit_tls
->handler_block
, ei
->handler_start
)) {
2906 jit_tls
->handler_block
= NULL
;
2907 mono_thread_resume_interruption (TRUE
); /*We ignore the exception here, it will be raised later*/
2911 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2912 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2915 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2916 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2917 * clause. Since we specifically want to indicate that we're executing the
2918 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2919 * instead of ei->flags.
2921 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2922 jit_tls
->orig_ex_ctx_set
= TRUE
;
2923 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, MONO_EXCEPTION_CLAUSE_NONE
, ex_obj
));
2924 jit_tls
->orig_ex_ctx_set
= FALSE
;
2927 mini_set_abort_threshold (&frame
);
2930 interp_exit_finally_abort_blocks (ji
, clause_index_start
, i
, ip
);
2932 * ctx->pc points into the interpreter, after the call which transitioned to
2933 * JITted code. Store the unwind state into the
2934 * interpeter state, then resume, the interpreter will unwind itself until
2935 * it reaches the target frame and will continue execution from there.
2936 * The resuming is kinda hackish, from the native code standpoint, it looks
2937 * like the call which transitioned to JITted code has succeeded, but the
2938 * return value register etc. is not set, so we have to be careful.
2940 mini_get_interp_callbacks ()->set_resume_state (jit_tls
, mono_ex
, ei
, frame
.interp_frame
, ei
->handler_start
);
2941 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2942 /* ip == 0 means an interpreter frame */
2943 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
2944 mono_arch_undo_ip_adjustment (ctx
);
2946 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2949 #ifndef DISABLE_PERFCOUNTERS
2950 mono_atomic_fetch_add_i32 (&mono_perfcounters
->exceptions_depth
, frame_count
);
2952 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2953 jit_tls
->handling_stack_ovf
= FALSE
;
2957 mono_error_cleanup (error
);
2958 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) {
2959 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2960 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2962 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2963 jit_tls
->orig_ex_ctx_set
= TRUE
;
2964 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2965 jit_tls
->orig_ex_ctx_set
= FALSE
;
2968 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2969 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2970 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2972 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2973 jit_tls
->orig_ex_ctx_set
= TRUE
;
2974 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2975 jit_tls
->orig_ex_ctx_set
= FALSE
;
2978 #ifndef DISABLE_PERFCOUNTERS
2979 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_finallys
);
2982 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
|| ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2984 if (ji
->from_llvm
) {
2986 * LLVM compiled finally handlers follow the design
2987 * of the c++ ehabi, i.e. they call a resume function
2988 * at the end instead of returning to the caller.
2989 * So save the exception handling state,
2990 * mono_resume_unwind () will call us again to continue
2993 jit_tls
->resume_state
.ex_obj
= obj
;
2994 jit_tls
->resume_state
.ji
= ji
;
2995 jit_tls
->resume_state
.clause_index
= i
+ 1;
2996 jit_tls
->resume_state
.ctx
= *ctx
;
2997 jit_tls
->resume_state
.new_ctx
= new_ctx
;
2998 jit_tls
->resume_state
.lmf
= lmf
;
2999 jit_tls
->resume_state
.first_filter_idx
= first_filter_idx
;
3000 jit_tls
->resume_state
.filter_idx
= filter_idx
;
3001 mini_set_abort_threshold (&frame
);
3002 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
3005 mini_set_abort_threshold (&frame
);
3007 gboolean has_ex
= mini_get_interp_callbacks ()->run_finally (&frame
, i
, ei
->handler_start
, ei
->data
.handler_end
);
3010 * If run_finally didn't resume to a context, it means that the handler frame
3011 * is linked to the frame calling finally through interpreter frames. This
3012 * means that we will reach the handler frame by resuming the current context.
3014 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
3015 mono_arch_undo_ip_adjustment (ctx
);
3019 call_filter (ctx
, ei
->handler_start
);
3027 interp_exit_finally_abort_blocks (ji
, clause_index_start
, ji
->num_clauses
, ip
);
3029 if (MONO_PROFILER_ENABLED (method_exception_leave
) &&
3030 mono_profiler_get_call_instrumentation_flags (method
) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
) {
3031 jit_tls
->orig_ex_ctx_set
= TRUE
;
3032 MONO_PROFILER_RAISE (method_exception_leave
, (method
, ex_obj
));
3033 jit_tls
->orig_ex_ctx_set
= FALSE
;
3039 g_assert_not_reached ();
3043 * mono_debugger_run_finally:
3044 * \param start_ctx saved processor state
3045 * This method is called by the Mono Debugger to call all \c finally clauses of the
3046 * current stack frame. It's used when the user issues a \c return command to make
3047 * the current stack frame return. After returning from this method, the debugger
3048 * unwinds the stack one frame and gives control back to the user.
3049 * NOTE: This method is only used when running inside the Mono Debugger.
3052 mono_debugger_run_finally (MonoContext
*start_ctx
)
3054 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
3055 MonoDomain
*domain
= mono_domain_get ();
3056 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3057 MonoLMF
*lmf
= mono_get_lmf ();
3058 MonoContext ctx
, new_ctx
;
3059 MonoJitInfo
*ji
, rji
;
3064 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
3065 if (!ji
|| ji
== (gpointer
)-1)
3069 call_filter
= (int (*)(MonoContext
*, void *))mono_get_call_filter ();
3071 for (i
= 0; i
< ji
->num_clauses
; i
++) {
3072 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
3074 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (&ctx
)) &&
3075 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
3076 call_filter (&ctx
, ei
->handler_start
);
3082 * mono_handle_exception:
3083 * \param ctx saved processor state
3084 * \param obj the exception object
3086 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3090 mono_handle_exception (MonoContext
*ctx
, gpointer void_obj
)
3092 MonoObject
*obj
= (MonoObject
*)void_obj
;
3094 MONO_REQ_GC_UNSAFE_MODE
;
3096 #ifndef DISABLE_PERFCOUNTERS
3097 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_thrown
);
3100 return mono_handle_exception_internal (ctx
, obj
, FALSE
, NULL
);
3103 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3105 #ifndef MONO_ARCH_USE_SIGACTION
3106 #error "Can't use sigaltstack without sigaction"
3110 mono_setup_altstack (MonoJitTlsData
*tls
)
3114 guint8
*staddr
= NULL
;
3115 #if defined(TARGET_OSX) || defined(_AIX)
3117 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3118 * stack pages. Stack overflow on main thread will kill the app.
3120 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3121 * do this for thread 1 with its stack at the top of memory. Other threads seem
3122 * fine for the altstack guard page, though.
3124 gboolean disable_stack_guard
= mono_threads_platform_is_main_thread ();
3126 gboolean disable_stack_guard
= FALSE
;
3129 if (mono_running_on_valgrind ())
3132 mono_thread_info_get_stack_bounds (&staddr
, &stsize
);
3136 tls
->end_of_stack
= staddr
+ stsize
;
3137 tls
->stack_size
= stsize
;
3139 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3141 if (!disable_stack_guard
) {
3142 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
3143 tls
->stack_ovf_guard_size
= ALIGN_TO (8 * 4096, mono_pagesize ());
3145 g_assert ((guint8
*)&sa
>= (guint8
*)tls
->stack_ovf_guard_base
+ tls
->stack_ovf_guard_size
);
3147 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
3148 /* mprotect can fail for the main thread stack */
3149 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
);
3151 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
3152 tls
->stack_ovf_valloced
= TRUE
;
3154 g_warning ("couldn't allocate guard page, continue without it");
3155 tls
->stack_ovf_guard_base
= NULL
;
3156 tls
->stack_ovf_guard_size
= 0;
3161 /* Setup an alternate signal stack */
3162 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
);
3163 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3165 g_assert (tls
->signal_stack
);
3167 sa
.ss_sp
= tls
->signal_stack
;
3168 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3170 g_assert (sigaltstack (&sa
, NULL
) == 0);
3172 if (tls
->stack_ovf_guard_base
)
3173 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
);
3175 mono_gc_register_altstack (staddr
, stsize
, tls
->signal_stack
, tls
->signal_stack_size
);
3180 mono_free_altstack (MonoJitTlsData
*tls
)
3185 sa
.ss_sp
= tls
->signal_stack
;
3186 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3187 sa
.ss_flags
= SS_DISABLE
;
3188 err
= sigaltstack (&sa
, NULL
);
3189 g_assert (err
== 0);
3191 if (tls
->signal_stack
)
3192 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3194 if (!tls
->stack_ovf_guard_base
)
3196 if (tls
->stack_ovf_valloced
)
3197 mono_vfree (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3199 mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3202 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3205 mono_setup_altstack (MonoJitTlsData
*tls
)
3210 mono_free_altstack (MonoJitTlsData
*tls
)
3214 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3217 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*siginfo
, guint8
* fault_addr
)
3225 /* we got a stack overflow in the soft-guard pages
3226 * There are two cases:
3227 * 1) managed code caused the overflow: we unprotect the soft-guard page
3228 * and let the arch-specific code trigger the exception handling mechanism
3229 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3230 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3231 * and hope we can continue with those enabled, at least until the hard-guard page
3232 * is hit. The alternative to continuing here is to just print a message and abort.
3233 * We may add in the future the code to protect the pages again in the codepath
3234 * when we return from unmanaged to managed code.
3236 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
3237 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
3238 gboolean handled
= FALSE
;
3240 mono_mprotect (jit_tls
->stack_ovf_guard_base
, jit_tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3241 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3243 mono_arch_handle_altstack_exception (ctx
, siginfo
, fault_addr
, TRUE
);
3248 /* We print a message: after this even managed stack overflows
3249 * may crash the runtime
3251 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx
), fault_addr
);
3252 if (!jit_tls
->handling_stack_ovf
) {
3253 jit_tls
->handling_stack_ovf
= 1;
3255 /*fprintf (stderr, "Already handling stack overflow\n");*/
3264 MonoMethod
*omethod
;
3266 } PrintOverflowUserData
;
3269 print_overflow_stack_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3271 MonoMethod
*method
= NULL
;
3272 PrintOverflowUserData
*user_data
= (PrintOverflowUserData
*)data
;
3275 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3276 method
= jinfo_get_method (frame
->ji
);
3279 if (user_data
->count
== 0) {
3280 /* The first frame is in its prolog, so a line number cannot be computed */
3281 user_data
->count
++;
3285 /* If this is a one method overflow, skip the other instances */
3286 if (method
== user_data
->omethod
)
3289 location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, mono_domain_get ());
3290 mono_runtime_printf_err (" %s", location
);
3293 if (user_data
->count
== 1) {
3294 mono_runtime_printf_err (" <...>");
3295 user_data
->omethod
= method
;
3297 user_data
->omethod
= NULL
;
3300 user_data
->count
++;
3302 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame
->native_offset
);
3308 mono_handle_hard_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, MonoContext
*mctx
, guint8
* fault_addr
)
3310 PrintOverflowUserData ud
;
3312 /* we don't do much now, but we can warn the user with a useful message */
3313 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx
), fault_addr
);
3315 mono_runtime_printf_err ("Stacktrace:");
3317 memset (&ud
, 0, sizeof (ud
));
3319 mono_walk_stack_with_ctx (print_overflow_stack_frame
, mctx
, MONO_UNWIND_LOOKUP_ACTUAL_METHOD
, &ud
);
3325 print_stack_frame_signal_safe (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3327 MonoMethod
*method
= NULL
;
3329 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3330 method
= jinfo_get_method (frame
->ji
);
3333 const char *name_space
= m_class_get_name_space (method
->klass
);
3334 g_async_safe_printf("\t at %s%s%s:%s <0x%05x>\n", name_space
, (name_space
[0] != '\0' ? "." : ""), m_class_get_name (method
->klass
), method
->name
, frame
->native_offset
);
3336 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame
->native_offset
);
3342 static G_GNUC_UNUSED gboolean
3343 print_stack_frame_to_string (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3345 GString
*p
= (GString
*)data
;
3346 MonoMethod
*method
= NULL
;
3348 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3349 method
= jinfo_get_method (frame
->ji
);
3351 if (method
&& frame
->domain
) {
3352 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
3353 g_string_append_printf (p
, " %s\n", location
);
3356 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
3361 #ifndef MONO_CROSS_COMPILE
3362 static gboolean handle_crash_loop
= FALSE
;
3365 * mono_handle_native_crash:
3367 * Handle a native crash (e.g. SIGSEGV) while in native code by
3368 * printing diagnostic information and aborting.
3371 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3373 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3375 if (handle_crash_loop
)
3378 #ifdef MONO_ARCH_USE_SIGACTION
3379 struct sigaction sa
;
3380 sa
.sa_handler
= SIG_DFL
;
3381 sigemptyset (&sa
.sa_mask
);
3384 /* Remove our SIGABRT handler */
3385 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
3387 /* On some systems we get a SIGILL when calling abort (), because it might
3388 * fail to raise SIGABRT */
3389 g_assert (sigaction (SIGILL
, &sa
, NULL
) != -1);
3391 /* Remove SIGCHLD, it uses the finalizer thread */
3392 g_assert (sigaction (SIGCHLD
, &sa
, NULL
) != -1);
3394 /* Remove SIGQUIT, we are already dumping threads */
3395 g_assert (sigaction (SIGQUIT
, &sa
, NULL
) != -1);
3399 if (mini_debug_options
.suspend_on_native_crash
) {
3400 g_async_safe_printf ("Received %s, suspending...\n", signal
);
3402 // Sleep for 1 second.
3403 g_usleep (1000 * 1000);
3407 /* prevent infinite loops in crash handling */
3408 handle_crash_loop
= TRUE
;
3411 * A SIGSEGV indicates something went very wrong so we can no longer depend
3412 * on anything working. So try to print out lots of diagnostics, starting
3413 * with ones which have a greater chance of working.
3416 g_async_safe_printf("\n=================================================================\n");
3417 g_async_safe_printf("\tNative Crash Reporting\n");
3418 g_async_safe_printf("=================================================================\n");
3419 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal
);
3420 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3421 g_async_safe_printf("used by your application.\n");
3422 g_async_safe_printf("=================================================================\n");
3423 mono_dump_native_crash_info (signal
, mctx
, info
);
3425 /* !jit_tls means the thread was not registered with the runtime */
3426 // This must be below the native crash dump, because we can't safely
3427 // do runtime state probing after we have walked the managed stack here.
3428 if (jit_tls
&& mono_thread_internal_current () && mctx
) {
3429 g_async_safe_printf ("\n=================================================================\n");
3430 g_async_safe_printf ("\tManaged Stacktrace:\n");
3431 g_async_safe_printf ("=================================================================\n");
3433 mono_walk_stack_full (print_stack_frame_signal_safe
, mctx
, mono_domain_get (), jit_tls
, mono_get_lmf (), MONO_UNWIND_LOOKUP_IL_OFFSET
, NULL
, TRUE
);
3434 g_async_safe_printf ("=================================================================\n");
3437 mono_post_native_crash_handler (signal
, mctx
, info
, mono_do_crash_chaining
);
3443 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3445 g_assert_not_reached ();
3448 #endif /* !MONO_CROSS_COMPILE */
3451 mono_print_thread_dump_internal (void *sigctx
, MonoContext
*start_ctx
)
3453 MonoInternalThread
*thread
= mono_thread_internal_current ();
3460 text
= g_string_new (0);
3462 mono_gstring_append_thread_name (text
, thread
);
3464 g_string_append_printf (text
, " tid=%p this=%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
3465 mono_thread_internal_describe (thread
, text
);
3466 g_string_append (text
, "\n");
3469 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
3471 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
3473 mono_sigctx_to_monoctx (sigctx
, &ctx
);
3475 mono_walk_stack_with_ctx (print_stack_frame_to_string
, &ctx
, MONO_UNWIND_LOOKUP_ALL
, text
);
3477 mono_runtime_printf ("%s", text
->str
);
3479 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3480 OutputDebugStringA(text
->str
);
3483 g_string_free (text
, TRUE
);
3484 mono_runtime_stdout_fflush ();
3488 * mono_print_thread_dump:
3490 * Print information about the current thread to stdout.
3491 * \p sigctx can be NULL, allowing this to be called from gdb.
3494 mono_print_thread_dump (void *sigctx
)
3496 mono_print_thread_dump_internal (sigctx
, NULL
);
3500 mono_print_thread_dump_from_ctx (MonoContext
*ctx
)
3502 mono_print_thread_dump_internal (NULL
, ctx
);
3506 * mono_resume_unwind:
3508 * This is called by a trampoline from LLVM compiled finally clauses to continue
3512 mono_resume_unwind (MonoContext
*ctx
)
3514 MONO_REQ_GC_UNSAFE_MODE
;
3516 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3517 MonoContext new_ctx
;
3519 MONO_CONTEXT_SET_IP (ctx
, MONO_CONTEXT_GET_IP (&jit_tls
->resume_state
.ctx
));
3520 MONO_CONTEXT_SET_SP (ctx
, MONO_CONTEXT_GET_SP (&jit_tls
->resume_state
.ctx
));
3523 mono_handle_exception_internal (&new_ctx
, (MonoObject
*)jit_tls
->resume_state
.ex_obj
, TRUE
, NULL
);
3525 mono_restore_context (&new_ctx
);
3531 MonoJitExceptionInfo
*ei
;
3532 } FindHandlerBlockData
;
3535 find_last_handler_block (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3539 FindHandlerBlockData
*pdata
= (FindHandlerBlockData
*)data
;
3540 MonoJitInfo
*ji
= frame
->ji
;
3545 ip
= MONO_CONTEXT_GET_IP (ctx
);
3547 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
3548 MonoJitExceptionInfo
*ei
= ji
->clauses
+ i
;
3549 if (ei
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
3551 /*If ip points to the first instruction it means the handler block didn't start
3552 so we can leave its execution to the EH machinery*/
3553 if (ei
->handler_start
<= ip
&& ip
< ei
->data
.handler_end
) {
3565 install_handler_block_guard (MonoJitInfo
*ji
, MonoContext
*ctx
)
3568 MonoJitExceptionInfo
*clause
= NULL
;
3572 ip
= MONO_CONTEXT_GET_IP (ctx
);
3574 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
3575 clause
= &ji
->clauses
[i
];
3576 if (clause
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
3578 if (clause
->handler_start
<= ip
&& clause
->data
.handler_end
> ip
)
3582 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3583 g_assert (i
< ji
->num_clauses
);
3586 bp
= (guint8
*)MONO_CONTEXT_GET_BP (ctx
);
3587 *(bp
+ clause
->exvar_offset
) = 1;
3591 * Finds the bottom handler block running and install a block guard if needed.
3594 mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
)
3596 FindHandlerBlockData data
= { 0 };
3597 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
];
3599 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3600 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3602 if (!jit_tls
|| jit_tls
->handler_block
)
3605 /* Do an async safe stack walk */
3606 mono_thread_info_set_is_async_context (TRUE
);
3607 mono_walk_stack_with_state (find_last_handler_block
, ctx
, MONO_UNWIND_NONE
, &data
);
3608 mono_thread_info_set_is_async_context (FALSE
);
3613 memcpy (&jit_tls
->handler_block_context
, &data
.ctx
, sizeof (MonoContext
));
3615 install_handler_block_guard (data
.ji
, &data
.ctx
);
3617 jit_tls
->handler_block
= data
.ei
;
3623 mono_uninstall_current_handler_block_guard (void)
3625 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3627 jit_tls
->handler_block
= NULL
;
3632 mono_current_thread_has_handle_block_guard (void)
3634 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3635 return jit_tls
&& jit_tls
->handler_block
!= NULL
;
3639 mono_set_cast_details (MonoClass
*from
, MonoClass
*to
)
3641 MonoJitTlsData
*jit_tls
= NULL
;
3643 if (mini_debug_options
.better_cast_details
) {
3644 jit_tls
= mono_tls_get_jit_tls ();
3645 jit_tls
->class_cast_from
= from
;
3646 jit_tls
->class_cast_to
= to
;
3651 /*returns false if the thread is not attached*/
3653 mono_thread_state_init_from_sigctx (MonoThreadUnwindState
*ctx
, void *sigctx
)
3655 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3662 mono_sigctx_to_monoctx (sigctx
, &ctx
->ctx
);
3664 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3665 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3666 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3669 mono_thread_state_init (ctx
);
3672 if (!ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] || !ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
])
3680 mono_thread_state_init (MonoThreadUnwindState
*ctx
)
3682 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3684 #if defined(MONO_CROSS_COMPILE)
3685 ctx
->valid
= FALSE
; //A cross compiler doesn't need to suspend.
3686 #elif MONO_ARCH_HAS_MONO_CONTEXT
3687 MONO_CONTEXT_GET_CURRENT (ctx
->ctx
);
3689 g_error ("Use a null sigctx requires a working mono-context");
3692 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3693 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3694 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
? thread
->jit_data
: NULL
;
3700 mono_thread_state_init_from_monoctx (MonoThreadUnwindState
*ctx
, MonoContext
*mctx
)
3702 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3709 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3710 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3711 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3716 /*returns false if the thread is not attached*/
3718 mono_thread_state_init_from_current (MonoThreadUnwindState
*ctx
)
3720 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3721 MONO_ARCH_CONTEXT_DEF
3723 mono_arch_flush_register_windows ();
3725 if (!thread
|| !thread
->jit_data
) {
3729 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
->ctx
, mono_thread_state_init_from_current
);
3731 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3732 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3733 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3739 mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
)
3741 mono_handle_exception (ctx
, (MonoObject
*)exc
);
3742 mono_restore_context (ctx
);
3745 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3747 mono_setup_async_callback (MonoContext
*ctx
, void (*async_cb
)(void *fun
), gpointer user_data
)
3749 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3750 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3751 jit_tls
->ex_ctx
= *ctx
;
3753 mono_arch_setup_async_callback (ctx
, async_cb
, user_data
);
3755 g_error ("This target doesn't support mono_arch_setup_async_callback");
3760 * mono_restore_context:
3762 * Call the architecture specific restore context function.
3765 mono_restore_context (MonoContext
*ctx
)
3767 static void (*restore_context
) (MonoContext
*);
3769 if (!restore_context
)
3770 restore_context
= (void (*)(MonoContext
*))mono_get_restore_context ();
3771 restore_context (ctx
);
3772 g_assert_not_reached ();
3776 * mono_jinfo_get_unwind_info:
3778 * Return the unwind info for JI.
3781 mono_jinfo_get_unwind_info (MonoJitInfo
*ji
, guint32
*unwind_info_len
)
3783 if (ji
->has_unwind_info
) {
3784 /* The address/length in the MonoJitInfo structure itself */
3785 MonoUnwindJitInfo
*info
= mono_jit_info_get_unwind_info (ji
);
3786 *unwind_info_len
= info
->unw_info_len
;
3787 return info
->unw_info
;
3788 } else if (ji
->from_aot
)
3789 return mono_aot_get_unwind_info (ji
, unwind_info_len
);
3791 return mono_get_cached_unwind_info (ji
->unwind_info
, unwind_info_len
);
3795 mono_jinfo_get_epilog_size (MonoJitInfo
*ji
)
3797 MonoArchEHJitInfo
*info
;
3799 info
= mono_jit_info_get_arch_eh_info (ji
);
3802 return info
->epilog_size
;
3806 * mono_install_ftnptr_eh_callback:
3808 * Install a callback that should be called when there is a managed exception
3809 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3810 * managed exception to a native exception, to properly unwind the native
3811 * stack; this native exception will then be converted back to a managed
3812 * exception in their managed-to-native wrapper.
3815 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback
)
3817 ftnptr_eh_callback
= callback
;
3821 * LLVM/Bitcode exception handling.
3825 throw_exception (MonoObject
*ex
, gboolean rethrow
)
3827 MONO_REQ_GC_UNSAFE_MODE
;
3830 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3831 MonoException
*mono_ex
;
3833 if (!mono_object_isinst_checked (ex
, mono_defaults
.exception_class
, error
)) {
3834 mono_error_assert_ok (error
);
3835 mono_ex
= mono_get_exception_runtime_wrapped_checked (ex
, error
);
3836 mono_error_assert_ok (error
);
3837 jit_tls
->thrown_non_exc
= mono_gchandle_new_internal (ex
, FALSE
);
3840 mono_ex
= (MonoException
*)ex
;
3843 jit_tls
->thrown_exc
= mono_gchandle_new_internal ((MonoObject
*)mono_ex
, FALSE
);
3846 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3847 GList
*l
, *ips
= NULL
;
3850 _Unwind_Backtrace (build_stack_trace
, &ips
);
3851 /* The list contains ip-gshared info pairs */
3853 ips
= g_list_reverse (ips
);
3854 for (l
= ips
; l
; l
= l
->next
) {
3855 trace
= g_list_append (trace
, l
->data
);
3856 trace
= g_list_append (trace
, NULL
);
3857 trace
= g_list_append (trace
, NULL
);
3859 MonoArray
*ips_arr
= mono_glist_to_array (trace
, mono_defaults
.int_class
, error
);
3860 mono_error_assert_ok (error
);
3861 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
3863 g_list_free (trace
);
3867 mono_llvm_cpp_throw_exception ();
3871 mono_llvm_throw_exception (MonoObject
*ex
)
3873 throw_exception (ex
, FALSE
);
3877 mono_llvm_rethrow_exception (MonoObject
*ex
)
3879 throw_exception (ex
, TRUE
);
3883 mono_llvm_raise_exception (MonoException
*e
)
3885 mono_llvm_throw_exception ((MonoObject
*)e
);
3889 mono_llvm_reraise_exception (MonoException
*e
)
3891 mono_llvm_rethrow_exception ((MonoObject
*)e
);
3895 mono_llvm_throw_corlib_exception (guint32 ex_token_index
)
3897 guint32 ex_token
= MONO_TOKEN_TYPE_DEF
| ex_token_index
;
3900 ex
= mono_exception_from_token (m_class_get_image (mono_defaults
.exception_class
), ex_token
);
3902 mono_llvm_throw_exception ((MonoObject
*)ex
);
3906 * mono_llvm_resume_exception:
3908 * Resume exception propagation.
3911 mono_llvm_resume_exception (void)
3913 mono_llvm_cpp_throw_exception ();
3917 * mono_llvm_load_exception:
3919 * Return the currently thrown exception.
3922 mono_llvm_load_exception (void)
3925 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3927 MonoException
*mono_ex
= (MonoException
*)mono_gchandle_get_target_internal (jit_tls
->thrown_exc
);
3929 MonoArray
*ta
= mono_ex
->trace_ips
;
3932 GList
*trace_ips
= NULL
;
3933 gpointer ip
= MONO_RETURN_ADDRESS ();
3935 size_t upper
= mono_array_length_internal (ta
);
3937 for (int i
= 0; i
< upper
; i
+= TRACE_IP_ENTRY_SIZE
) {
3938 gpointer curr_ip
= mono_array_get_internal (ta
, gpointer
, i
);
3939 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
3940 gpointer p
= mono_array_get_internal (ta
, gpointer
, i
+ j
);
3941 trace_ips
= g_list_append (trace_ips
, p
);
3947 // FIXME: Does this work correctly for rethrows?
3948 // We may be discarding useful information
3949 // when this gets GC'ed
3950 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips
, mono_defaults
.int_class
, error
);
3951 mono_error_assert_ok (error
);
3952 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
3953 g_list_free (trace_ips
);
3956 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3958 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, 0, error
));
3959 mono_error_assert_ok (error
);
3960 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, stack_trace
, mono_array_new_checked (mono_domain_get (), mono_defaults
.stack_frame_class
, 0, error
));
3961 mono_error_assert_ok (error
);
3964 return &mono_ex
->object
;
3968 * mono_llvm_clear_exception:
3970 * Mark the currently thrown exception as handled.
3973 mono_llvm_clear_exception (void)
3975 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3976 mono_gchandle_free_internal (jit_tls
->thrown_exc
);
3977 jit_tls
->thrown_exc
= 0;
3978 if (jit_tls
->thrown_non_exc
)
3979 mono_gchandle_free_internal (jit_tls
->thrown_non_exc
);
3980 jit_tls
->thrown_non_exc
= 0;
3982 mono_memory_barrier ();
3986 * mono_llvm_match_exception:
3988 * Return the innermost clause containing REGION_START-REGION_END which can handle
3989 * the current exception.
3992 mono_llvm_match_exception (MonoJitInfo
*jinfo
, guint32 region_start
, guint32 region_end
, gpointer rgctx
, MonoObject
*this_obj
)
3995 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3999 g_assert (jit_tls
->thrown_exc
);
4000 exc
= mono_gchandle_get_target_internal (jit_tls
->thrown_exc
);
4001 if (jit_tls
->thrown_non_exc
) {
4003 * Have to unwrap RuntimeWrappedExceptions if the
4004 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
4006 if (!wrap_non_exception_throws (jinfo_get_method (jinfo
)))
4007 exc
= mono_gchandle_get_target_internal (jit_tls
->thrown_non_exc
);
4010 for (int i
= 0; i
< jinfo
->num_clauses
; i
++) {
4011 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
4012 MonoClass
*catch_class
;
4014 if (! (ei
->try_offset
== region_start
&& ei
->try_offset
+ ei
->try_len
== region_end
) )
4017 catch_class
= ei
->data
.catch_class
;
4018 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class
))) {
4019 MonoGenericContext context
;
4020 MonoType
*inflated_type
;
4022 g_assert (rgctx
|| this_obj
);
4023 context
= get_generic_context_from_stack_frame (jinfo
, rgctx
? rgctx
: this_obj
->vtable
);
4024 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
4025 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
4027 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
4028 mono_metadata_free_type (inflated_type
);
4031 // FIXME: Handle edge cases handled in get_exception_catch_class
4032 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (exc
, catch_class
, error
)) {
4033 index
= ei
->clause_index
;
4036 mono_error_assert_ok (error
);
4038 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
4039 g_assert_not_reached ();
4046 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4047 G_EXTERN_C _Unwind_Reason_Code
mono_debug_personality (int a
, _Unwind_Action b
,
4048 uint64_t c
, struct _Unwind_Exception
*d
, struct _Unwind_Context
*e
)
4050 g_assert_not_reached ();
4053 G_EXTERN_C
void mono_debug_personality (void);
4056 mono_debug_personality (void)
4058 g_assert_not_reached ();