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 "debugger-engine.h"
76 #include "seq-points.h"
77 #include "llvm-runtime.h"
78 #include "mini-llvm.h"
79 #include "aot-runtime.h"
80 #include "mini-runtime.h"
81 #include "interp/interp.h"
84 #include "mini-llvm-cpp.h"
91 #ifndef MONO_ARCH_CONTEXT_DEF
92 #define MONO_ARCH_CONTEXT_DEF
95 #if !defined(DISABLE_CRASH_REPORTING)
98 #include "mono/utils/mono-tls-inline.h"
101 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
102 * This structure represents one entry.
103 * This should consists of pointers only.
108 gpointer generic_info
;
109 /* Only for interpreter frames */
113 /* Number of words in trace_ips belonging to one entry */
114 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
116 static gpointer restore_context_func
, call_filter_func
;
117 static gpointer throw_exception_func
, rethrow_exception_func
, rethrow_preserve_exception_func
;
118 static gpointer throw_corlib_exception_func
;
120 static MonoFtnPtrEHCallback ftnptr_eh_callback
;
122 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
);
123 static void mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
);
124 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
);
125 static gboolean
mono_current_thread_has_handle_block_guard (void);
126 static gboolean
mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
);
127 static void mono_uninstall_current_handler_block_guard (void);
128 static gboolean
mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
);
129 static void throw_exception (MonoObject
*ex
, gboolean rethrow
);
131 static void mono_summarize_managed_stack (MonoThreadSummary
*out
);
132 static void mono_summarize_unmanaged_stack (MonoThreadSummary
*out
);
133 static void mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
);
134 static void mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
);
135 static void mono_crash_reporting_allow_all_native_libraries (void);
138 first_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer addr
)
140 gpointer
*data
= (gpointer
*)addr
;
146 // FIXME: Happens with llvm_only
151 *data
= frame
->frame_addr
;
157 mono_thread_get_managed_sp (void)
159 gpointer addr
= NULL
;
160 mono_walk_stack (first_managed
, MONO_UNWIND_SIGNAL_SAFE
, &addr
);
165 mini_clear_abort_threshold (void)
167 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
168 jit_tls
->abort_exc_stack_threshold
= NULL
;
172 mini_set_abort_threshold (StackFrameInfo
*frame
)
174 gpointer sp
= frame
->frame_addr
;
175 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
176 // Only move it up, to avoid thrown/caught
177 // exceptions lower in the stack from triggering
179 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
180 if (!jit_tls
->abort_exc_stack_threshold
|| above_threshold
) {
181 jit_tls
->abort_exc_stack_threshold
= sp
;
185 // Note: In the case that the frame is above where the thread abort
186 // was set we bump the threshold so that functions called from the new,
187 // higher threshold don't trigger the thread abort exception
189 mini_above_abort_threshold (void)
191 gpointer sp
= mono_thread_get_managed_sp ();
192 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
197 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
200 jit_tls
->abort_exc_stack_threshold
= sp
;
202 return above_threshold
;
206 mono_get_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
209 if (mono_find_prev_seq_point_for_native_offset (domain
, method
, native_offset
, NULL
, &sp
))
215 mono_exceptions_init (void)
217 MonoRuntimeExceptionHandlingCallbacks cbs
;
218 if (mono_ee_features
.use_aot_trampolines
) {
219 restore_context_func
= mono_aot_get_trampoline ("restore_context");
220 call_filter_func
= mono_aot_get_trampoline ("call_filter");
221 throw_exception_func
= mono_aot_get_trampoline ("throw_exception");
222 rethrow_exception_func
= mono_aot_get_trampoline ("rethrow_exception");
223 rethrow_preserve_exception_func
= mono_aot_get_trampoline ("rethrow_preserve_exception");
224 } else if (!mono_llvm_only
) {
227 restore_context_func
= mono_arch_get_restore_context (&info
, FALSE
);
228 mono_tramp_info_register (info
, NULL
);
229 call_filter_func
= mono_arch_get_call_filter (&info
, FALSE
);
230 mono_tramp_info_register (info
, NULL
);
231 throw_exception_func
= mono_arch_get_throw_exception (&info
, FALSE
);
232 mono_tramp_info_register (info
, NULL
);
233 rethrow_exception_func
= mono_arch_get_rethrow_exception (&info
, FALSE
);
234 mono_tramp_info_register (info
, NULL
);
235 rethrow_preserve_exception_func
= mono_arch_get_rethrow_preserve_exception (&info
, FALSE
);
236 mono_tramp_info_register (info
, NULL
);
239 mono_arch_exceptions_init ();
241 cbs
.mono_walk_stack_with_ctx
= mono_runtime_walk_stack_with_ctx
;
242 cbs
.mono_walk_stack_with_state
= mono_walk_stack_with_state
;
243 cbs
.mono_summarize_managed_stack
= mono_summarize_managed_stack
;
244 cbs
.mono_summarize_unmanaged_stack
= mono_summarize_unmanaged_stack
;
245 cbs
.mono_summarize_exception
= mono_summarize_exception
;
246 cbs
.mono_register_native_library
= mono_crash_reporting_register_native_library
;
247 cbs
.mono_allow_all_native_libraries
= mono_crash_reporting_allow_all_native_libraries
;
249 if (mono_llvm_only
) {
250 cbs
.mono_raise_exception
= mono_llvm_raise_exception
;
251 cbs
.mono_reraise_exception
= mono_llvm_reraise_exception
;
253 cbs
.mono_raise_exception
= (void (*)(MonoException
*))mono_get_throw_exception ();
254 cbs
.mono_reraise_exception
= (void (*)(MonoException
*))mono_get_rethrow_exception ();
256 cbs
.mono_raise_exception_with_ctx
= mono_raise_exception_with_ctx
;
257 cbs
.mono_exception_walk_trace
= mono_exception_walk_trace
;
258 cbs
.mono_install_handler_block_guard
= mono_install_handler_block_guard
;
259 cbs
.mono_uninstall_current_handler_block_guard
= mono_uninstall_current_handler_block_guard
;
260 cbs
.mono_current_thread_has_handle_block_guard
= mono_current_thread_has_handle_block_guard
;
261 cbs
.mono_clear_abort_threshold
= mini_clear_abort_threshold
;
262 cbs
.mono_above_abort_threshold
= mini_above_abort_threshold
;
263 mono_install_eh_callbacks (&cbs
);
264 mono_install_get_seq_point (mono_get_seq_point_for_native_offset
);
268 mono_get_throw_exception (void)
270 g_assert (throw_exception_func
);
271 return throw_exception_func
;
275 mono_get_rethrow_exception (void)
277 g_assert (rethrow_exception_func
);
278 return rethrow_exception_func
;
282 mono_get_rethrow_preserve_exception (void)
284 g_assert (rethrow_preserve_exception_func
);
285 return rethrow_preserve_exception_func
;
289 no_call_filter (void)
291 g_assert_not_reached ();
295 mono_get_call_filter (void)
297 /* This is called even in llvmonly mode etc. */
298 if (!call_filter_func
)
299 return (gpointer
)no_call_filter
;
300 return call_filter_func
;
304 mono_get_restore_context (void)
306 g_assert (restore_context_func
);
307 return restore_context_func
;
311 mono_get_throw_corlib_exception (void)
313 gpointer code
= NULL
;
316 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
317 if (throw_corlib_exception_func
)
318 return throw_corlib_exception_func
;
320 if (mono_ee_features
.use_aot_trampolines
)
321 code
= mono_aot_get_trampoline ("throw_corlib_exception");
323 code
= mono_arch_get_throw_corlib_exception (&info
, FALSE
);
324 mono_tramp_info_register (info
, NULL
);
327 mono_memory_barrier ();
329 throw_corlib_exception_func
= code
;
331 return throw_corlib_exception_func
;
335 * mono_get_throw_exception_addr:
337 * Return an address which stores the result of
338 * mono_get_throw_exception.
341 mono_get_throw_exception_addr (void)
343 return &throw_exception_func
;
347 mono_get_rethrow_preserve_exception_addr (void)
349 return &rethrow_preserve_exception_func
;
353 is_address_protected (MonoJitInfo
*ji
, MonoJitExceptionInfo
*ei
, gpointer ip
)
355 MonoTryBlockHoleTableJitInfo
*table
;
360 if (ei
->try_start
> ip
|| ip
>= ei
->try_end
)
363 if (!ji
->has_try_block_holes
)
366 table
= mono_jit_info_get_try_block_hole_table_info (ji
);
367 offset
= (guint32
)((char*)ip
- (char*)ji
->code_start
);
368 clause
= (guint16
)(ei
- ji
->clauses
);
369 g_assert (clause
< ji
->num_clauses
);
371 for (i
= 0; i
< table
->num_holes
; ++i
) {
372 MonoTryBlockHoleJitInfo
*hole
= &table
->holes
[i
];
373 if (hole
->clause
== clause
&& hole
->offset
<= offset
&& hole
->offset
+ hole
->length
> offset
)
379 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
382 static gboolean show_native_addresses
= TRUE
;
384 static gboolean show_native_addresses
= FALSE
;
387 static _Unwind_Reason_Code
388 build_stack_trace (struct _Unwind_Context
*frame_ctx
, void *state
)
390 MonoDomain
*domain
= mono_domain_get ();
391 uintptr_t ip
= _Unwind_GetIP (frame_ctx
);
393 if (show_native_addresses
|| mono_jit_info_table_find (domain
, (char*)ip
)) {
394 GList
**trace_ips
= (GList
**)state
;
395 *trace_ips
= g_list_prepend (*trace_ips
, (gpointer
)ip
);
398 return _URC_NO_REASON
;
402 get_unwind_backtrace (void)
406 _Unwind_Backtrace (build_stack_trace
, &ips
);
408 return g_slist_reverse (ips
);
414 get_unwind_backtrace (void)
422 arch_unwind_frame (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
423 MonoJitInfo
*ji
, MonoContext
*ctx
,
424 MonoContext
*new_ctx
, MonoLMF
**lmf
,
425 host_mgreg_t
**save_locations
,
426 StackFrameInfo
*frame
)
429 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
430 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
432 memset (frame
, 0, sizeof (StackFrameInfo
));
437 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
439 * This LMF entry is created by the soft debug code to mark transitions to
440 * managed code done during invokes.
442 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
443 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
444 } else if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT
|| ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
445 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED
;
446 frame
->interp_exit_data
= ext
->interp_exit_data
;
447 if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
448 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
449 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
452 g_assert_not_reached ();
455 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~3);
461 return mono_arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
467 * Translate between the mono_arch_unwind_frame function and the old API.
470 find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
471 MonoContext
*new_ctx
, MonoLMF
**lmf
, gboolean
*managed
)
473 StackFrameInfo frame
;
476 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
478 /* Avoid costly table lookup during stack overflow */
479 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
482 ji
= mini_jit_info_table_find (domain
, ip
, NULL
);
487 err
= arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, NULL
, &frame
);
489 return (MonoJitInfo
*)-1;
491 if (*lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
493 * Remove any unused lmf.
494 * Mask out the lower bits which might be used to hold additional information.
496 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
499 /* Convert between the new and the old APIs */
500 switch (frame
.type
) {
501 case FRAME_TYPE_MANAGED
:
505 case FRAME_TYPE_TRAMPOLINE
:
507 case FRAME_TYPE_MANAGED_TO_NATIVE
:
511 memset (res
, 0, sizeof (MonoJitInfo
));
512 res
->d
.method
= frame
.method
;
515 case FRAME_TYPE_DEBUGGER_INVOKE
: {
519 * The normal exception handling code can't handle this frame, so just
522 ji
= find_jit_info (domain
, jit_tls
, res
, NULL
, new_ctx
, &tmp_ctx
, lmf
, managed
);
523 memcpy (new_ctx
, &tmp_ctx
, sizeof (MonoContext
));
527 g_assert_not_reached ();
532 /* mono_find_jit_info:
534 * This function is used to gather information from @ctx. It return the
535 * MonoJitInfo of the corresponding function, unwinds one stack frame and
536 * stores the resulting context into @new_ctx. It also stores a string
537 * describing the stack location into @trace (if not NULL), and modifies
538 * the @lmf if necessary. @native_offset return the IP offset from the
539 * start of the function or -1 if that info is not available.
542 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
543 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
547 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
549 MonoMethod
*method
= NULL
;
560 ji
= find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
562 if (ji
== (gpointer
)-1)
565 if (ji
&& !ji
->is_trampoline
)
566 method
= jinfo_get_method (ji
);
568 if (managed2
|| (method
&& method
->wrapper_type
)) {
569 const char *real_ip
, *start
;
572 start
= (const char *)ji
->code_start
;
574 /* ctx->ip points into native code */
575 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
577 real_ip
= (const char*)ip
;
579 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
580 offset
= real_ip
- start
;
585 *native_offset
= offset
;
588 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
592 *trace
= mono_debug_print_stack_frame (method
, offset
, domain
);
595 char *fname
= mono_method_full_name (jinfo_get_method (res
), TRUE
);
596 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
605 * mono_find_jit_info_ext:
607 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
609 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
610 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
611 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
612 * to obtain the last managed frame.
613 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
614 * On return, it will be filled with the locations where callee saved registers are saved
615 * by the current frame. This is returned outside of StackFrameInfo because it can be
616 * quite large on some platforms.
617 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
621 mono_find_jit_info_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
622 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
623 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
624 host_mgreg_t
**save_locations
,
625 StackFrameInfo
*frame
)
628 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
630 MonoDomain
*target_domain
= domain
;
631 MonoMethod
*method
= NULL
;
632 gboolean async
= mono_thread_info_is_async_context ();
637 /* Avoid costly table lookup during stack overflow */
638 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
641 ji
= mini_jit_info_table_find_ext (domain
, ip
, TRUE
, &target_domain
);
644 target_domain
= domain
;
647 memset (save_locations
, 0, MONO_MAX_IREGS
* sizeof (host_mgreg_t
*));
649 err
= arch_unwind_frame (target_domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
653 gboolean not_i2m
= frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED
&& frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
655 if (not_i2m
&& *lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
657 * Remove any unused lmf.
658 * Mask out the lower bits which might be used to hold additional information.
660 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
663 if (frame
->ji
&& !frame
->ji
->is_trampoline
&& !frame
->ji
->async
)
664 method
= jinfo_get_method (frame
->ji
);
666 if (frame
->type
== FRAME_TYPE_MANAGED
&& method
) {
667 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
668 frame
->managed
= TRUE
;
671 if (frame
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
) {
673 * This type of frame is just a marker, the caller should unwind once more to get the
674 * last managed frame.
677 frame
->method
= NULL
;
680 frame
->native_offset
= -1;
681 frame
->domain
= target_domain
;
682 frame
->async_context
= async
;
683 frame
->frame_addr
= MONO_CONTEXT_GET_SP (ctx
);
687 if (frame
->type
== FRAME_TYPE_MANAGED
)
688 frame
->method
= method
;
690 if (ji
&& (frame
->managed
|| (method
&& method
->wrapper_type
))) {
691 const char *real_ip
, *start
;
693 start
= (const char *)ji
->code_start
;
694 if (frame
->type
== FRAME_TYPE_MANAGED
)
695 real_ip
= (const char*)ip
;
697 /* ctx->ip points into native code */
698 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
700 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
701 frame
->native_offset
= real_ip
- start
;
703 frame
->native_offset
= -1;
707 *trace
= mono_debug_print_stack_frame (method
, frame
->native_offset
, domain
);
709 if (trace
&& frame
->method
) {
710 char *fname
= mono_method_full_name (frame
->method
, TRUE
);
711 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
721 MonoInterpStackIter interp_iter
;
722 gpointer last_frame_addr
;
726 unwinder_init (Unwinder
*unwinder
)
728 memset (unwinder
, 0, sizeof (Unwinder
));
731 #if defined(__GNUC__) && defined(TARGET_ARM64)
732 /* gcc 4.9.2 seems to miscompile this on arm64 */
733 static __attribute__((optimize("O0"))) gboolean
737 unwinder_unwind_frame (Unwinder
*unwinder
,
738 MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
739 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
740 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
741 host_mgreg_t
**save_locations
,
742 StackFrameInfo
*frame
)
745 if (unwinder
->in_interp
) {
746 memcpy (new_ctx
, ctx
, sizeof (MonoContext
));
748 /* Process debugger invokes */
749 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
750 if (unwinder
->last_frame_addr
< (gpointer
)(*lmf
)) {
751 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
752 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
753 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
754 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~7);
755 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
761 unwinder
->in_interp
= mini_get_interp_callbacks ()->frame_iter_next (&unwinder
->interp_iter
, frame
);
762 if (frame
->type
== FRAME_TYPE_INTERP
) {
763 parent
= mini_get_interp_callbacks ()->frame_get_parent (frame
->interp_frame
);
765 unwinder
->last_frame_addr
= mini_get_interp_callbacks ()->frame_get_native_stack_addr (parent
);
767 unwinder
->last_frame_addr
= NULL
;
769 if (!unwinder
->in_interp
)
770 return unwinder_unwind_frame (unwinder
, domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
, save_locations
, frame
);
773 gboolean res
= mono_find_jit_info_ext (domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
,
774 save_locations
, frame
);
777 if (frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
) {
778 unwinder
->in_interp
= TRUE
;
779 mini_get_interp_callbacks ()->frame_iter_init (&unwinder
->interp_iter
, frame
->interp_exit_data
);
781 unwinder
->last_frame_addr
= frame
->frame_addr
;
787 * This function is async-safe.
790 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
792 MonoGenericJitInfo
*gi
;
796 if (!ji
->has_generic_jit_info
)
798 gi
= mono_jit_info_get_generic_jit_info (ji
);
804 * Search location list if available, it contains the precise location of the
805 * argument for every pc offset, even if the method was interrupted while it was in
809 int offset
= (gsize
)MONO_CONTEXT_GET_IP (ctx
) - (gsize
)ji
->code_start
;
812 for (i
= 0; i
< gi
->nlocs
; ++i
) {
813 MonoDwarfLocListEntry
*entry
= &gi
->locations
[i
];
815 if (offset
>= entry
->from
&& (offset
< entry
->to
|| entry
->to
== 0)) {
817 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, entry
->reg
);
819 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, entry
->reg
) + entry
->offset
);
823 g_assert (i
< gi
->nlocs
);
826 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
828 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
832 method
= jinfo_get_method (ji
);
833 if (mono_method_get_context (method
)->method_inst
) {
834 /* A MonoMethodRuntimeGenericContext* */
836 } else if ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) || m_class_is_valuetype (method
->klass
)) {
840 /* Avoid returning a managed object */
841 MonoObject
*this_obj
= (MonoObject
*)info
;
843 return this_obj
? this_obj
->vtable
: NULL
;
848 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
851 mono_get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
853 MonoGenericContext context
= { NULL
, NULL
};
854 MonoClass
*klass
, *method_container_class
;
857 g_assert (generic_info
);
859 method
= jinfo_get_method (ji
);
860 g_assert (method
->is_inflated
);
861 if (mono_method_get_context (method
)->method_inst
) {
862 MonoMethodRuntimeGenericContext
*mrgctx
= (MonoMethodRuntimeGenericContext
*)generic_info
;
864 klass
= mrgctx
->class_vtable
->klass
;
865 context
.method_inst
= mrgctx
->method_inst
;
866 g_assert (context
.method_inst
);
868 MonoVTable
*vtable
= (MonoVTable
*)generic_info
;
870 klass
= vtable
->klass
;
873 //g_assert (!mono_class_is_gtd (method->klass));
874 if (mono_class_is_ginst (method
->klass
))
875 method_container_class
= mono_class_get_generic_class (method
->klass
)->container_class
;
877 method_container_class
= method
->klass
;
879 /* class might refer to a subclass of method's class */
880 while (!(klass
== method
->klass
|| (mono_class_is_ginst (klass
) && mono_class_get_generic_class (klass
)->container_class
== method_container_class
))) {
881 klass
= m_class_get_parent (klass
);
885 if (mono_class_is_ginst (klass
) || mono_class_is_gtd (klass
))
886 context
.class_inst
= mini_class_get_context (klass
)->class_inst
;
888 if (mono_class_is_ginst (klass
))
889 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass
)->container_class
, method_container_class
));
891 g_assert (mono_class_has_parent_and_ignore_generics (klass
, method_container_class
));
898 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
901 MonoGenericContext context
;
904 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
|| !generic_info
)
905 return jinfo_get_method (ji
);
906 context
= mono_get_generic_context_from_stack_frame (ji
, generic_info
);
908 method
= jinfo_get_method (ji
);
909 method
= mono_method_get_declaring_generic_method (method
);
910 method
= mono_class_inflate_generic_method_checked (method
, &context
, error
);
911 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
917 * mono_exception_walk_native_trace:
918 * \param ex The exception object whose frames should be walked
919 * \param func callback to call for each stack frame
920 * \param user_data data passed to the callback
921 * This function walks the stacktrace of an exception. For
922 * each frame the callback function is called with the relevant info.
923 * The walk ends when no more stack frames are found or when the callback
924 * returns a TRUE value.
928 mono_exception_walk_trace (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
932 MONO_ENTER_GC_UNSAFE
;
933 res
= mono_exception_walk_trace_internal (ex
, func
, user_data
);
939 mono_exception_stackframe_obj_walk (MonoStackFrame
*captured_frame
, MonoExceptionFrameWalk func
, gpointer user_data
)
944 gpointer ip
= (gpointer
) (captured_frame
->method_address
+ captured_frame
->native_offset
);
945 MonoJitInfo
*ji
= mono_jit_info_table_find_internal (mono_domain_get (), ip
, TRUE
, TRUE
);
947 // Other domain maybe?
950 MonoMethod
*method
= jinfo_get_method (ji
);
952 gboolean r
= func (method
, (gpointer
) captured_frame
->method_address
, captured_frame
->native_offset
, TRUE
, user_data
);
960 mono_exception_stacktrace_obj_walk (MonoStackTrace
*st
, MonoExceptionFrameWalk func
, gpointer user_data
)
962 int num_captured
= st
->captured_traces
? mono_array_length_internal (st
->captured_traces
) : 0;
963 for (int i
=0; i
< num_captured
; i
++) {
964 MonoStackTrace
*curr_trace
= mono_array_get_fast (st
->captured_traces
, MonoStackTrace
*, i
);
965 mono_exception_stacktrace_obj_walk (curr_trace
, func
, user_data
);
968 int num_frames
= st
->frames
? mono_array_length_internal (st
->frames
) : 0;
969 for (int frame
= 0; frame
< num_frames
; frame
++) {
970 gboolean r
= mono_exception_stackframe_obj_walk (mono_array_get_fast (st
->frames
, MonoStackFrame
*, frame
), func
, user_data
);
979 mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
981 MONO_REQ_GC_UNSAFE_MODE
;
983 MonoDomain
*domain
= mono_domain_get ();
984 MonoArray
*ta
= ex
->trace_ips
;
986 /* Exception is not thrown yet */
990 int len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
991 gboolean otherwise_has_traces
= len
> 0;
993 for (int i
= 0; i
< len
; i
++) {
994 ExceptionTraceIp trace_ip
;
996 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
997 gpointer ip
= trace_ip
.ip
;
998 gpointer generic_info
= trace_ip
.generic_info
;
1000 MonoJitInfo
*ji
= NULL
;
1004 ji
= mono_jit_info_table_find (domain
, ip
);
1010 r
= func (NULL
, ip
, 0, FALSE
, user_data
);
1015 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
1016 if (func (method
, ji
->code_start
, (char *) ip
- (char *) ji
->code_start
, TRUE
, user_data
))
1021 ta
= (MonoArray
*) ex
->captured_traces
;
1022 len
= ta
? mono_array_length_internal (ta
) : 0;
1023 gboolean captured_has_traces
= len
> 0;
1025 for (int i
= 0; i
< len
; i
++) {
1026 MonoStackTrace
*captured_trace
= mono_array_get_fast (ta
, MonoStackTrace
*, i
);
1027 if (!captured_trace
)
1030 mono_exception_stacktrace_obj_walk (captured_trace
, func
, user_data
);
1033 return captured_has_traces
|| otherwise_has_traces
;
1037 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
1040 MonoDomain
*domain
= mono_domain_get ();
1042 MonoArray
*ta
= exc
->trace_ips
;
1043 MonoDebugSourceLocation
*location
;
1047 /* Exception is not thrown yet */
1048 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, 0, error
);
1049 mono_error_set_pending_exception (error
);
1053 len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
1055 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0, error
);
1056 if (mono_error_set_pending_exception (error
))
1059 for (i
= skip
; i
< len
; i
++) {
1061 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
1062 if (!is_ok (error
)) {
1063 mono_error_set_pending_exception (error
);
1066 ExceptionTraceIp trace_ip
;
1067 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
1068 gpointer ip
= trace_ip
.ip
;
1069 gpointer generic_info
= trace_ip
.generic_info
;
1075 ji
= mono_jit_info_table_find (domain
, ip
);
1077 /* Unmanaged frame */
1078 mono_array_setref_internal (res
, i
, sf
);
1083 g_assert (ji
!= NULL
);
1085 if (mono_llvm_only
|| !generic_info
)
1086 /* Can't resolve actual method */
1087 method
= jinfo_get_method (ji
);
1089 method
= get_method_from_stack_frame (ji
, generic_info
);
1090 if (jinfo_get_method (ji
)->wrapper_type
) {
1094 s
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_REFLECTION
);
1095 MonoString
*name
= mono_string_new_checked (domain
, s
, error
);
1097 if (!is_ok (error
)) {
1098 mono_error_set_pending_exception (error
);
1101 MONO_OBJECT_SETREF_INTERNAL (sf
, internal_method_name
, name
);
1104 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
1105 if (!is_ok (error
)) {
1106 mono_error_set_pending_exception (error
);
1109 MONO_OBJECT_SETREF_INTERNAL (sf
, method
, rm
);
1112 sf
->method_index
= ji
->from_aot
? mono_aot_find_method_index (method
) : 0xffffff;
1113 sf
->method_address
= (gsize
) ji
->code_start
;
1114 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
1117 * mono_debug_lookup_source_location() returns both the file / line number information
1118 * and the IL offset. Note that computing the IL offset is already an expensive
1119 * operation, so we shouldn't call this method twice.
1121 location
= mono_debug_lookup_source_location (jinfo_get_method (ji
), sf
->native_offset
, domain
);
1123 sf
->il_offset
= location
->il_offset
;
1126 if (mono_find_prev_seq_point_for_native_offset (domain
, jinfo_get_method (ji
), sf
->native_offset
, NULL
, &sp
))
1127 sf
->il_offset
= sp
.il_offset
;
1132 if (need_file_info
) {
1133 if (location
&& location
->source_file
) {
1134 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1135 if (!is_ok (error
)) {
1136 mono_error_set_pending_exception (error
);
1139 MONO_OBJECT_SETREF_INTERNAL (sf
, filename
, filename
);
1140 sf
->line
= location
->row
;
1141 sf
->column
= location
->column
;
1143 sf
->line
= sf
->column
= 0;
1144 sf
->filename
= NULL
;
1148 mono_debug_free_source_location (location
);
1149 mono_array_setref_internal (res
, i
- skip
, sf
);
1156 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1159 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1160 if (jit_tls
&& jit_tls
->orig_ex_ctx_set
)
1161 start_ctx
= &jit_tls
->orig_ex_ctx
;
1163 mono_walk_stack_with_ctx (func
, start_ctx
, unwind_options
, user_data
);
1166 * mono_walk_stack_with_ctx:
1167 * Unwind the current thread starting at \p start_ctx.
1168 * If \p start_ctx is null, we capture the current context.
1171 mono_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1173 MonoContext extra_ctx
;
1174 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1175 MONO_ARCH_CONTEXT_DEF
1177 if (!thread
|| !thread
->jit_data
)
1181 mono_arch_flush_register_windows ();
1182 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx
, mono_walk_stack_with_ctx
);
1183 start_ctx
= &extra_ctx
;
1186 mono_walk_stack_full (func
, start_ctx
, mono_domain_get (), thread
->jit_data
, mono_get_lmf (), unwind_options
, user_data
, FALSE
);
1190 * mono_walk_stack_with_state:
1191 * Unwind a thread described by \p state.
1193 * State must be valid (state->valid == TRUE).
1195 * If you are using this function to unwind another thread, make sure it is suspended.
1197 * If \p state is null, we capture the current context.
1200 mono_walk_stack_with_state (MonoJitStackWalk func
, MonoThreadUnwindState
*state
, MonoUnwindOptions unwind_options
, void *user_data
)
1202 MonoThreadUnwindState extra_state
;
1204 g_assert (!mono_thread_info_is_async_context ());
1205 if (!mono_thread_state_init_from_current (&extra_state
))
1207 state
= &extra_state
;
1210 g_assert (state
->valid
);
1212 if (!state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
])
1216 mono_walk_stack_full (func
,
1218 (MonoDomain
*)state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
],
1219 (MonoJitTlsData
*)state
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
],
1220 (MonoLMF
*)state
->unwind_data
[MONO_UNWIND_DATA_LMF
],
1221 unwind_options
, user_data
, FALSE
);
1225 mono_walk_stack (MonoJitStackWalk func
, MonoUnwindOptions options
, void *user_data
)
1227 MonoThreadUnwindState state
;
1228 if (!mono_thread_state_init_from_current (&state
))
1230 mono_walk_stack_with_state (func
, &state
, options
, user_data
);
1234 * mono_walk_stack_full:
1235 * \param func callback to call for each stack frame
1236 * \param domain starting appdomain, can be NULL to use the current domain
1237 * \param unwind_options what extra information the unwinder should gather
1238 * \param start_ctx starting state of the stack walk, can be NULL.
1239 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1240 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1241 * \param user_data data passed to the callback
1242 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1243 * This function walks the stack of a thread, starting from the state
1244 * represented by \p start_ctx. For each frame the callback
1245 * function is called with the relevant info. The walk ends when no more
1246 * managed stack frames are found or when the callback returns a TRUE value.
1249 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
)
1252 MonoContext ctx
, new_ctx
;
1253 StackFrameInfo frame
;
1255 host_mgreg_t
*reg_locations
[MONO_MAX_IREGS
];
1256 host_mgreg_t
*new_reg_locations
[MONO_MAX_IREGS
];
1257 gboolean get_reg_locations
= unwind_options
& MONO_UNWIND_REG_LOCATIONS
;
1258 gboolean async
= mono_thread_info_is_async_context ();
1261 memset (&frame
, 0, sizeof (StackFrameInfo
));
1264 if (mono_llvm_only
) {
1270 ips
= get_unwind_backtrace ();
1271 for (l
= ips
; l
; l
= l
->next
) {
1272 guint8
*ip
= (guint8
*)l
->data
;
1273 memset (&frame
, 0, sizeof (StackFrameInfo
));
1274 frame
.ji
= mini_jit_info_table_find (domain
, ip
, &frame
.domain
);
1275 if (!frame
.ji
|| frame
.ji
->is_trampoline
)
1277 frame
.type
= FRAME_TYPE_MANAGED
;
1278 frame
.method
= jinfo_get_method (frame
.ji
);
1279 // FIXME: Cannot lookup the actual method
1280 frame
.actual_method
= frame
.method
;
1281 if (frame
.type
== FRAME_TYPE_MANAGED
) {
1282 if (!frame
.method
->wrapper_type
|| frame
.method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1283 frame
.managed
= TRUE
;
1285 frame
.native_offset
= ip
- (guint8
*)frame
.ji
->code_start
;
1286 frame
.il_offset
= -1;
1288 if (func (&frame
, NULL
, user_data
))
1297 g_warning ("start_ctx required for stack walk");
1302 g_warning ("domain required for stack walk");
1307 g_warning ("jit_tls required for stack walk");
1311 /*The LMF will be null if the target have no managed frames.*/
1312 /* g_assert (lmf); */
1313 if (async
&& (unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
)) {
1314 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1318 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
1319 memset (reg_locations
, 0, sizeof (reg_locations
));
1321 unwinder_init (&unwinder
);
1323 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
1325 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, get_reg_locations
? new_reg_locations
: NULL
, &frame
);
1329 if (frame
.type
== FRAME_TYPE_TRAMPOLINE
)
1332 if ((unwind_options
& MONO_UNWIND_LOOKUP_IL_OFFSET
) && frame
.ji
) {
1333 MonoDebugSourceLocation
*source
= NULL
;
1335 // Don't do this when we can be in a signal handler
1337 source
= mono_debug_lookup_source_location (jinfo_get_method (frame
.ji
), frame
.native_offset
, domain
);
1339 il_offset
= source
->il_offset
;
1341 MonoSeqPointInfo
*seq_points
= NULL
;
1343 // It's more reliable to look into the global cache if possible
1345 seq_points
= (MonoSeqPointInfo
*) frame
.ji
->seq_points
;
1347 seq_points
= mono_get_seq_points (domain
, jinfo_get_method (frame
.ji
));
1350 if (seq_points
&& mono_seq_point_find_prev_by_native_offset (seq_points
, frame
.native_offset
, &sp
))
1351 il_offset
= sp
.il_offset
;
1355 mono_debug_free_source_location (source
);
1359 frame
.il_offset
= il_offset
;
1361 if ((unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
) && frame
.ji
) {
1362 frame
.actual_method
= get_method_from_stack_frame (frame
.ji
, get_generic_info_from_stack_frame (frame
.ji
, &ctx
));
1364 frame
.actual_method
= frame
.method
;
1367 if (get_reg_locations
)
1368 frame
.reg_locations
= reg_locations
;
1370 if (func (&frame
, &ctx
, user_data
))
1374 if (get_reg_locations
) {
1375 for (int i
= 0; i
< MONO_MAX_IREGS
; ++i
)
1376 if (new_reg_locations
[i
])
1377 reg_locations
[i
] = new_reg_locations
[i
];
1384 #ifdef DISABLE_CRASH_REPORTING
1387 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1393 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1399 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1405 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1411 mono_crash_reporting_allow_all_native_libraries ()
1420 MonoFrameSummary
*frames
;
1423 MonoStackHash
*hashes
;
1425 } MonoSummarizeUserData
;
1428 copy_summary_string_safe (char *dest
, const char *src
)
1430 g_strlcpy (dest
, src
, MONO_MAX_SUMMARY_NAME_LEN
);
1434 fill_frame_managed_info (MonoFrameSummary
*frame
, MonoMethod
* method
)
1436 MonoImage
*image
= mono_class_get_image (method
->klass
);
1437 // Used for hashing, more stable across rebuilds than using GUID
1438 copy_summary_string_safe (frame
->str_descr
, image
->assembly_name
);
1440 frame
->managed_data
.guid
= image
->guid
;
1441 frame
->managed_data
.token
= method
->token
;
1442 frame
->managed_data
.filename
= image
->module_name
;
1444 MonoDotNetHeader
*header
= &image
->image_info
->cli_header
;
1445 frame
->managed_data
.image_size
= header
->nt
.pe_image_size
;
1446 frame
->managed_data
.time_date_stamp
= image
->time_date_stamp
;
1451 char *exported_name
;
1452 } MonoLibWhitelistEntry
;
1454 static GList
*native_library_whitelist
;
1455 static gboolean allow_all_native_libraries
= FALSE
;
1458 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1460 // Examples: libsystem_pthread.dylib -> "pthread"
1461 // Examples: libsystem_platform.dylib -> "platform"
1462 // Examples: mono-sgen -> "mono" from above line
1463 MonoLibWhitelistEntry
*entry
= g_new0 (MonoLibWhitelistEntry
, 1);
1464 entry
->suffix
= g_strdup (module_path
);
1465 entry
->exported_name
= g_strdup (module_name
);
1466 native_library_whitelist
= g_list_append (native_library_whitelist
, entry
);
1470 mono_crash_reporting_allow_all_native_libraries ()
1472 allow_all_native_libraries
= TRUE
;
1476 check_whitelisted_module (const char *in_name
, const char **out_module
)
1478 #ifndef MONO_PRIVATE_CRASHES
1481 if (g_str_has_suffix (in_name
, "mono-sgen")) {
1483 copy_summary_string_safe ((char *) *out_module
, "mono");
1486 if (allow_all_native_libraries
) {
1488 /* for a module name, use the basename of the full path in in_name */
1489 char *basename
= (char *) in_name
, *p
= (char *) in_name
;
1490 while (*p
!= '\0') {
1496 copy_summary_string_safe ((char *) *out_module
, basename
);
1498 copy_summary_string_safe ((char *) *out_module
, "unknown");
1504 for (GList
*cursor
= native_library_whitelist
; cursor
; cursor
= cursor
->next
) {
1505 MonoLibWhitelistEntry
*iter
= (MonoLibWhitelistEntry
*) cursor
->data
;
1506 if (!g_str_has_suffix (in_name
, iter
->suffix
))
1509 copy_summary_string_safe ((char *) *out_module
, iter
->exported_name
);
1518 mono_make_portable_ip (intptr_t in_ip
, intptr_t module_base
)
1520 // FIXME: Make generalize away from llvm tools?
1521 // So lldb starts the pointer base at 0x100000000
1522 // and expects to get pointers as (offset + constant)
1525 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1526 // *CoreSymbolicationDT.framework version: 63750*/
1527 intptr_t offset
= in_ip
- module_base
;
1528 intptr_t magic_value
= offset
+ 0x100000000;
1533 mono_get_portable_ip (intptr_t in_ip
, intptr_t *out_ip
, gint32
*out_offset
, const char **out_module
, char *out_name
)
1535 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1536 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1537 // non-recursive lock twice on this thread, and will deadlock.
1538 char sname
[256], fname
[256];
1539 void *saddr
= NULL
, *fbase
= NULL
;
1540 gboolean success
= g_module_address ((void*)in_ip
, fname
, 256, &fbase
, sname
, 256, &saddr
);
1544 if (!check_whitelisted_module (fname
, out_module
))
1547 *out_ip
= mono_make_portable_ip ((intptr_t) saddr
, (intptr_t) fbase
);
1548 *out_offset
= in_ip
- (intptr_t) saddr
;
1550 if (saddr
&& out_name
)
1551 copy_summary_string_safe (out_name
, sname
);
1556 summarize_offset_free_hash (guint64 accum
, MonoFrameSummary
*frame
)
1558 if (!frame
->is_managed
)
1561 // See: mono_ptrarray_hash
1562 guint64 hash_accum
= accum
;
1564 // The assembly and the method token, no offsets
1565 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1566 hash_accum
+= frame
->managed_data
.token
;
1572 summarize_offset_rich_hash (guint64 accum
, MonoFrameSummary
*frame
)
1574 // See: mono_ptrarray_hash
1575 guint64 hash_accum
= accum
;
1577 if (!frame
->is_managed
) {
1578 hash_accum
+= frame
->unmanaged_data
.ip
;
1580 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1581 hash_accum
+= frame
->managed_data
.token
;
1582 hash_accum
+= frame
->managed_data
.il_offset
;
1589 summarize_frame_internal (MonoMethod
*method
, gpointer ip
, size_t native_offset
, int il_offset
, gboolean managed
, gpointer user_data
)
1591 MonoSummarizeUserData
*ud
= (MonoSummarizeUserData
*) user_data
;
1593 gboolean valid_state
= ud
->num_frames
+ 1 < ud
->max_frames
;
1595 ud
->error
= "Exceeded the maximum number of frames";
1599 MonoFrameSummary
*dest
= &ud
->frames
[ud
->num_frames
];
1601 dest
->unmanaged_data
.ip
= (intptr_t) ip
;
1602 dest
->is_managed
= managed
;
1603 dest
->unmanaged_data
.module
[0] = '\0';
1605 if (!managed
&& method
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
&& method
->wrapper_type
< MONO_WRAPPER_NUM
) {
1606 dest
->is_managed
= FALSE
;
1607 dest
->unmanaged_data
.has_name
= TRUE
;
1608 copy_summary_string_safe (dest
->str_descr
, mono_wrapper_type_to_str (method
->wrapper_type
));
1611 #ifndef MONO_PRIVATE_CRASHES
1613 dest
->managed_data
.name
= (char *) method
->name
;
1618 ud
->error
= "Managed method frame, but no provided managed method";
1621 fill_frame_managed_info (dest
, method
);
1622 dest
->managed_data
.native_offset
= native_offset
;
1623 dest
->managed_data
.il_offset
= il_offset
;
1625 dest
->managed_data
.token
= -1;
1629 ud
->hashes
->offset_free_hash
= summarize_offset_free_hash (ud
->hashes
->offset_free_hash
, dest
);
1630 ud
->hashes
->offset_rich_hash
= summarize_offset_rich_hash (ud
->hashes
->offset_rich_hash
, dest
);
1632 // We return FALSE, so we're continuing walking
1633 // And we increment the pointer because we're done with this cell in the array
1639 summarize_frame_managed_walk (MonoMethod
*method
, gpointer ip
, size_t frame_native_offset
, gboolean managed
, gpointer user_data
)
1643 if (managed
&& method
) {
1644 MonoDebugSourceLocation
*location
= mono_debug_lookup_source_location (method
, frame_native_offset
, mono_domain_get ());
1646 il_offset
= location
->il_offset
;
1647 mono_debug_free_source_location (location
);
1651 intptr_t portable_ip
= 0;
1653 mono_get_portable_ip ((intptr_t) ip
, &portable_ip
, &offset
, NULL
, NULL
);
1655 return summarize_frame_internal (method
, (gpointer
) portable_ip
, frame_native_offset
, il_offset
, managed
, user_data
);
1660 summarize_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
1662 // Don't record trampolines between managed frames
1663 if (frame
->ji
&& frame
->ji
->is_trampoline
)
1666 if (frame
->ji
&& (frame
->ji
->is_trampoline
|| frame
->ji
->async
))
1667 return FALSE
; // Keep unwinding
1671 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx
), &ip
, &offset
, NULL
, NULL
);
1672 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1674 gboolean is_managed
= (frame
->type
== FRAME_TYPE_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP
);
1675 MonoMethod
*method
= NULL
;
1676 if (frame
&& frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
1677 method
= jinfo_get_method (frame
->ji
);
1680 method
= jinfo_get_method (frame
->ji
);
1682 return summarize_frame_internal (method
, (gpointer
) ip
, offset
, frame
->il_offset
, is_managed
, data
);
1686 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1688 memset (out
, 0, sizeof (MonoThreadSummary
));
1690 MonoException
*inner_exc
= exc
;
1693 for (exc_index
= 0; exc_index
< MONO_MAX_SUMMARY_EXCEPTIONS
; exc_index
++) {
1694 if (inner_exc
== NULL
)
1697 // Set up state to walk this MonoException's stack
1698 MonoSummarizeUserData data
;
1699 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1700 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1701 data
.num_frames
= 0;
1702 data
.frames
= out
->exceptions
[exc_index
].managed_frames
;
1704 // Accumulate all hashes from all exceptions in traveral order
1705 data
.hashes
= &out
->hashes
;
1707 mono_exception_walk_trace (inner_exc
, summarize_frame_managed_walk
, &data
);
1709 // Save per-MonoException info
1710 out
->exceptions
[exc_index
].managed_exc_type
= inner_exc
->object
.vtable
->klass
;
1711 out
->exceptions
[exc_index
].num_managed_frames
= data
.num_frames
;
1713 // Continue to traverse nesting of exceptions
1714 inner_exc
= (MonoException
*) inner_exc
->inner_ex
;
1717 out
->num_exceptions
= exc_index
;
1722 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1724 MonoSummarizeUserData data
;
1725 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1726 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1727 data
.num_frames
= 0;
1728 data
.frames
= out
->managed_frames
;
1729 data
.hashes
= &out
->hashes
;
1731 // FIXME: collect stack pointer for both and sort frames by SP
1732 // so people can see relative ordering of both managed and unmanaged frames.
1735 // Summarize managed stack
1737 mono_walk_stack_full (summarize_frame
, out
->ctx
, out
->domain
, out
->jit_tls
, out
->lmf
, MONO_UNWIND_LOOKUP_IL_OFFSET
, &data
, TRUE
);
1738 out
->num_managed_frames
= data
.num_frames
;
1740 if (data
.error
!= NULL
)
1741 out
->error_msg
= data
.error
;
1742 out
->is_managed
= (out
->num_managed_frames
!= 0);
1745 // Always runs on the dumped thread
1747 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1749 MONO_ARCH_CONTEXT_DEF
1751 // Summarize unmanaged stack
1753 #ifdef HAVE_BACKTRACE_SYMBOLS
1754 intptr_t frame_ips
[MONO_MAX_SUMMARY_FRAMES
];
1756 out
->num_unmanaged_frames
= backtrace ((void **)frame_ips
, MONO_MAX_SUMMARY_FRAMES
);
1758 for (int i
=0; i
< out
->num_unmanaged_frames
; ++i
) {
1759 intptr_t ip
= frame_ips
[i
];
1760 MonoFrameSummary
*frame
= &out
->unmanaged_frames
[i
];
1761 const char* module_buf
= frame
->unmanaged_data
.module
;
1762 int success
= mono_get_portable_ip (ip
, &frame
->unmanaged_data
.ip
, &frame
->unmanaged_data
.offset
, &module_buf
, (char *) frame
->str_descr
);
1764 /* attempt to look up any managed method at that ip */
1765 /* TODO: Trampolines - follow examples from mono_print_method_from_ip() */
1768 MonoDomain
*domain
= mono_domain_get ();
1769 MonoDomain
*target_domain
;
1770 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
1772 frame
->is_managed
= TRUE
;
1773 if (!ji
->async
&& !ji
->is_trampoline
) {
1774 MonoMethod
*method
= jinfo_get_method (ji
);
1775 fill_frame_managed_info (frame
, method
);
1776 #ifndef MONO_PRIVATE_CRASHES
1777 frame
->managed_data
.name
= method
->name
;
1782 if (!success
&& !ji
) {
1783 frame
->unmanaged_data
.ip
= ip
;
1787 if (out
->unmanaged_frames
[i
].str_descr
[0] != '\0')
1788 out
->unmanaged_frames
[i
].unmanaged_data
.has_name
= TRUE
;
1790 out
->hashes
.offset_free_hash
= summarize_offset_free_hash (out
->hashes
.offset_free_hash
, frame
);
1791 out
->hashes
.offset_rich_hash
= summarize_offset_rich_hash (out
->hashes
.offset_rich_hash
, frame
);
1795 out
->lmf
= mono_get_lmf ();
1797 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1798 out
->info_addr
= (intptr_t) thread
;
1799 out
->jit_tls
= thread
->jit_data
;
1800 out
->domain
= mono_domain_get ();
1803 out
->ctx
= &out
->ctx_mem
;
1804 mono_arch_flush_register_windows ();
1805 MONO_INIT_CONTEXT_FROM_FUNC (out
->ctx
, mono_summarize_unmanaged_stack
);
1814 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
1815 MonoReflectionMethod
**method
,
1816 gint32
*iloffset
, gint32
*native_offset
,
1817 MonoString
**file
, gint32
*line
, gint32
*column
)
1820 MonoDomain
*domain
= mono_domain_get ();
1821 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1822 MonoLMF
*lmf
= mono_get_lmf ();
1823 MonoJitInfo
*ji
= NULL
;
1824 MonoContext ctx
, new_ctx
;
1825 MonoDebugSourceLocation
*location
;
1826 MonoMethod
*jmethod
= NULL
, *actual_method
;
1827 StackFrameInfo frame
;
1832 MONO_ARCH_CONTEXT_DEF
;
1834 g_assert (skip
>= 0);
1836 if (mono_llvm_only
) {
1838 MonoDomain
*frame_domain
;
1839 guint8
*frame_ip
= NULL
;
1841 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1843 ips
= get_unwind_backtrace ();
1844 for (l
= ips
; l
&& skip
>= 0; l
= l
->next
) {
1845 guint8
*ip
= (guint8
*)l
->data
;
1849 ji
= mini_jit_info_table_find (mono_domain_get (), ip
, &frame_domain
);
1850 if (!ji
|| ji
->is_trampoline
)
1853 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1854 jmethod
= jinfo_get_method (ji
);
1855 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1862 /* No way to resolve generic instances */
1863 actual_method
= jmethod
;
1864 *native_offset
= frame_ip
- (guint8
*)ji
->code_start
;
1866 mono_arch_flush_register_windows ();
1867 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
1869 unwinder_init (&unwinder
);
1874 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
1877 switch (frame
.type
) {
1878 case FRAME_TYPE_MANAGED_TO_NATIVE
:
1879 case FRAME_TYPE_DEBUGGER_INVOKE
:
1880 case FRAME_TYPE_TRAMPOLINE
:
1881 case FRAME_TYPE_INTERP_TO_MANAGED
:
1882 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
1884 case FRAME_TYPE_INTERP
:
1885 case FRAME_TYPE_MANAGED
:
1887 *native_offset
= frame
.native_offset
;
1889 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1890 jmethod
= jinfo_get_method (ji
);
1891 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1896 g_assert_not_reached ();
1898 } while (skip
>= 0);
1900 if (frame
.type
== FRAME_TYPE_INTERP
) {
1901 jmethod
= frame
.method
;
1902 actual_method
= frame
.actual_method
;
1904 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &ctx
));
1908 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, actual_method
, NULL
, error
);
1909 if (!is_ok (error
)) {
1910 mono_error_set_pending_exception (error
);
1913 mono_gc_wbarrier_generic_store_internal (method
, (MonoObject
*) rm
);
1915 if (il_offset
!= -1) {
1916 location
= mono_debug_lookup_source_location_by_il (jmethod
, il_offset
, domain
);
1918 location
= mono_debug_lookup_source_location (jmethod
, *native_offset
, domain
);
1921 *iloffset
= location
->il_offset
;
1925 if (need_file_info
) {
1927 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1928 if (!is_ok (error
)) {
1929 mono_error_set_pending_exception (error
);
1932 mono_gc_wbarrier_generic_store_internal (file
, (MonoObject
*)filename
);
1933 *line
= location
->row
;
1934 *column
= location
->column
;
1937 *line
= *column
= 0;
1941 mono_debug_free_source_location (location
);
1947 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
1950 MonoClass
*catch_class
= ei
->data
.catch_class
;
1951 MonoType
*inflated_type
;
1952 MonoGenericContext context
;
1954 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1955 if (!catch_class
|| ei
->flags
!= MONO_EXCEPTION_CLAUSE_NONE
)
1958 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
1960 context
= mono_get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
1962 /* FIXME: we shouldn't inflate but instead put the
1963 type in the rgctx and fetch it from there. It
1964 might be a good idea to do this lazily, i.e. only
1965 when the exception is actually thrown, so as not to
1966 waste space for exception clauses which might never
1968 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
1969 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1971 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
1972 mono_metadata_free_type (inflated_type
);
1978 * mini_jit_info_table_find_ext:
1980 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1981 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1982 * OUT_DOMAIN if it is not NULL.
1985 mini_jit_info_table_find_ext (MonoDomain
*domain
, gpointer addr
, gboolean allow_trampolines
, MonoDomain
**out_domain
)
1988 MonoInternalThread
*t
= mono_thread_internal_current ();
1994 ji
= mono_jit_info_table_find_internal (domain
, addr
, TRUE
, allow_trampolines
);
1997 *out_domain
= domain
;
2001 /* maybe it is shared code, so we also search in the root domain */
2002 if (domain
!= mono_get_root_domain ()) {
2003 ji
= mono_jit_info_table_find_internal (mono_get_root_domain (), addr
, TRUE
, allow_trampolines
);
2006 *out_domain
= mono_get_root_domain ();
2014 refs
= (gpointer
*)((t
->appdomain_refs
) ? *(gpointer
*) t
->appdomain_refs
: NULL
);
2015 for (; refs
&& *refs
; refs
++) {
2016 if (*refs
!= domain
&& *refs
!= mono_get_root_domain ()) {
2017 ji
= mono_jit_info_table_find_internal ((MonoDomain
*) *refs
, addr
, TRUE
, allow_trampolines
);
2020 *out_domain
= (MonoDomain
*) *refs
;
2030 mini_jit_info_table_find (MonoDomain
*domain
, gpointer addr
, MonoDomain
**out_domain
)
2032 return mini_jit_info_table_find_ext (domain
, addr
, FALSE
, out_domain
);
2035 /* Class lazy loading functions */
2036 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr
, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
2039 * wrap_non_exception_throws:
2041 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
2042 * WrapNonExceptionThrows flag set.
2045 wrap_non_exception_throws (MonoMethod
*m
)
2048 MonoAssembly
*ass
= m_class_get_image (m
->klass
)->assembly
;
2049 MonoCustomAttrInfo
* attrs
;
2052 gboolean val
= FALSE
;
2054 if (m
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
2055 MonoDynamicMethod
*dm
= (MonoDynamicMethod
*)m
;
2060 if (ass
->wrap_non_exception_throws_inited
)
2061 return ass
->wrap_non_exception_throws
;
2063 klass
= mono_class_get_runtime_compat_attr_class ();
2065 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
2066 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2068 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
2069 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
2071 int num_named
, named_type
, name_len
;
2074 if (!attr
->ctor
|| attr
->ctor
->klass
!= klass
)
2076 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2077 p
= (const char*)attr
->data
;
2078 g_assert (read16 (p
) == 0x0001);
2080 num_named
= read16 (p
);
2086 /* data_type = *p; */
2089 if (named_type
!= 0x54)
2091 name_len
= mono_metadata_decode_blob_size (p
, &p
);
2092 name
= (char *)g_malloc (name_len
+ 1);
2093 memcpy (name
, p
, name_len
);
2094 name
[name_len
] = 0;
2096 g_assert (!strcmp (name
, "WrapNonExceptionThrows"));
2098 /* The value is a BOOLEAN */
2101 mono_custom_attrs_free (attrs
);
2104 ass
->wrap_non_exception_throws
= val
;
2105 mono_memory_barrier ();
2106 ass
->wrap_non_exception_throws_inited
= TRUE
;
2111 #define MAX_UNMANAGED_BACKTRACE 128
2113 build_native_trace (MonoError
*error
)
2116 /* This puppy only makes sense on mobile, IOW, ARM. */
2117 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2119 void *native_trace
[MAX_UNMANAGED_BACKTRACE
];
2122 size
= backtrace (native_trace
, MAX_UNMANAGED_BACKTRACE
);
2128 res
= mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, size
, error
);
2129 return_val_if_nok (error
, NULL
);
2131 for (i
= 0; i
< size
; i
++)
2132 mono_array_set_internal (res
, gpointer
, i
, native_trace
[i
]);
2140 remove_wrappers_from_trace (GList
**trace_ips_p
)
2142 GList
*trace_ips
= *trace_ips_p
;
2143 GList
*p
= trace_ips
;
2145 /* jit info, generic info, ip */
2147 MonoJitInfo
*jinfo
= (MonoJitInfo
*) p
->data
;
2148 GList
*next_p
= p
->next
->next
->next
;
2149 /* FIXME Maybe remove more wrapper types */
2150 if (jinfo
->d
.method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2151 trace_ips
= g_list_delete_link (trace_ips
, p
->next
->next
);
2152 trace_ips
= g_list_delete_link (trace_ips
, p
->next
);
2153 trace_ips
= g_list_delete_link (trace_ips
, p
);
2158 *trace_ips_p
= trace_ips
;
2161 /* This can be called more than once on a MonoException. */
2163 setup_stack_trace (MonoException
*mono_ex
, GSList
**dynamic_methods
, GList
*trace_ips
, gboolean remove_wrappers
)
2166 GList
*trace_ips_copy
= g_list_copy (trace_ips
);
2167 if (remove_wrappers
)
2168 remove_wrappers_from_trace (&trace_ips_copy
);
2169 trace_ips_copy
= g_list_reverse (trace_ips_copy
);
2171 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips_copy
, mono_defaults
.int_class
, error
);
2172 mono_error_assert_ok (error
);
2173 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
2174 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, native_trace_ips
, build_native_trace (error
));
2175 mono_error_assert_ok (error
);
2176 if (*dynamic_methods
) {
2177 /* These methods could go away anytime, so save a reference to them in the exception object */
2179 MonoMList
*list
= (MonoMList
*)mono_ex
->dynamic_methods
;
2181 for (l
= *dynamic_methods
; l
; l
= l
->next
) {
2183 MonoDomain
*domain
= mono_domain_get ();
2185 if (domain
->method_to_dyn_method
) {
2186 mono_domain_lock (domain
);
2187 dis_link
= (guint32
)(size_t)g_hash_table_lookup (domain
->method_to_dyn_method
, l
->data
);
2188 mono_domain_unlock (domain
);
2190 MonoObject
*o
= mono_gchandle_get_target_internal (dis_link
);
2192 list
= mono_mlist_prepend_checked (list
, o
, error
);
2193 mono_error_assert_ok (error
);
2199 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, dynamic_methods
, list
);
2201 g_slist_free (*dynamic_methods
);
2202 *dynamic_methods
= NULL
;
2205 g_list_free (trace_ips_copy
);
2210 MONO_FIRST_PASS_UNHANDLED
,
2211 MONO_FIRST_PASS_CALLBACK_TO_NATIVE
,
2212 MONO_FIRST_PASS_HANDLED
,
2213 } MonoFirstPassResult
;
2216 * handle_exception_first_pass:
2218 * The first pass of exception handling. Unwind the stack until a catch
2219 * clause which can catch OBJ is found. Store the index of the filter clause
2220 * which caught the exception into OUT_FILTER_IDX. Return
2221 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2222 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2223 * wrapper and an exception handling callback is installed (in which case
2224 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2226 static MonoFirstPassResult
2227 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
)
2230 MonoDomain
*domain
= mono_domain_get ();
2231 MonoJitInfo
*ji
= NULL
;
2232 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2233 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2234 MonoLMF
*lmf
= mono_get_lmf ();
2235 GList
*trace_ips
= NULL
;
2236 GSList
*dynamic_methods
= NULL
;
2237 MonoException
*mono_ex
;
2238 gboolean stack_overflow
= FALSE
;
2239 MonoContext initial_ctx
;
2241 int frame_count
= 0;
2248 MonoFirstPassResult result
= MONO_FIRST_PASS_UNHANDLED
;
2250 g_assert (ctx
!= NULL
);
2251 *last_mono_wrapper_runtime_invoke
= TRUE
;
2252 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2253 stack_overflow
= TRUE
;
2255 mono_ex
= (MonoException
*)obj
;
2256 MonoArray
*initial_trace_ips
= mono_ex
->trace_ips
;
2257 if (initial_trace_ips
) {
2258 int len
= mono_array_length_internal (initial_trace_ips
) / TRACE_IP_ENTRY_SIZE
;
2260 // If we catch in managed/non-wrapper, we don't save the catching frame
2261 if (!mono_ex
->caught_in_unmanaged
)
2264 for (i
= 0; i
< len
; i
++) {
2265 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
2266 gpointer p
= mono_array_get_internal (initial_trace_ips
, gpointer
, (i
* TRACE_IP_ENTRY_SIZE
) + j
);
2267 trace_ips
= g_list_prepend (trace_ips
, p
);
2272 // Reset the state because we're making it be caught somewhere
2273 if (mono_ex
->caught_in_unmanaged
)
2274 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, caught_in_unmanaged
, 0);
2276 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2277 mono_error_assert_ok (error
);
2282 call_filter
= (int (*) (MonoContext
*, void *))mono_get_call_filter ();
2284 g_assert (jit_tls
->end_of_stack
);
2285 g_assert (jit_tls
->abort_func
);
2288 *out_filter_idx
= -1;
2292 *out_prev_ji
= NULL
;
2296 unwinder_init (&unwinder
);
2299 MonoContext new_ctx
;
2301 int clause_index_start
= 0;
2302 gboolean unwind_res
= TRUE
;
2304 StackFrameInfo frame
;
2309 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2311 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2312 g_list_free (trace_ips
);
2316 switch (frame
.type
) {
2317 case FRAME_TYPE_DEBUGGER_INVOKE
:
2318 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2319 case FRAME_TYPE_TRAMPOLINE
:
2320 case FRAME_TYPE_INTERP_TO_MANAGED
:
2321 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2324 case FRAME_TYPE_INTERP
:
2325 case FRAME_TYPE_MANAGED
:
2328 g_assert_not_reached ();
2332 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2337 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2339 ip
= MONO_CONTEXT_GET_IP (ctx
);
2342 method
= jinfo_get_method (ji
);
2343 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2345 if (mini_debug_options
.reverse_pinvoke_exceptions
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2346 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2347 "The native frame called the managed method:\n%s\n",
2348 mono_method_full_name (method
, TRUE
));
2351 if (method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
2352 // avoid giant stack traces during a stack overflow
2353 if (frame_count
< 1000) {
2354 trace_ips
= g_list_prepend (trace_ips
, ip
);
2355 trace_ips
= g_list_prepend (trace_ips
, get_generic_info_from_stack_frame (ji
, ctx
));
2356 trace_ips
= g_list_prepend (trace_ips
, ji
);
2360 if (method
->dynamic
)
2361 dynamic_methods
= g_slist_prepend (dynamic_methods
, method
);
2363 if (stack_overflow
) {
2364 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2366 free_stack
= 0xffffff;
2369 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2370 result
= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
;
2374 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2375 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2376 gboolean filtered
= FALSE
;
2379 * During stack overflow, wait till the unwinding frees some stack
2380 * space before running handlers/finalizers.
2382 if (free_stack
<= (64 * 1024))
2385 if (is_address_protected (ji
, ei
, ip
)) {
2387 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2390 * Have to unwrap RuntimeWrappedExceptions if the
2391 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2393 if (non_exception
&& !wrap_non_exception_throws (method
))
2394 ex_obj
= non_exception
;
2398 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2399 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2401 #ifndef DISABLE_PERFCOUNTERS
2402 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_filters
);
2405 if (!ji
->is_interp
) {
2406 #ifndef MONO_CROSS_COMPILE
2407 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2409 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2411 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2412 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2414 g_assert (!ji
->from_llvm
);
2415 /* store the exception object in bp + ei->exvar_offset */
2416 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2420 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2422 * Pass the original il clause index to the landing pad so it can
2423 * branch to the landing pad associated with the il clause.
2424 * This is needed because llvm compiled code assumes that the EH
2425 * code always branches to the innermost landing pad.
2428 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2432 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2434 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2435 jit_tls
->orig_ex_ctx_set
= TRUE
;
2436 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2437 jit_tls
->orig_ex_ctx_set
= FALSE
;
2440 if (ji
->is_interp
) {
2441 /* The filter ends where the exception handler starts */
2442 filtered
= mini_get_interp_callbacks ()->run_filter (&frame
, (MonoException
*)ex_obj
, i
, ei
->data
.filter
, ei
->handler_start
);
2444 filtered
= call_filter (ctx
, ei
->data
.filter
);
2446 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2447 if (filtered
&& out_filter_idx
)
2448 *out_filter_idx
= filter_idx
;
2454 g_list_free (trace_ips
);
2455 /* mono_debugger_agent_handle_exception () needs this */
2456 mini_set_abort_threshold (&frame
);
2457 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2458 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2459 *catch_frame
= frame
;
2460 result
= MONO_FIRST_PASS_HANDLED
;
2465 ERROR_DECL (isinst_error
); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2466 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (ex_obj
, catch_class
, error
)) {
2467 /* runtime invokes catch even unhandled exceptions */
2468 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
);
2469 g_list_free (trace_ips
);
2474 /* mono_debugger_agent_handle_exception () needs this */
2476 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2477 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2478 *catch_frame
= frame
;
2479 result
= MONO_FIRST_PASS_HANDLED
;
2480 if (method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2481 //try to find threadpool_perform_wait_callback_method
2482 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &new_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2483 while (unwind_res
) {
2484 if (frame
.ji
&& !frame
.ji
->is_trampoline
&& jinfo_get_method (frame
.ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2485 *last_mono_wrapper_runtime_invoke
= FALSE
;
2488 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &new_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2493 mono_error_cleanup (isinst_error
);
2500 g_assert_not_reached ();
2504 * We implement delaying of aborts when in finally blocks by reusing the
2505 * abort protected block mechanism. The problem is that when throwing an
2506 * exception in a finally block we don't get to exit the protected block.
2507 * We exit it here when unwinding. Given that the order of the clauses
2508 * in the jit info is from inner clauses to the outer clauses, when we
2509 * want to exit the finally blocks inner to the clause that handles the
2510 * exception, we need to search up to its index.
2512 * FIXME We should do this inside interp, but with mixed mode we can
2513 * resume directly, without giving control back to the interp.
2516 interp_exit_finally_abort_blocks (MonoJitInfo
*ji
, int start_clause
, int end_clause
, gpointer ip
)
2519 for (i
= start_clause
; i
< end_clause
; i
++) {
2520 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2521 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
&&
2522 ip
>= ei
->handler_start
&&
2523 ip
< ei
->data
.handler_end
) {
2524 mono_threads_end_abort_protected_block ();
2529 static MonoException
*
2530 mono_get_exception_runtime_wrapped_checked (MonoObject
*wrapped_exception_raw
, MonoError
*error
)
2532 HANDLE_FUNCTION_ENTER ();
2533 MONO_HANDLE_DCL (MonoObject
, wrapped_exception
);
2534 MonoExceptionHandle ret
= mono_get_exception_runtime_wrapped_handle (wrapped_exception
, error
);
2535 HANDLE_FUNCTION_RETURN_OBJ (ret
);
2539 * mono_handle_exception_internal:
2540 * \param ctx saved processor state
2541 * \param obj the exception object
2542 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2545 mono_handle_exception_internal (MonoContext
*ctx
, MonoObject
*obj
, gboolean resume
, MonoJitInfo
**out_ji
)
2548 MonoDomain
*domain
= mono_domain_get ();
2549 MonoJitInfo
*ji
, *prev_ji
;
2550 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2551 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2552 MonoLMF
*lmf
= mono_get_lmf ();
2553 MonoException
*mono_ex
;
2554 gboolean stack_overflow
= FALSE
;
2555 MonoContext initial_ctx
;
2557 int frame_count
= 0;
2558 gint32 filter_idx
, first_filter_idx
= 0;
2560 MonoObject
*ex_obj
= NULL
;
2561 MonoObject
*non_exception
= NULL
;
2564 gboolean is_caught_unmanaged
= FALSE
;
2565 gboolean last_mono_wrapper_runtime_invoke
= TRUE
;
2567 g_assert (ctx
!= NULL
);
2569 MonoException
*ex
= mono_get_exception_null_reference ();
2570 MonoString
*msg
= mono_string_new_checked (domain
, "Object reference not set to an instance of an object", error
);
2571 mono_error_assert_ok (error
);
2572 MONO_OBJECT_SETREF_INTERNAL (ex
, message
, msg
);
2573 obj
= (MonoObject
*)ex
;
2577 * Allocate a new exception object instead of the preconstructed ones.
2579 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
) {
2581 * It is not a good idea to try and put even more pressure on the little stack available.
2582 * obj = mono_get_exception_stack_overflow ();
2584 stack_overflow
= TRUE
;
2586 else if (obj
== (MonoObject
*)domain
->null_reference_ex
) {
2587 obj
= (MonoObject
*)mono_get_exception_null_reference ();
2590 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2591 mono_error_assert_ok (error
);
2592 non_exception
= obj
;
2593 obj
= (MonoObject
*)mono_get_exception_runtime_wrapped_checked (obj
, error
);
2594 mono_error_assert_ok (error
);
2597 mono_ex
= (MonoException
*)obj
;
2599 if (mini_debug_options
.suspend_on_exception
) {
2600 mono_runtime_printf_err ("Exception thrown, suspending...");
2605 if (mono_ex
->caught_in_unmanaged
)
2606 is_caught_unmanaged
= TRUE
;
2609 if (mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2610 mono_ex
= (MonoException
*)obj
;
2612 mono_error_assert_ok (error
);
2616 if (mono_ex
&& jit_tls
->class_cast_from
) {
2617 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "InvalidCastException")) {
2618 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2619 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2620 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
2621 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2624 if (!is_ok (error
)) {
2625 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg
);
2626 mono_error_assert_ok (error
);
2630 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "ArrayTypeMismatchException")) {
2631 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2632 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2633 char *msg
= g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name
, to_name
);
2634 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2637 if (!is_ok (error
)) {
2638 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg
);
2639 mono_error_assert_ok (error
);
2646 call_filter
= (int (*)(MonoContext
*, void*))mono_get_call_filter ();
2648 g_assert (jit_tls
->end_of_stack
);
2649 g_assert (jit_tls
->abort_func
);
2652 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2653 * end up being TRUE on any code path.
2655 memcpy (&jit_tls
->orig_ex_ctx
, ctx
, sizeof (MonoContext
));
2658 MonoContext ctx_cp
= *ctx
;
2659 if (mono_trace_is_enabled ()) {
2661 MonoMethod
*system_exception_get_message
= mono_class_get_method_from_name_checked (mono_defaults
.exception_class
, "get_Message", 0, 0, error
);
2662 mono_error_cleanup (error
);
2664 MonoMethod
*get_message
= system_exception_get_message
== NULL
? NULL
: mono_object_get_virtual_method_internal (obj
, system_exception_get_message
);
2665 MonoObject
*message
;
2666 const char *type_name
= m_class_get_name (mono_object_class (mono_ex
));
2668 if (get_message
== NULL
) {
2670 } else if (!strcmp (type_name
, "OutOfMemoryException") || !strcmp (type_name
, "StackOverflowException")) {
2672 msg
= g_strdup_printf ("(No exception message for: %s)\n", type_name
);
2674 MonoObject
*exc
= NULL
;
2675 message
= mono_runtime_try_invoke (get_message
, obj
, NULL
, &exc
, error
);
2676 g_assert (exc
== NULL
);
2677 mono_error_assert_ok (error
);
2681 msg
= mono_string_to_utf8_checked_internal ((MonoString
*) message
, error
);
2682 if (!is_ok (error
)) {
2683 mono_error_cleanup (error
);
2684 msg
= g_strdup ("(error while display System.Exception.Message property)");
2687 msg
= g_strdup ("(System.Exception.Message property not available)");
2690 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
);
2692 if (mono_ex
&& mono_trace_eval_exception (mono_object_class (mono_ex
)))
2693 mono_print_thread_dump_from_ctx (ctx
);
2695 jit_tls
->orig_ex_ctx_set
= TRUE
;
2696 MONO_PROFILER_RAISE (exception_throw
, (obj
));
2697 jit_tls
->orig_ex_ctx_set
= FALSE
;
2699 StackFrameInfo catch_frame
;
2700 MonoFirstPassResult res
;
2701 res
= handle_exception_first_pass (&ctx_cp
, obj
, &first_filter_idx
, &ji
, &prev_ji
, non_exception
, &catch_frame
, &last_mono_wrapper_runtime_invoke
);
2703 if (res
== MONO_FIRST_PASS_UNHANDLED
) {
2704 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2705 /* Reached the top interpreted frames, but there might be native frames above us */
2706 throw_exception (obj
, TRUE
);
2707 g_assert_not_reached ();
2709 if (mini_debug_options
.break_on_exc
)
2711 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2713 // FIXME: This runs managed code so it might cause another stack overflow when
2714 // we are handling a stack overflow
2715 mini_set_abort_threshold (&catch_frame
);
2716 mono_unhandled_exception_internal (obj
);
2718 gboolean unhandled
= FALSE
;
2721 * The exceptions caught by the mono_runtime_invoke_checked () calls
2722 * in the threadpool needs to be treated as unhandled (#669836).
2724 * FIXME: The check below is hackish, but its hard to distinguish
2725 * these runtime invoke calls from others in the runtime.
2727 #ifndef ENABLE_NETCORE
2728 if (ji
&& jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2729 if (prev_ji
&& jinfo_get_method (prev_ji
) == mono_defaults
.threadpool_perform_wait_callback_method
)
2735 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2736 else if (!ji
|| (jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
)) {
2737 if (last_mono_wrapper_runtime_invoke
&& !mono_thread_internal_current ()->threadpool_thread
) {
2738 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2739 if (mini_get_debug_options ()->top_runtime_invoke_unhandled
) {
2740 mini_set_abort_threshold (&catch_frame
);
2741 mono_unhandled_exception_internal (obj
);
2744 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2747 else if (res
!= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
)
2748 if (!is_caught_unmanaged
)
2749 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2758 unwinder_init (&unwinder
);
2761 MonoContext new_ctx
;
2763 int clause_index_start
= 0;
2764 gboolean unwind_res
= TRUE
;
2765 StackFrameInfo frame
;
2770 ji
= jit_tls
->resume_state
.ji
;
2771 new_ctx
= jit_tls
->resume_state
.new_ctx
;
2772 clause_index_start
= jit_tls
->resume_state
.clause_index
;
2773 lmf
= jit_tls
->resume_state
.lmf
;
2774 first_filter_idx
= jit_tls
->resume_state
.first_filter_idx
;
2775 filter_idx
= jit_tls
->resume_state
.filter_idx
;
2778 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2780 *(mono_get_lmf_addr ()) = lmf
;
2782 jit_tls
->abort_func (obj
);
2783 g_assert_not_reached ();
2785 switch (frame
.type
) {
2786 case FRAME_TYPE_DEBUGGER_INVOKE
:
2787 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2788 case FRAME_TYPE_TRAMPOLINE
:
2789 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2792 case FRAME_TYPE_INTERP_TO_MANAGED
:
2794 case FRAME_TYPE_INTERP
:
2795 case FRAME_TYPE_MANAGED
:
2798 g_assert_not_reached ();
2801 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2806 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2808 ip
= MONO_CONTEXT_GET_IP (ctx
);
2810 method
= jinfo_get_method (ji
);
2812 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2814 if (stack_overflow
) {
2815 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2817 free_stack
= 0xffffff;
2820 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2821 guint32 handle
= mono_gchandle_new_internal (obj
, FALSE
);
2822 MONO_STACKDATA (stackptr
);
2824 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr
);
2826 ftnptr_eh_callback (handle
);
2827 g_error ("Did not expect ftnptr_eh_callback to return.");
2830 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2831 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2832 gboolean filtered
= FALSE
;
2835 * During stack overflow, wait till the unwinding frees some stack
2836 * space before running handlers/finalizers.
2838 if (free_stack
<= (64 * 1024))
2841 if (is_address_protected (ji
, ei
, ip
)) {
2843 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2846 * Have to unwrap RuntimeWrappedExceptions if the
2847 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2849 if (non_exception
&& !wrap_non_exception_throws (method
))
2850 ex_obj
= non_exception
;
2854 if (((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
))) {
2855 #ifndef MONO_CROSS_COMPILE
2856 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2857 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2859 g_assert (!ji
->from_llvm
);
2860 /* store the exception object in bp + ei->exvar_offset */
2861 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2866 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2868 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2871 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2873 * Filter clauses should only be run in the
2874 * first pass of exception handling.
2876 filtered
= (filter_idx
== first_filter_idx
);
2881 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
2882 mono_object_isinst_checked (ex_obj
, catch_class
, error
)) || filtered
) {
2884 * This guards against the situation that we abort a thread that is executing a finally clause
2885 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2886 * check for this situation here and resume interruption if we are below the guarded block.
2888 if (G_UNLIKELY (jit_tls
->handler_block
)) {
2889 gboolean is_outside
= FALSE
;
2890 gpointer prot_bp
= MONO_CONTEXT_GET_BP (&jit_tls
->handler_block_context
);
2891 gpointer catch_bp
= MONO_CONTEXT_GET_BP (ctx
);
2892 //FIXME make this stack direction aware
2894 if (catch_bp
> prot_bp
) {
2896 } else if (catch_bp
== prot_bp
) {
2897 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2898 * So we check if the catch handler_start is protected by the guarded handler protected region
2901 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2902 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2903 * There aren't any further finally/fault handler blocks down the stack over this exception.
2904 * This must be ensured by the code that installs the guard trampoline.
2906 g_assert (ji
== mini_jit_info_table_find (domain
, (char *)MONO_CONTEXT_GET_IP (&jit_tls
->handler_block_context
), NULL
));
2908 if (!is_address_protected (ji
, jit_tls
->handler_block
, ei
->handler_start
)) {
2913 jit_tls
->handler_block
= NULL
;
2914 mono_thread_resume_interruption (TRUE
); /*We ignore the exception here, it will be raised later*/
2918 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2919 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2922 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2923 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2924 * clause. Since we specifically want to indicate that we're executing the
2925 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2926 * instead of ei->flags.
2928 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2929 jit_tls
->orig_ex_ctx_set
= TRUE
;
2930 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, MONO_EXCEPTION_CLAUSE_NONE
, ex_obj
));
2931 jit_tls
->orig_ex_ctx_set
= FALSE
;
2934 mini_set_abort_threshold (&frame
);
2937 interp_exit_finally_abort_blocks (ji
, clause_index_start
, i
, ip
);
2939 * ctx->pc points into the interpreter, after the call which transitioned to
2940 * JITted code. Store the unwind state into the
2941 * interpeter state, then resume, the interpreter will unwind itself until
2942 * it reaches the target frame and will continue execution from there.
2943 * The resuming is kinda hackish, from the native code standpoint, it looks
2944 * like the call which transitioned to JITted code has succeeded, but the
2945 * return value register etc. is not set, so we have to be careful.
2947 mini_get_interp_callbacks ()->set_resume_state (jit_tls
, mono_ex
, ei
, frame
.interp_frame
, ei
->handler_start
);
2948 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2949 /* ip == 0 means an interpreter frame */
2950 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
2951 mono_arch_undo_ip_adjustment (ctx
);
2953 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2956 #ifndef DISABLE_PERFCOUNTERS
2957 mono_atomic_fetch_add_i32 (&mono_perfcounters
->exceptions_depth
, frame_count
);
2959 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2960 jit_tls
->handling_stack_ovf
= FALSE
;
2964 mono_error_cleanup (error
);
2965 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) {
2966 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2967 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2969 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2970 jit_tls
->orig_ex_ctx_set
= TRUE
;
2971 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2972 jit_tls
->orig_ex_ctx_set
= FALSE
;
2975 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2976 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2977 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2979 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2980 jit_tls
->orig_ex_ctx_set
= TRUE
;
2981 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2982 jit_tls
->orig_ex_ctx_set
= FALSE
;
2985 #ifndef DISABLE_PERFCOUNTERS
2986 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_finallys
);
2989 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
|| ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2991 if (ji
->from_llvm
) {
2993 * LLVM compiled finally handlers follow the design
2994 * of the c++ ehabi, i.e. they call a resume function
2995 * at the end instead of returning to the caller.
2996 * So save the exception handling state,
2997 * mono_resume_unwind () will call us again to continue
3000 jit_tls
->resume_state
.ex_obj
= obj
;
3001 jit_tls
->resume_state
.ji
= ji
;
3002 jit_tls
->resume_state
.clause_index
= i
+ 1;
3003 jit_tls
->resume_state
.ctx
= *ctx
;
3004 jit_tls
->resume_state
.new_ctx
= new_ctx
;
3005 jit_tls
->resume_state
.lmf
= lmf
;
3006 jit_tls
->resume_state
.first_filter_idx
= first_filter_idx
;
3007 jit_tls
->resume_state
.filter_idx
= filter_idx
;
3008 mini_set_abort_threshold (&frame
);
3009 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
3012 mini_set_abort_threshold (&frame
);
3014 gboolean has_ex
= mini_get_interp_callbacks ()->run_finally (&frame
, i
, ei
->handler_start
, ei
->data
.handler_end
);
3017 * If run_finally didn't resume to a context, it means that the handler frame
3018 * is linked to the frame calling finally through interpreter frames. This
3019 * means that we will reach the handler frame by resuming the current context.
3021 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
3022 mono_arch_undo_ip_adjustment (ctx
);
3026 call_filter (ctx
, ei
->handler_start
);
3034 interp_exit_finally_abort_blocks (ji
, clause_index_start
, ji
->num_clauses
, ip
);
3036 if (MONO_PROFILER_ENABLED (method_exception_leave
) &&
3037 mono_profiler_get_call_instrumentation_flags (method
) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
) {
3038 jit_tls
->orig_ex_ctx_set
= TRUE
;
3039 MONO_PROFILER_RAISE (method_exception_leave
, (method
, ex_obj
));
3040 jit_tls
->orig_ex_ctx_set
= FALSE
;
3046 g_assert_not_reached ();
3050 * mono_debugger_run_finally:
3051 * \param start_ctx saved processor state
3052 * This method is called by the Mono Debugger to call all \c finally clauses of the
3053 * current stack frame. It's used when the user issues a \c return command to make
3054 * the current stack frame return. After returning from this method, the debugger
3055 * unwinds the stack one frame and gives control back to the user.
3056 * NOTE: This method is only used when running inside the Mono Debugger.
3059 mono_debugger_run_finally (MonoContext
*start_ctx
)
3061 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
3062 MonoDomain
*domain
= mono_domain_get ();
3063 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3064 MonoLMF
*lmf
= mono_get_lmf ();
3065 MonoContext ctx
, new_ctx
;
3066 MonoJitInfo
*ji
, rji
;
3071 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
3072 if (!ji
|| ji
== (gpointer
)-1)
3076 call_filter
= (int (*)(MonoContext
*, void *))mono_get_call_filter ();
3078 for (i
= 0; i
< ji
->num_clauses
; i
++) {
3079 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
3081 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (&ctx
)) &&
3082 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
3083 call_filter (&ctx
, ei
->handler_start
);
3089 * mono_handle_exception:
3090 * \param ctx saved processor state
3091 * \param obj the exception object
3093 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3097 mono_handle_exception (MonoContext
*ctx
, gpointer void_obj
)
3099 MonoObject
*obj
= (MonoObject
*)void_obj
;
3101 MONO_REQ_GC_UNSAFE_MODE
;
3103 #ifndef DISABLE_PERFCOUNTERS
3104 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_thrown
);
3107 return mono_handle_exception_internal (ctx
, obj
, FALSE
, NULL
);
3110 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3112 #ifndef MONO_ARCH_USE_SIGACTION
3113 #error "Can't use sigaltstack without sigaction"
3117 mono_setup_altstack (MonoJitTlsData
*tls
)
3121 guint8
*staddr
= NULL
;
3122 #if defined(TARGET_OSX) || defined(_AIX)
3124 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3125 * stack pages. Stack overflow on main thread will kill the app.
3127 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3128 * do this for thread 1 with its stack at the top of memory. Other threads seem
3129 * fine for the altstack guard page, though.
3131 gboolean disable_stack_guard
= mono_threads_platform_is_main_thread ();
3133 gboolean disable_stack_guard
= FALSE
;
3136 if (mono_running_on_valgrind ())
3139 mono_thread_info_get_stack_bounds (&staddr
, &stsize
);
3143 tls
->end_of_stack
= staddr
+ stsize
;
3144 tls
->stack_size
= stsize
;
3146 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3148 if (!disable_stack_guard
) {
3149 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
3150 tls
->stack_ovf_guard_size
= ALIGN_TO (8 * 4096, mono_pagesize ());
3152 g_assert ((guint8
*)&sa
>= (guint8
*)tls
->stack_ovf_guard_base
+ tls
->stack_ovf_guard_size
);
3154 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
3155 /* mprotect can fail for the main thread stack */
3156 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
);
3158 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
3159 tls
->stack_ovf_valloced
= TRUE
;
3161 g_warning ("couldn't allocate guard page, continue without it");
3162 tls
->stack_ovf_guard_base
= NULL
;
3163 tls
->stack_ovf_guard_size
= 0;
3168 /* Setup an alternate signal stack */
3169 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
);
3170 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3172 g_assert (tls
->signal_stack
);
3174 sa
.ss_sp
= tls
->signal_stack
;
3175 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3177 g_assert (sigaltstack (&sa
, NULL
) == 0);
3179 if (tls
->stack_ovf_guard_base
)
3180 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
);
3182 mono_gc_register_altstack (staddr
, stsize
, tls
->signal_stack
, tls
->signal_stack_size
);
3187 mono_free_altstack (MonoJitTlsData
*tls
)
3192 sa
.ss_sp
= tls
->signal_stack
;
3193 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3194 sa
.ss_flags
= SS_DISABLE
;
3195 err
= sigaltstack (&sa
, NULL
);
3196 g_assert (err
== 0);
3198 if (tls
->signal_stack
)
3199 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3201 if (!tls
->stack_ovf_guard_base
)
3203 if (tls
->stack_ovf_valloced
)
3204 mono_vfree (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3206 mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3209 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3212 mono_setup_altstack (MonoJitTlsData
*tls
)
3217 mono_free_altstack (MonoJitTlsData
*tls
)
3221 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3224 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*siginfo
, guint8
* fault_addr
)
3232 /* we got a stack overflow in the soft-guard pages
3233 * There are two cases:
3234 * 1) managed code caused the overflow: we unprotect the soft-guard page
3235 * and let the arch-specific code trigger the exception handling mechanism
3236 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3237 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3238 * and hope we can continue with those enabled, at least until the hard-guard page
3239 * is hit. The alternative to continuing here is to just print a message and abort.
3240 * We may add in the future the code to protect the pages again in the codepath
3241 * when we return from unmanaged to managed code.
3243 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
3244 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
3245 gboolean handled
= FALSE
;
3247 mono_mprotect (jit_tls
->stack_ovf_guard_base
, jit_tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3248 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3250 mono_arch_handle_altstack_exception (ctx
, siginfo
, fault_addr
, TRUE
);
3255 /* We print a message: after this even managed stack overflows
3256 * may crash the runtime
3258 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx
), fault_addr
);
3259 if (!jit_tls
->handling_stack_ovf
) {
3260 jit_tls
->handling_stack_ovf
= 1;
3262 /*fprintf (stderr, "Already handling stack overflow\n");*/
3271 MonoMethod
*omethod
;
3273 } PrintOverflowUserData
;
3276 print_overflow_stack_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3278 MonoMethod
*method
= NULL
;
3279 PrintOverflowUserData
*user_data
= (PrintOverflowUserData
*)data
;
3282 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3283 method
= jinfo_get_method (frame
->ji
);
3286 if (user_data
->count
== 0) {
3287 /* The first frame is in its prolog, so a line number cannot be computed */
3288 user_data
->count
++;
3292 /* If this is a one method overflow, skip the other instances */
3293 if (method
== user_data
->omethod
)
3296 location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, mono_domain_get ());
3297 mono_runtime_printf_err (" %s", location
);
3300 if (user_data
->count
== 1) {
3301 mono_runtime_printf_err (" <...>");
3302 user_data
->omethod
= method
;
3304 user_data
->omethod
= NULL
;
3307 user_data
->count
++;
3309 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame
->native_offset
);
3315 mono_handle_hard_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, MonoContext
*mctx
, guint8
* fault_addr
)
3317 PrintOverflowUserData ud
;
3319 /* we don't do much now, but we can warn the user with a useful message */
3320 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx
), fault_addr
);
3322 mono_runtime_printf_err ("Stacktrace:");
3324 memset (&ud
, 0, sizeof (ud
));
3326 mono_walk_stack_with_ctx (print_overflow_stack_frame
, mctx
, MONO_UNWIND_LOOKUP_ACTUAL_METHOD
, &ud
);
3332 print_stack_frame_signal_safe (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3334 MonoMethod
*method
= NULL
;
3336 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3337 method
= jinfo_get_method (frame
->ji
);
3340 const char *name_space
= m_class_get_name_space (method
->klass
);
3341 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
);
3343 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame
->native_offset
);
3349 static G_GNUC_UNUSED gboolean
3350 print_stack_frame_to_string (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3352 GString
*p
= (GString
*)data
;
3353 MonoMethod
*method
= NULL
;
3355 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3356 method
= jinfo_get_method (frame
->ji
);
3358 if (method
&& frame
->domain
) {
3359 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
3360 g_string_append_printf (p
, " %s\n", location
);
3363 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
3368 #ifndef MONO_CROSS_COMPILE
3371 * mono_handle_native_crash:
3373 * Handle a native crash (e.g. SIGSEGV) while in native code by
3374 * printing diagnostic information and aborting.
3377 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3379 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3381 #ifdef MONO_ARCH_USE_SIGACTION
3382 struct sigaction sa
;
3383 sa
.sa_handler
= SIG_DFL
;
3384 sigemptyset (&sa
.sa_mask
);
3387 /* Remove our SIGABRT handler */
3388 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
3390 /* On some systems we get a SIGILL when calling abort (), because it might
3391 * fail to raise SIGABRT */
3392 g_assert (sigaction (SIGILL
, &sa
, NULL
) != -1);
3394 /* Remove SIGCHLD, it uses the finalizer thread */
3395 g_assert (sigaction (SIGCHLD
, &sa
, NULL
) != -1);
3397 /* Remove SIGQUIT, we are already dumping threads */
3398 g_assert (sigaction (SIGQUIT
, &sa
, NULL
) != -1);
3402 if (mini_debug_options
.suspend_on_native_crash
) {
3403 g_async_safe_printf ("Received %s, suspending...\n", signal
);
3405 // Sleep for 1 second.
3406 g_usleep (1000 * 1000);
3411 * A crash 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
= mono_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 ();