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/metadata/handle.h>
65 #include <mono/utils/mono-merp.h>
66 #include <mono/utils/mono-mmap.h>
67 #include <mono/utils/mono-logger-internals.h>
68 #include <mono/utils/mono-error.h>
69 #include <mono/utils/mono-error-internals.h>
70 #include <mono/utils/mono-state.h>
71 #include <mono/utils/mono-threads-debug.h>
72 #include <mono/utils/w32subset.h>
76 #include "debugger-agent.h"
77 #include "debugger-engine.h"
78 #include "seq-points.h"
79 #include "llvm-runtime.h"
80 #include "mini-llvm.h"
81 #include "aot-runtime.h"
82 #include "mini-runtime.h"
83 #include "interp/interp.h"
86 #include "mini-llvm-cpp.h"
93 #ifndef MONO_ARCH_CONTEXT_DEF
94 #define MONO_ARCH_CONTEXT_DEF
97 #if !defined(DISABLE_CRASH_REPORTING)
100 #include "mono/utils/mono-tls-inline.h"
103 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
104 * This structure represents one entry.
105 * This should consists of pointers only.
110 gpointer generic_info
;
111 /* Only for interpreter frames */
115 /* Number of words in trace_ips belonging to one entry */
116 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
118 static gpointer restore_context_func
, call_filter_func
;
119 static gpointer throw_exception_func
, rethrow_exception_func
, rethrow_preserve_exception_func
;
120 static gpointer throw_corlib_exception_func
;
122 static MonoFtnPtrEHCallback ftnptr_eh_callback
;
124 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
);
125 static void mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
);
126 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
);
127 static gboolean
mono_current_thread_has_handle_block_guard (void);
128 static gboolean
mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
);
129 static void mono_uninstall_current_handler_block_guard (void);
130 static gboolean
mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
);
131 static void throw_exception (MonoObject
*ex
, gboolean rethrow
);
133 static void mono_summarize_managed_stack (MonoThreadSummary
*out
);
134 static void mono_summarize_unmanaged_stack (MonoThreadSummary
*out
);
135 static void mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
);
136 static void mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
);
137 static void mono_crash_reporting_allow_all_native_libraries (void);
140 first_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer addr
)
142 gpointer
*data
= (gpointer
*)addr
;
148 // FIXME: Happens with llvm_only
153 *data
= frame
->frame_addr
;
159 mono_thread_get_managed_sp (void)
161 gpointer addr
= NULL
;
162 mono_walk_stack (first_managed
, MONO_UNWIND_SIGNAL_SAFE
, &addr
);
167 mini_clear_abort_threshold (void)
169 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
170 jit_tls
->abort_exc_stack_threshold
= NULL
;
174 mini_set_abort_threshold (StackFrameInfo
*frame
)
176 gpointer sp
= frame
->frame_addr
;
177 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
178 // Only move it up, to avoid thrown/caught
179 // exceptions lower in the stack from triggering
181 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
182 if (!jit_tls
->abort_exc_stack_threshold
|| above_threshold
) {
183 jit_tls
->abort_exc_stack_threshold
= sp
;
187 // Note: In the case that the frame is above where the thread abort
188 // was set we bump the threshold so that functions called from the new,
189 // higher threshold don't trigger the thread abort exception
191 mini_above_abort_threshold (void)
193 gpointer sp
= mono_thread_get_managed_sp ();
194 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
199 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
202 jit_tls
->abort_exc_stack_threshold
= sp
;
204 return above_threshold
;
208 mono_get_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
211 if (mono_find_prev_seq_point_for_native_offset (domain
, method
, native_offset
, NULL
, &sp
))
217 mono_exceptions_init (void)
219 MonoRuntimeExceptionHandlingCallbacks cbs
;
220 if (mono_ee_features
.use_aot_trampolines
) {
221 restore_context_func
= mono_aot_get_trampoline ("restore_context");
222 call_filter_func
= mono_aot_get_trampoline ("call_filter");
223 throw_exception_func
= mono_aot_get_trampoline ("throw_exception");
224 rethrow_exception_func
= mono_aot_get_trampoline ("rethrow_exception");
225 rethrow_preserve_exception_func
= mono_aot_get_trampoline ("rethrow_preserve_exception");
226 } else if (!mono_llvm_only
) {
229 restore_context_func
= mono_arch_get_restore_context (&info
, FALSE
);
230 mono_tramp_info_register (info
, NULL
);
231 call_filter_func
= mono_arch_get_call_filter (&info
, FALSE
);
232 mono_tramp_info_register (info
, NULL
);
233 throw_exception_func
= mono_arch_get_throw_exception (&info
, FALSE
);
234 mono_tramp_info_register (info
, NULL
);
235 rethrow_exception_func
= mono_arch_get_rethrow_exception (&info
, FALSE
);
236 mono_tramp_info_register (info
, NULL
);
237 rethrow_preserve_exception_func
= mono_arch_get_rethrow_preserve_exception (&info
, FALSE
);
238 mono_tramp_info_register (info
, NULL
);
241 mono_arch_exceptions_init ();
243 cbs
.mono_walk_stack_with_ctx
= mono_runtime_walk_stack_with_ctx
;
244 cbs
.mono_walk_stack_with_state
= mono_walk_stack_with_state
;
245 cbs
.mono_summarize_managed_stack
= mono_summarize_managed_stack
;
246 cbs
.mono_summarize_unmanaged_stack
= mono_summarize_unmanaged_stack
;
247 cbs
.mono_summarize_exception
= mono_summarize_exception
;
248 cbs
.mono_register_native_library
= mono_crash_reporting_register_native_library
;
249 cbs
.mono_allow_all_native_libraries
= mono_crash_reporting_allow_all_native_libraries
;
251 if (mono_llvm_only
) {
252 cbs
.mono_raise_exception
= mono_llvm_raise_exception
;
253 cbs
.mono_reraise_exception
= mono_llvm_reraise_exception
;
255 cbs
.mono_raise_exception
= (void (*)(MonoException
*))mono_get_throw_exception ();
256 cbs
.mono_reraise_exception
= (void (*)(MonoException
*))mono_get_rethrow_exception ();
258 cbs
.mono_raise_exception_with_ctx
= mono_raise_exception_with_ctx
;
259 cbs
.mono_exception_walk_trace
= mono_exception_walk_trace
;
260 cbs
.mono_install_handler_block_guard
= mono_install_handler_block_guard
;
261 cbs
.mono_uninstall_current_handler_block_guard
= mono_uninstall_current_handler_block_guard
;
262 cbs
.mono_current_thread_has_handle_block_guard
= mono_current_thread_has_handle_block_guard
;
263 cbs
.mono_clear_abort_threshold
= mini_clear_abort_threshold
;
264 cbs
.mono_above_abort_threshold
= mini_above_abort_threshold
;
265 mono_install_eh_callbacks (&cbs
);
266 mono_install_get_seq_point (mono_get_seq_point_for_native_offset
);
270 mono_get_throw_exception (void)
272 g_assert (throw_exception_func
);
273 return throw_exception_func
;
277 mono_get_rethrow_exception (void)
279 g_assert (rethrow_exception_func
);
280 return rethrow_exception_func
;
284 mono_get_rethrow_preserve_exception (void)
286 g_assert (rethrow_preserve_exception_func
);
287 return rethrow_preserve_exception_func
;
291 no_call_filter (void)
293 g_assert_not_reached ();
297 mono_get_call_filter (void)
299 /* This is called even in llvmonly mode etc. */
300 if (!call_filter_func
)
301 return (gpointer
)no_call_filter
;
302 return call_filter_func
;
306 mono_get_restore_context (void)
308 g_assert (restore_context_func
);
309 return restore_context_func
;
313 mono_get_throw_corlib_exception (void)
315 gpointer code
= NULL
;
318 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
319 if (throw_corlib_exception_func
)
320 return throw_corlib_exception_func
;
322 if (mono_ee_features
.use_aot_trampolines
)
323 code
= mono_aot_get_trampoline ("throw_corlib_exception");
325 code
= mono_arch_get_throw_corlib_exception (&info
, FALSE
);
326 mono_tramp_info_register (info
, NULL
);
329 mono_memory_barrier ();
331 throw_corlib_exception_func
= code
;
333 return throw_corlib_exception_func
;
337 * mono_get_throw_exception_addr:
339 * Return an address which stores the result of
340 * mono_get_throw_exception.
343 mono_get_throw_exception_addr (void)
345 return &throw_exception_func
;
349 mono_get_rethrow_preserve_exception_addr (void)
351 return &rethrow_preserve_exception_func
;
355 is_address_protected (MonoJitInfo
*ji
, MonoJitExceptionInfo
*ei
, gpointer ip
)
357 MonoTryBlockHoleTableJitInfo
*table
;
362 if (ei
->try_start
> ip
|| ip
>= ei
->try_end
)
365 if (!ji
->has_try_block_holes
)
368 table
= mono_jit_info_get_try_block_hole_table_info (ji
);
369 offset
= (guint32
)((char*)ip
- (char*)ji
->code_start
);
370 clause
= (guint16
)(ei
- ji
->clauses
);
371 g_assert (clause
< ji
->num_clauses
);
373 for (i
= 0; i
< table
->num_holes
; ++i
) {
374 MonoTryBlockHoleJitInfo
*hole
= &table
->holes
[i
];
375 if (hole
->clause
== clause
&& hole
->offset
<= offset
&& hole
->offset
+ hole
->length
> offset
)
381 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
384 static gboolean show_native_addresses
= TRUE
;
386 static gboolean show_native_addresses
= FALSE
;
389 static _Unwind_Reason_Code
390 build_stack_trace (struct _Unwind_Context
*frame_ctx
, void *state
)
392 MonoDomain
*domain
= mono_domain_get ();
393 uintptr_t ip
= _Unwind_GetIP (frame_ctx
);
395 if (show_native_addresses
|| mono_jit_info_table_find (domain
, (char*)ip
)) {
396 GList
**trace_ips
= (GList
**)state
;
397 *trace_ips
= g_list_prepend (*trace_ips
, (gpointer
)ip
);
400 return _URC_NO_REASON
;
404 get_unwind_backtrace (void)
408 _Unwind_Backtrace (build_stack_trace
, &ips
);
410 return g_slist_reverse (ips
);
416 get_unwind_backtrace (void)
424 arch_unwind_frame (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
425 MonoJitInfo
*ji
, MonoContext
*ctx
,
426 MonoContext
*new_ctx
, MonoLMF
**lmf
,
427 host_mgreg_t
**save_locations
,
428 StackFrameInfo
*frame
)
431 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
432 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
434 memset (frame
, 0, sizeof (StackFrameInfo
));
439 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
441 * This LMF entry is created by the soft debug code to mark transitions to
442 * managed code done during invokes.
444 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
445 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
446 } else if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT
|| ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
447 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED
;
448 frame
->interp_exit_data
= ext
->interp_exit_data
;
449 if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
450 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
451 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
454 g_assert_not_reached ();
457 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~3);
463 return mono_arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
469 * Translate between the mono_arch_unwind_frame function and the old API.
472 find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
473 MonoContext
*new_ctx
, MonoLMF
**lmf
, gboolean
*managed
)
475 StackFrameInfo frame
;
478 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
480 /* Avoid costly table lookup during stack overflow */
481 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
484 ji
= mini_jit_info_table_find (domain
, ip
, NULL
);
489 err
= arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, NULL
, &frame
);
491 return (MonoJitInfo
*)-1;
493 if (*lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
495 * Remove any unused lmf.
496 * Mask out the lower bits which might be used to hold additional information.
498 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
501 /* Convert between the new and the old APIs */
502 switch (frame
.type
) {
503 case FRAME_TYPE_MANAGED
:
507 case FRAME_TYPE_TRAMPOLINE
:
509 case FRAME_TYPE_MANAGED_TO_NATIVE
:
513 memset (res
, 0, sizeof (MonoJitInfo
));
514 res
->d
.method
= frame
.method
;
517 case FRAME_TYPE_DEBUGGER_INVOKE
: {
521 * The normal exception handling code can't handle this frame, so just
524 ji
= find_jit_info (domain
, jit_tls
, res
, NULL
, new_ctx
, &tmp_ctx
, lmf
, managed
);
525 memcpy (new_ctx
, &tmp_ctx
, sizeof (MonoContext
));
529 g_assert_not_reached ();
534 /* mono_find_jit_info:
536 * This function is used to gather information from @ctx. It return the
537 * MonoJitInfo of the corresponding function, unwinds one stack frame and
538 * stores the resulting context into @new_ctx. It also stores a string
539 * describing the stack location into @trace (if not NULL), and modifies
540 * the @lmf if necessary. @native_offset return the IP offset from the
541 * start of the function or -1 if that info is not available.
544 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
545 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
549 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
551 MonoMethod
*method
= NULL
;
562 ji
= find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
564 if (ji
== (gpointer
)-1)
567 if (ji
&& !ji
->is_trampoline
)
568 method
= jinfo_get_method (ji
);
570 if (managed2
|| (method
&& method
->wrapper_type
)) {
571 const char *real_ip
, *start
;
574 start
= (const char *)ji
->code_start
;
576 /* ctx->ip points into native code */
577 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
579 real_ip
= (const char*)ip
;
581 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
582 offset
= real_ip
- start
;
587 *native_offset
= offset
;
590 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
594 *trace
= mono_debug_print_stack_frame (method
, offset
, domain
);
597 char *fname
= mono_method_full_name (jinfo_get_method (res
), TRUE
);
598 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
607 * mono_find_jit_info_ext:
609 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
611 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
612 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
613 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
614 * to obtain the last managed frame.
615 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
616 * On return, it will be filled with the locations where callee saved registers are saved
617 * by the current frame. This is returned outside of StackFrameInfo because it can be
618 * quite large on some platforms.
619 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
623 mono_find_jit_info_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
624 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
625 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
626 host_mgreg_t
**save_locations
,
627 StackFrameInfo
*frame
)
630 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
632 MonoDomain
*target_domain
= domain
;
633 MonoMethod
*method
= NULL
;
634 gboolean async
= mono_thread_info_is_async_context ();
639 /* Avoid costly table lookup during stack overflow */
640 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
643 ji
= mini_jit_info_table_find_ext (domain
, ip
, TRUE
, &target_domain
);
646 target_domain
= domain
;
649 memset (save_locations
, 0, MONO_MAX_IREGS
* sizeof (host_mgreg_t
*));
651 err
= arch_unwind_frame (target_domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
655 gboolean not_i2m
= frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED
&& frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
657 if (not_i2m
&& *lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
659 * Remove any unused lmf.
660 * Mask out the lower bits which might be used to hold additional information.
662 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
665 if (frame
->ji
&& !frame
->ji
->is_trampoline
&& !frame
->ji
->async
)
666 method
= jinfo_get_method (frame
->ji
);
668 if (frame
->type
== FRAME_TYPE_MANAGED
&& method
) {
669 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
670 frame
->managed
= TRUE
;
673 if (frame
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
) {
675 * This type of frame is just a marker, the caller should unwind once more to get the
676 * last managed frame.
679 frame
->method
= NULL
;
682 frame
->native_offset
= -1;
683 frame
->domain
= target_domain
;
684 frame
->async_context
= async
;
685 frame
->frame_addr
= MONO_CONTEXT_GET_SP (ctx
);
689 if (frame
->type
== FRAME_TYPE_MANAGED
)
690 frame
->method
= method
;
692 if (ji
&& (frame
->managed
|| (method
&& method
->wrapper_type
))) {
693 const char *real_ip
, *start
;
695 start
= (const char *)ji
->code_start
;
696 if (frame
->type
== FRAME_TYPE_MANAGED
)
697 real_ip
= (const char*)ip
;
699 /* ctx->ip points into native code */
700 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
702 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
703 frame
->native_offset
= real_ip
- start
;
705 frame
->native_offset
= -1;
709 *trace
= mono_debug_print_stack_frame (method
, frame
->native_offset
, domain
);
711 if (trace
&& frame
->method
) {
712 char *fname
= mono_method_full_name (frame
->method
, TRUE
);
713 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
723 MonoInterpStackIter interp_iter
;
724 gpointer last_frame_addr
;
728 unwinder_init (Unwinder
*unwinder
)
730 memset (unwinder
, 0, sizeof (Unwinder
));
733 #if defined(__GNUC__) && defined(TARGET_ARM64)
734 /* gcc 4.9.2 seems to miscompile this on arm64 */
735 static __attribute__((optimize("O0"))) gboolean
739 unwinder_unwind_frame (Unwinder
*unwinder
,
740 MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
741 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
742 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
743 host_mgreg_t
**save_locations
,
744 StackFrameInfo
*frame
)
746 if (unwinder
->in_interp
) {
747 memcpy (new_ctx
, ctx
, sizeof (MonoContext
));
749 /* Process debugger invokes */
750 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
751 if (unwinder
->last_frame_addr
< (gpointer
)(*lmf
)) {
752 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
753 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
754 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
755 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~7);
756 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
762 unwinder
->in_interp
= mini_get_interp_callbacks ()->frame_iter_next (&unwinder
->interp_iter
, frame
);
763 if (frame
->type
== FRAME_TYPE_INTERP
) {
764 const gpointer parent
= mini_get_interp_callbacks ()->frame_get_parent (frame
->interp_frame
);
765 unwinder
->last_frame_addr
= parent
;
768 if (!unwinder
->in_interp
)
769 return unwinder_unwind_frame (unwinder
, domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
, save_locations
, frame
);
772 gboolean res
= mono_find_jit_info_ext (domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
,
773 save_locations
, frame
);
776 if (frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
) {
777 unwinder
->in_interp
= TRUE
;
778 mini_get_interp_callbacks ()->frame_iter_init (&unwinder
->interp_iter
, frame
->interp_exit_data
);
780 unwinder
->last_frame_addr
= frame
->frame_addr
;
786 * This function is async-safe.
789 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
791 MonoGenericJitInfo
*gi
;
795 if (!ji
->has_generic_jit_info
)
797 gi
= mono_jit_info_get_generic_jit_info (ji
);
803 * Search location list if available, it contains the precise location of the
804 * argument for every pc offset, even if the method was interrupted while it was in
808 int offset
= (gsize
)MONO_CONTEXT_GET_IP (ctx
) - (gsize
)ji
->code_start
;
811 for (i
= 0; i
< gi
->nlocs
; ++i
) {
812 MonoDwarfLocListEntry
*entry
= &gi
->locations
[i
];
814 if (offset
>= entry
->from
&& (offset
< entry
->to
|| entry
->to
== 0)) {
816 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, entry
->reg
);
818 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, entry
->reg
) + entry
->offset
);
822 g_assert (i
< gi
->nlocs
);
825 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
827 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
831 method
= jinfo_get_method (ji
);
832 if (mono_method_get_context (method
)->method_inst
) {
833 /* A MonoMethodRuntimeGenericContext* */
835 } else if ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) || m_class_is_valuetype (method
->klass
)) {
839 /* Avoid returning a managed object */
840 MonoObject
*this_obj
= (MonoObject
*)info
;
842 return this_obj
->vtable
;
847 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
850 mono_get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
852 MonoGenericContext context
= { NULL
, NULL
};
853 MonoClass
*klass
, *method_container_class
;
856 g_assert (generic_info
);
858 method
= jinfo_get_method (ji
);
859 g_assert (method
->is_inflated
);
860 if (mono_method_get_context (method
)->method_inst
) {
861 MonoMethodRuntimeGenericContext
*mrgctx
= (MonoMethodRuntimeGenericContext
*)generic_info
;
863 klass
= mrgctx
->class_vtable
->klass
;
864 context
.method_inst
= mrgctx
->method_inst
;
865 g_assert (context
.method_inst
);
867 MonoVTable
*vtable
= (MonoVTable
*)generic_info
;
869 klass
= vtable
->klass
;
872 //g_assert (!mono_class_is_gtd (method->klass));
873 if (mono_class_is_ginst (method
->klass
))
874 method_container_class
= mono_class_get_generic_class (method
->klass
)->container_class
;
876 method_container_class
= method
->klass
;
878 /* class might refer to a subclass of method's class */
879 while (!(klass
== method
->klass
|| (mono_class_is_ginst (klass
) && mono_class_get_generic_class (klass
)->container_class
== method_container_class
))) {
880 klass
= m_class_get_parent (klass
);
884 if (mono_class_is_ginst (klass
) || mono_class_is_gtd (klass
))
885 context
.class_inst
= mini_class_get_context (klass
)->class_inst
;
887 if (mono_class_is_ginst (klass
))
888 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass
)->container_class
, method_container_class
));
890 g_assert (mono_class_has_parent_and_ignore_generics (klass
, method_container_class
));
897 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
900 MonoGenericContext context
;
903 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
904 return jinfo_get_method (ji
);
905 context
= mono_get_generic_context_from_stack_frame (ji
, generic_info
);
907 method
= jinfo_get_method (ji
);
908 method
= mono_method_get_declaring_generic_method (method
);
909 method
= mono_class_inflate_generic_method_checked (method
, &context
, error
);
910 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
916 * mono_exception_walk_native_trace:
917 * \param ex The exception object whose frames should be walked
918 * \param func callback to call for each stack frame
919 * \param user_data data passed to the callback
920 * This function walks the stacktrace of an exception. For
921 * each frame the callback function is called with the relevant info.
922 * The walk ends when no more stack frames are found or when the callback
923 * returns a TRUE value.
927 mono_exception_walk_trace (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
931 MONO_ENTER_GC_UNSAFE
;
932 res
= mono_exception_walk_trace_internal (ex
, func
, user_data
);
938 mono_exception_stackframe_obj_walk (MonoStackFrame
*captured_frame
, MonoExceptionFrameWalk func
, gpointer user_data
)
943 gpointer ip
= (gpointer
) (captured_frame
->method_address
+ captured_frame
->native_offset
);
944 MonoJitInfo
*ji
= mono_jit_info_table_find_internal (mono_domain_get (), ip
, TRUE
, TRUE
);
946 // Other domain maybe?
949 MonoMethod
*method
= jinfo_get_method (ji
);
951 gboolean r
= func (method
, (gpointer
) captured_frame
->method_address
, captured_frame
->native_offset
, TRUE
, user_data
);
959 mono_exception_stacktrace_obj_walk (MonoStackTrace
*st
, MonoExceptionFrameWalk func
, gpointer user_data
)
961 int num_captured
= st
->captured_traces
? mono_array_length_internal (st
->captured_traces
) : 0;
962 for (int i
=0; i
< num_captured
; i
++) {
963 MonoStackTrace
*curr_trace
= mono_array_get_fast (st
->captured_traces
, MonoStackTrace
*, i
);
964 mono_exception_stacktrace_obj_walk (curr_trace
, func
, user_data
);
967 int num_frames
= st
->frames
? mono_array_length_internal (st
->frames
) : 0;
968 for (int frame
= 0; frame
< num_frames
; frame
++) {
969 gboolean r
= mono_exception_stackframe_obj_walk (mono_array_get_fast (st
->frames
, MonoStackFrame
*, frame
), func
, user_data
);
978 mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
980 MONO_REQ_GC_UNSAFE_MODE
;
982 MonoDomain
*domain
= mono_domain_get ();
983 MonoArray
*ta
= ex
->trace_ips
;
985 /* Exception is not thrown yet */
989 int len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
990 gboolean otherwise_has_traces
= len
> 0;
992 for (int i
= 0; i
< len
; i
++) {
993 ExceptionTraceIp trace_ip
;
995 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
996 gpointer ip
= trace_ip
.ip
;
997 gpointer generic_info
= trace_ip
.generic_info
;
999 MonoJitInfo
*ji
= NULL
;
1003 ji
= mono_jit_info_table_find (domain
, ip
);
1009 r
= func (NULL
, ip
, 0, FALSE
, user_data
);
1014 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
1015 if (func (method
, ji
->code_start
, (char *) ip
- (char *) ji
->code_start
, TRUE
, user_data
))
1020 ta
= (MonoArray
*) ex
->captured_traces
;
1021 len
= ta
? mono_array_length_internal (ta
) : 0;
1022 gboolean captured_has_traces
= len
> 0;
1024 for (int i
= 0; i
< len
; i
++) {
1025 MonoStackTrace
*captured_trace
= mono_array_get_fast (ta
, MonoStackTrace
*, i
);
1026 if (!captured_trace
)
1029 mono_exception_stacktrace_obj_walk (captured_trace
, func
, user_data
);
1032 return captured_has_traces
|| otherwise_has_traces
;
1036 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
1039 MonoDomain
*domain
= mono_domain_get ();
1041 MonoArray
*ta
= exc
->trace_ips
;
1042 MonoDebugSourceLocation
*location
;
1046 /* Exception is not thrown yet */
1047 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, 0, error
);
1048 mono_error_set_pending_exception (error
);
1052 HANDLE_FUNCTION_ENTER ();
1054 MONO_HANDLE_PIN (ta
);
1056 len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
1058 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0, error
);
1062 MONO_HANDLE_PIN (res
);
1064 MonoObjectHandle sf_h
;
1065 sf_h
= MONO_HANDLE_NEW (MonoObject
, NULL
);
1067 for (i
= skip
; i
< len
; i
++) {
1069 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
1072 MONO_HANDLE_ASSIGN_RAW (sf_h
, sf
);
1074 ExceptionTraceIp trace_ip
;
1075 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
1076 gpointer ip
= trace_ip
.ip
;
1077 gpointer generic_info
= trace_ip
.generic_info
;
1083 ji
= mono_jit_info_table_find (domain
, ip
);
1085 /* Unmanaged frame */
1086 mono_array_setref_internal (res
, i
, sf
);
1091 g_assert (ji
!= NULL
);
1093 if (mono_llvm_only
|| !generic_info
)
1094 /* Can't resolve actual method */
1095 method
= jinfo_get_method (ji
);
1097 method
= get_method_from_stack_frame (ji
, generic_info
);
1098 if (jinfo_get_method (ji
)->wrapper_type
) {
1102 s
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_REFLECTION
);
1103 MonoString
*name
= mono_string_new_checked (domain
, s
, error
);
1107 MONO_OBJECT_SETREF_INTERNAL (sf
, internal_method_name
, name
);
1110 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
1113 MONO_OBJECT_SETREF_INTERNAL (sf
, method
, rm
);
1116 sf
->method_index
= ji
->from_aot
? mono_aot_find_method_index (method
) : 0xffffff;
1117 sf
->method_address
= (gsize
) ji
->code_start
;
1118 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
1121 * mono_debug_lookup_source_location() returns both the file / line number information
1122 * and the IL offset. Note that computing the IL offset is already an expensive
1123 * operation, so we shouldn't call this method twice.
1125 location
= mono_debug_lookup_source_location (jinfo_get_method (ji
), sf
->native_offset
, domain
);
1127 sf
->il_offset
= location
->il_offset
;
1130 if (mono_find_prev_seq_point_for_native_offset (domain
, jinfo_get_method (ji
), sf
->native_offset
, NULL
, &sp
))
1131 sf
->il_offset
= sp
.il_offset
;
1136 if (need_file_info
) {
1137 if (location
&& location
->source_file
) {
1138 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1141 MONO_OBJECT_SETREF_INTERNAL (sf
, filename
, filename
);
1142 sf
->line
= location
->row
;
1143 sf
->column
= location
->column
;
1145 sf
->line
= sf
->column
= 0;
1146 sf
->filename
= NULL
;
1150 mono_debug_free_source_location (location
);
1151 mono_array_setref_internal (res
, i
- skip
, sf
);
1156 mono_error_set_pending_exception (error
);
1159 HANDLE_FUNCTION_RETURN_VAL (res
);
1163 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1166 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1167 if (jit_tls
&& jit_tls
->orig_ex_ctx_set
)
1168 start_ctx
= &jit_tls
->orig_ex_ctx
;
1170 mono_walk_stack_with_ctx (func
, start_ctx
, unwind_options
, user_data
);
1173 * mono_walk_stack_with_ctx:
1174 * Unwind the current thread starting at \p start_ctx.
1175 * If \p start_ctx is null, we capture the current context.
1178 mono_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1180 MonoContext extra_ctx
;
1181 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1182 MONO_ARCH_CONTEXT_DEF
1184 if (!thread
|| !thread
->jit_data
)
1188 mono_arch_flush_register_windows ();
1189 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx
, mono_walk_stack_with_ctx
);
1190 start_ctx
= &extra_ctx
;
1193 mono_walk_stack_full (func
, start_ctx
, mono_domain_get (), thread
->jit_data
, mono_get_lmf (), unwind_options
, user_data
, FALSE
);
1197 * mono_walk_stack_with_state:
1198 * Unwind a thread described by \p state.
1200 * State must be valid (state->valid == TRUE).
1202 * If you are using this function to unwind another thread, make sure it is suspended.
1204 * If \p state is null, we capture the current context.
1207 mono_walk_stack_with_state (MonoJitStackWalk func
, MonoThreadUnwindState
*state
, MonoUnwindOptions unwind_options
, void *user_data
)
1209 MonoThreadUnwindState extra_state
;
1211 g_assert (!mono_thread_info_is_async_context ());
1212 if (!mono_thread_state_init_from_current (&extra_state
))
1214 state
= &extra_state
;
1217 g_assert (state
->valid
);
1219 if (!state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
])
1223 mono_walk_stack_full (func
,
1225 (MonoDomain
*)state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
],
1226 (MonoJitTlsData
*)state
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
],
1227 (MonoLMF
*)state
->unwind_data
[MONO_UNWIND_DATA_LMF
],
1228 unwind_options
, user_data
, FALSE
);
1232 mono_walk_stack (MonoJitStackWalk func
, MonoUnwindOptions options
, void *user_data
)
1234 MonoThreadUnwindState state
;
1235 if (!mono_thread_state_init_from_current (&state
))
1237 mono_walk_stack_with_state (func
, &state
, options
, user_data
);
1241 * mono_walk_stack_full:
1242 * \param func callback to call for each stack frame
1243 * \param domain starting appdomain, can be NULL to use the current domain
1244 * \param unwind_options what extra information the unwinder should gather
1245 * \param start_ctx starting state of the stack walk, can be NULL.
1246 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1247 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1248 * \param user_data data passed to the callback
1249 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1250 * This function walks the stack of a thread, starting from the state
1251 * represented by \p start_ctx. For each frame the callback
1252 * function is called with the relevant info. The walk ends when no more
1253 * managed stack frames are found or when the callback returns a TRUE value.
1256 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
)
1259 MonoContext ctx
, new_ctx
;
1260 StackFrameInfo frame
;
1262 host_mgreg_t
*reg_locations
[MONO_MAX_IREGS
];
1263 host_mgreg_t
*new_reg_locations
[MONO_MAX_IREGS
];
1264 gboolean get_reg_locations
= unwind_options
& MONO_UNWIND_REG_LOCATIONS
;
1265 gboolean async
= mono_thread_info_is_async_context ();
1268 memset (&frame
, 0, sizeof (StackFrameInfo
));
1271 if (mono_llvm_only
) {
1277 ips
= get_unwind_backtrace ();
1278 for (l
= ips
; l
; l
= l
->next
) {
1279 guint8
*ip
= (guint8
*)l
->data
;
1280 memset (&frame
, 0, sizeof (StackFrameInfo
));
1281 frame
.ji
= mini_jit_info_table_find (domain
, ip
, &frame
.domain
);
1282 if (!frame
.ji
|| frame
.ji
->is_trampoline
)
1284 frame
.type
= FRAME_TYPE_MANAGED
;
1285 frame
.method
= jinfo_get_method (frame
.ji
);
1286 // FIXME: Cannot lookup the actual method
1287 frame
.actual_method
= frame
.method
;
1288 if (frame
.type
== FRAME_TYPE_MANAGED
) {
1289 if (!frame
.method
->wrapper_type
|| frame
.method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1290 frame
.managed
= TRUE
;
1292 frame
.native_offset
= ip
- (guint8
*)frame
.ji
->code_start
;
1293 frame
.il_offset
= -1;
1295 if (func (&frame
, NULL
, user_data
))
1304 g_warning ("start_ctx required for stack walk");
1309 g_warning ("domain required for stack walk");
1314 g_warning ("jit_tls required for stack walk");
1318 /*The LMF will be null if the target have no managed frames.*/
1319 /* g_assert (lmf); */
1320 if (async
&& (unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
)) {
1321 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1325 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
1326 memset (reg_locations
, 0, sizeof (reg_locations
));
1328 unwinder_init (&unwinder
);
1330 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
1332 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, get_reg_locations
? new_reg_locations
: NULL
, &frame
);
1336 if (frame
.type
== FRAME_TYPE_TRAMPOLINE
)
1339 if ((unwind_options
& MONO_UNWIND_LOOKUP_IL_OFFSET
) && frame
.ji
) {
1340 MonoDebugSourceLocation
*source
= NULL
;
1342 // Don't do this when we can be in a signal handler
1344 source
= mono_debug_lookup_source_location (jinfo_get_method (frame
.ji
), frame
.native_offset
, domain
);
1346 il_offset
= source
->il_offset
;
1348 MonoSeqPointInfo
*seq_points
= NULL
;
1350 // It's more reliable to look into the global cache if possible
1352 seq_points
= (MonoSeqPointInfo
*) frame
.ji
->seq_points
;
1354 seq_points
= mono_get_seq_points (domain
, jinfo_get_method (frame
.ji
));
1357 if (seq_points
&& mono_seq_point_find_prev_by_native_offset (seq_points
, frame
.native_offset
, &sp
))
1358 il_offset
= sp
.il_offset
;
1362 mono_debug_free_source_location (source
);
1366 frame
.il_offset
= il_offset
;
1368 if ((unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
) && frame
.ji
) {
1369 frame
.actual_method
= get_method_from_stack_frame (frame
.ji
, get_generic_info_from_stack_frame (frame
.ji
, &ctx
));
1371 frame
.actual_method
= frame
.method
;
1374 if (get_reg_locations
)
1375 frame
.reg_locations
= reg_locations
;
1377 if (func (&frame
, &ctx
, user_data
))
1381 if (get_reg_locations
) {
1382 for (int i
= 0; i
< MONO_MAX_IREGS
; ++i
)
1383 if (new_reg_locations
[i
])
1384 reg_locations
[i
] = new_reg_locations
[i
];
1391 #ifdef DISABLE_CRASH_REPORTING
1394 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1400 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1406 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1412 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1418 mono_crash_reporting_allow_all_native_libraries ()
1427 MonoFrameSummary
*frames
;
1430 MonoStackHash
*hashes
;
1432 } MonoSummarizeUserData
;
1435 copy_summary_string_safe (char *dest
, const char *src
)
1437 g_strlcpy (dest
, src
, MONO_MAX_SUMMARY_NAME_LEN
);
1441 fill_frame_managed_info (MonoFrameSummary
*frame
, MonoMethod
* method
)
1443 MonoImage
*image
= mono_class_get_image (method
->klass
);
1444 // Used for hashing, more stable across rebuilds than using GUID
1445 copy_summary_string_safe (frame
->str_descr
, image
->assembly_name
);
1447 frame
->managed_data
.guid
= image
->guid
;
1448 frame
->managed_data
.token
= method
->token
;
1449 frame
->managed_data
.filename
= image
->module_name
;
1451 MonoDotNetHeader
*header
= &image
->image_info
->cli_header
;
1452 frame
->managed_data
.image_size
= header
->nt
.pe_image_size
;
1453 frame
->managed_data
.time_date_stamp
= image
->time_date_stamp
;
1458 char *exported_name
;
1459 } MonoLibAllowlistEntry
;
1461 static GList
*native_library_allowlist
;
1462 static gboolean allow_all_native_libraries
= FALSE
;
1465 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1467 // Examples: libsystem_pthread.dylib -> "pthread"
1468 // Examples: libsystem_platform.dylib -> "platform"
1469 // Examples: mono-sgen -> "mono" from above line
1470 MonoLibAllowlistEntry
*entry
= g_new0 (MonoLibAllowlistEntry
, 1);
1471 entry
->suffix
= g_strdup (module_path
);
1472 entry
->exported_name
= g_strdup (module_name
);
1473 native_library_allowlist
= g_list_append (native_library_allowlist
, entry
);
1477 mono_crash_reporting_allow_all_native_libraries ()
1479 allow_all_native_libraries
= TRUE
;
1483 check_allowlisted_module (const char *in_name
, const char **out_module
)
1485 #ifndef MONO_PRIVATE_CRASHES
1488 if (g_str_has_suffix (in_name
, "mono-sgen")) {
1490 copy_summary_string_safe ((char *) *out_module
, "mono");
1493 if (allow_all_native_libraries
) {
1495 /* for a module name, use the basename of the full path in in_name */
1496 char *basename
= (char *) in_name
, *p
= (char *) in_name
;
1497 while (*p
!= '\0') {
1503 copy_summary_string_safe ((char *) *out_module
, basename
);
1505 copy_summary_string_safe ((char *) *out_module
, "unknown");
1511 for (GList
*cursor
= native_library_allowlist
; cursor
; cursor
= cursor
->next
) {
1512 MonoLibAllowlistEntry
*iter
= (MonoLibAllowlistEntry
*) cursor
->data
;
1513 if (!g_str_has_suffix (in_name
, iter
->suffix
))
1516 copy_summary_string_safe ((char *) *out_module
, iter
->exported_name
);
1525 mono_make_portable_ip (intptr_t in_ip
, intptr_t module_base
)
1527 // FIXME: Make generalize away from llvm tools?
1528 // So lldb starts the pointer base at 0x100000000
1529 // and expects to get pointers as (offset + constant)
1532 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1533 // *CoreSymbolicationDT.framework version: 63750*/
1534 intptr_t offset
= in_ip
- module_base
;
1535 intptr_t magic_value
= offset
+ 0x100000000;
1540 mono_get_portable_ip (intptr_t in_ip
, intptr_t *out_ip
, gint32
*out_offset
, const char **out_module
, char *out_name
)
1542 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1543 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1544 // non-recursive lock twice on this thread, and will deadlock.
1545 char sname
[256], fname
[256];
1546 void *saddr
= NULL
, *fbase
= NULL
;
1547 gboolean success
= g_module_address ((void*)in_ip
, fname
, 256, &fbase
, sname
, 256, &saddr
);
1551 if (!check_allowlisted_module (fname
, out_module
))
1554 *out_ip
= mono_make_portable_ip ((intptr_t) saddr
, (intptr_t) fbase
);
1555 *out_offset
= in_ip
- (intptr_t) saddr
;
1557 if (saddr
&& out_name
)
1558 copy_summary_string_safe (out_name
, sname
);
1563 summarize_offset_free_hash (guint64 accum
, MonoFrameSummary
*frame
)
1565 if (!frame
->is_managed
)
1568 // See: mono_ptrarray_hash
1569 guint64 hash_accum
= accum
;
1571 // The assembly and the method token, no offsets
1572 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1573 hash_accum
+= frame
->managed_data
.token
;
1579 summarize_offset_rich_hash (guint64 accum
, MonoFrameSummary
*frame
)
1581 // See: mono_ptrarray_hash
1582 guint64 hash_accum
= accum
;
1584 if (!frame
->is_managed
) {
1585 hash_accum
+= frame
->unmanaged_data
.ip
;
1587 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1588 hash_accum
+= frame
->managed_data
.token
;
1589 hash_accum
+= frame
->managed_data
.il_offset
;
1596 summarize_frame_internal (MonoMethod
*method
, gpointer ip
, size_t native_offset
, int il_offset
, gboolean managed
, gpointer user_data
)
1598 MonoSummarizeUserData
*ud
= (MonoSummarizeUserData
*) user_data
;
1600 gboolean valid_state
= ud
->num_frames
+ 1 < ud
->max_frames
;
1602 ud
->error
= "Exceeded the maximum number of frames";
1606 MonoFrameSummary
*dest
= &ud
->frames
[ud
->num_frames
];
1608 dest
->unmanaged_data
.ip
= (intptr_t) ip
;
1609 dest
->is_managed
= managed
;
1610 dest
->unmanaged_data
.module
[0] = '\0';
1612 if (!managed
&& method
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
&& method
->wrapper_type
< MONO_WRAPPER_NUM
) {
1613 dest
->is_managed
= FALSE
;
1614 dest
->unmanaged_data
.has_name
= TRUE
;
1615 copy_summary_string_safe (dest
->str_descr
, mono_wrapper_type_to_str (method
->wrapper_type
));
1618 #ifndef MONO_PRIVATE_CRASHES
1620 dest
->managed_data
.name
= (char *) method
->name
;
1625 ud
->error
= "Managed method frame, but no provided managed method";
1628 fill_frame_managed_info (dest
, method
);
1629 dest
->managed_data
.native_offset
= native_offset
;
1630 dest
->managed_data
.il_offset
= il_offset
;
1632 dest
->managed_data
.token
= -1;
1636 ud
->hashes
->offset_free_hash
= summarize_offset_free_hash (ud
->hashes
->offset_free_hash
, dest
);
1637 ud
->hashes
->offset_rich_hash
= summarize_offset_rich_hash (ud
->hashes
->offset_rich_hash
, dest
);
1639 // We return FALSE, so we're continuing walking
1640 // And we increment the pointer because we're done with this cell in the array
1646 summarize_frame_managed_walk (MonoMethod
*method
, gpointer ip
, size_t frame_native_offset
, gboolean managed
, gpointer user_data
)
1650 if (managed
&& method
) {
1651 MonoDebugSourceLocation
*location
= mono_debug_lookup_source_location (method
, frame_native_offset
, mono_domain_get ());
1653 il_offset
= location
->il_offset
;
1654 mono_debug_free_source_location (location
);
1658 intptr_t portable_ip
= 0;
1660 mono_get_portable_ip ((intptr_t) ip
, &portable_ip
, &offset
, NULL
, NULL
);
1662 return summarize_frame_internal (method
, (gpointer
) portable_ip
, frame_native_offset
, il_offset
, managed
, user_data
);
1667 summarize_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
1669 // Don't record trampolines between managed frames
1670 if (frame
->ji
&& frame
->ji
->is_trampoline
)
1673 if (frame
->ji
&& (frame
->ji
->is_trampoline
|| frame
->ji
->async
))
1674 return FALSE
; // Keep unwinding
1678 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx
), &ip
, &offset
, NULL
, NULL
);
1679 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1681 gboolean is_managed
= (frame
->type
== FRAME_TYPE_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP
);
1682 MonoMethod
*method
= NULL
;
1683 if (frame
&& frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
1684 method
= jinfo_get_method (frame
->ji
);
1687 method
= jinfo_get_method (frame
->ji
);
1689 return summarize_frame_internal (method
, (gpointer
) ip
, offset
, frame
->il_offset
, is_managed
, data
);
1693 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1695 memset (out
, 0, sizeof (MonoThreadSummary
));
1697 MonoException
*inner_exc
= exc
;
1700 for (exc_index
= 0; exc_index
< MONO_MAX_SUMMARY_EXCEPTIONS
; exc_index
++) {
1701 if (inner_exc
== NULL
)
1704 // Set up state to walk this MonoException's stack
1705 MonoSummarizeUserData data
;
1706 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1707 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1708 data
.num_frames
= 0;
1709 data
.frames
= out
->exceptions
[exc_index
].managed_frames
;
1711 // Accumulate all hashes from all exceptions in traveral order
1712 data
.hashes
= &out
->hashes
;
1714 mono_exception_walk_trace (inner_exc
, summarize_frame_managed_walk
, &data
);
1716 // Save per-MonoException info
1717 out
->exceptions
[exc_index
].managed_exc_type
= inner_exc
->object
.vtable
->klass
;
1718 out
->exceptions
[exc_index
].num_managed_frames
= data
.num_frames
;
1720 // Continue to traverse nesting of exceptions
1721 inner_exc
= (MonoException
*) inner_exc
->inner_ex
;
1724 out
->num_exceptions
= exc_index
;
1729 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1731 MonoSummarizeUserData data
;
1732 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1733 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1734 data
.num_frames
= 0;
1735 data
.frames
= out
->managed_frames
;
1736 data
.hashes
= &out
->hashes
;
1738 // FIXME: collect stack pointer for both and sort frames by SP
1739 // so people can see relative ordering of both managed and unmanaged frames.
1742 // Summarize managed stack
1744 mono_walk_stack_full (summarize_frame
, out
->ctx
, out
->domain
, out
->jit_tls
, out
->lmf
, MONO_UNWIND_LOOKUP_IL_OFFSET
, &data
, TRUE
);
1745 out
->num_managed_frames
= data
.num_frames
;
1747 if (data
.error
!= NULL
)
1748 out
->error_msg
= data
.error
;
1749 out
->is_managed
= (out
->num_managed_frames
!= 0);
1752 // Always runs on the dumped thread
1754 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1756 MONO_ARCH_CONTEXT_DEF
1758 // Summarize unmanaged stack
1760 #ifdef HAVE_BACKTRACE_SYMBOLS
1761 intptr_t frame_ips
[MONO_MAX_SUMMARY_FRAMES
];
1763 out
->num_unmanaged_frames
= backtrace ((void **)frame_ips
, MONO_MAX_SUMMARY_FRAMES
);
1765 for (int i
=0; i
< out
->num_unmanaged_frames
; ++i
) {
1766 intptr_t ip
= frame_ips
[i
];
1767 MonoFrameSummary
*frame
= &out
->unmanaged_frames
[i
];
1768 const char* module_buf
= frame
->unmanaged_data
.module
;
1769 int success
= mono_get_portable_ip (ip
, &frame
->unmanaged_data
.ip
, &frame
->unmanaged_data
.offset
, &module_buf
, (char *) frame
->str_descr
);
1771 /* attempt to look up any managed method at that ip */
1772 /* TODO: Trampolines - follow examples from mono_print_method_from_ip() */
1775 MonoDomain
*domain
= mono_domain_get ();
1776 MonoDomain
*target_domain
;
1777 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
1779 frame
->is_managed
= TRUE
;
1780 if (!ji
->async
&& !ji
->is_trampoline
) {
1781 MonoMethod
*method
= jinfo_get_method (ji
);
1782 fill_frame_managed_info (frame
, method
);
1783 #ifndef MONO_PRIVATE_CRASHES
1784 frame
->managed_data
.name
= method
->name
;
1789 if (!success
&& !ji
) {
1790 frame
->unmanaged_data
.ip
= ip
;
1794 if (out
->unmanaged_frames
[i
].str_descr
[0] != '\0')
1795 out
->unmanaged_frames
[i
].unmanaged_data
.has_name
= TRUE
;
1797 out
->hashes
.offset_free_hash
= summarize_offset_free_hash (out
->hashes
.offset_free_hash
, frame
);
1798 out
->hashes
.offset_rich_hash
= summarize_offset_rich_hash (out
->hashes
.offset_rich_hash
, frame
);
1802 out
->lmf
= mono_get_lmf ();
1804 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1805 out
->info_addr
= (intptr_t) thread
;
1806 out
->jit_tls
= thread
->jit_data
;
1807 out
->domain
= mono_domain_get ();
1810 out
->ctx
= &out
->ctx_mem
;
1811 mono_arch_flush_register_windows ();
1812 MONO_INIT_CONTEXT_FROM_FUNC (out
->ctx
, mono_summarize_unmanaged_stack
);
1821 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
1822 MonoReflectionMethod
**method
,
1823 gint32
*iloffset
, gint32
*native_offset
,
1824 MonoString
**file
, gint32
*line
, gint32
*column
)
1827 MonoDomain
*domain
= mono_domain_get ();
1828 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1829 MonoLMF
*lmf
= mono_get_lmf ();
1830 MonoJitInfo
*ji
= NULL
;
1831 MonoContext ctx
, new_ctx
;
1832 MonoDebugSourceLocation
*location
;
1833 MonoMethod
*jmethod
= NULL
, *actual_method
;
1834 StackFrameInfo frame
;
1839 MONO_ARCH_CONTEXT_DEF
;
1841 g_assert (skip
>= 0);
1843 if (mono_llvm_only
) {
1845 MonoDomain
*frame_domain
;
1846 guint8
*frame_ip
= NULL
;
1848 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1850 ips
= get_unwind_backtrace ();
1851 for (l
= ips
; l
&& skip
>= 0; l
= l
->next
) {
1852 guint8
*ip
= (guint8
*)l
->data
;
1856 ji
= mini_jit_info_table_find (mono_domain_get (), ip
, &frame_domain
);
1857 if (!ji
|| ji
->is_trampoline
)
1860 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1861 jmethod
= jinfo_get_method (ji
);
1862 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1869 /* No way to resolve generic instances */
1870 actual_method
= jmethod
;
1871 *native_offset
= frame_ip
- (guint8
*)ji
->code_start
;
1873 mono_arch_flush_register_windows ();
1874 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
1876 unwinder_init (&unwinder
);
1881 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
1884 switch (frame
.type
) {
1885 case FRAME_TYPE_MANAGED_TO_NATIVE
:
1886 case FRAME_TYPE_DEBUGGER_INVOKE
:
1887 case FRAME_TYPE_TRAMPOLINE
:
1888 case FRAME_TYPE_INTERP_TO_MANAGED
:
1889 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
1891 case FRAME_TYPE_INTERP
:
1892 case FRAME_TYPE_MANAGED
:
1894 *native_offset
= frame
.native_offset
;
1896 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1897 jmethod
= jinfo_get_method (ji
);
1898 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1903 g_assert_not_reached ();
1905 } while (skip
>= 0);
1907 if (frame
.type
== FRAME_TYPE_INTERP
) {
1908 jmethod
= frame
.method
;
1909 actual_method
= frame
.actual_method
;
1911 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &ctx
));
1915 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, actual_method
, NULL
, error
);
1916 if (!is_ok (error
)) {
1917 mono_error_set_pending_exception (error
);
1920 mono_gc_wbarrier_generic_store_internal (method
, (MonoObject
*) rm
);
1922 if (il_offset
!= -1) {
1923 location
= mono_debug_lookup_source_location_by_il (jmethod
, il_offset
, domain
);
1925 location
= mono_debug_lookup_source_location (jmethod
, *native_offset
, domain
);
1928 *iloffset
= location
->il_offset
;
1932 if (need_file_info
) {
1934 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1935 if (!is_ok (error
)) {
1936 mono_error_set_pending_exception (error
);
1939 mono_gc_wbarrier_generic_store_internal (file
, (MonoObject
*)filename
);
1940 *line
= location
->row
;
1941 *column
= location
->column
;
1944 *line
= *column
= 0;
1948 mono_debug_free_source_location (location
);
1954 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
1957 MonoClass
*catch_class
= ei
->data
.catch_class
;
1958 MonoType
*inflated_type
;
1959 MonoGenericContext context
;
1961 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1962 if (!catch_class
|| ei
->flags
!= MONO_EXCEPTION_CLAUSE_NONE
)
1965 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
1967 context
= mono_get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
1969 /* FIXME: we shouldn't inflate but instead put the
1970 type in the rgctx and fetch it from there. It
1971 might be a good idea to do this lazily, i.e. only
1972 when the exception is actually thrown, so as not to
1973 waste space for exception clauses which might never
1975 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
1976 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1978 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
1979 mono_metadata_free_type (inflated_type
);
1985 * mini_jit_info_table_find_ext:
1987 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1988 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1989 * OUT_DOMAIN if it is not NULL.
1992 mini_jit_info_table_find_ext (MonoDomain
*domain
, gpointer addr
, gboolean allow_trampolines
, MonoDomain
**out_domain
)
1995 MonoInternalThread
*t
= mono_thread_internal_current ();
2001 ji
= mono_jit_info_table_find_internal (domain
, addr
, TRUE
, allow_trampolines
);
2004 *out_domain
= domain
;
2008 /* maybe it is shared code, so we also search in the root domain */
2009 if (domain
!= mono_get_root_domain ()) {
2010 ji
= mono_jit_info_table_find_internal (mono_get_root_domain (), addr
, TRUE
, allow_trampolines
);
2013 *out_domain
= mono_get_root_domain ();
2021 refs
= (gpointer
*)((t
->appdomain_refs
) ? *(gpointer
*) t
->appdomain_refs
: NULL
);
2022 for (; refs
&& *refs
; refs
++) {
2023 if (*refs
!= domain
&& *refs
!= mono_get_root_domain ()) {
2024 ji
= mono_jit_info_table_find_internal ((MonoDomain
*) *refs
, addr
, TRUE
, allow_trampolines
);
2027 *out_domain
= (MonoDomain
*) *refs
;
2037 mini_jit_info_table_find (MonoDomain
*domain
, gpointer addr
, MonoDomain
**out_domain
)
2039 return mini_jit_info_table_find_ext (domain
, addr
, FALSE
, out_domain
);
2042 /* Class lazy loading functions */
2043 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr
, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
2046 * wrap_non_exception_throws:
2048 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
2049 * WrapNonExceptionThrows flag set.
2052 wrap_non_exception_throws (MonoMethod
*m
)
2055 MonoAssembly
*ass
= m_class_get_image (m
->klass
)->assembly
;
2056 MonoCustomAttrInfo
* attrs
;
2059 gboolean val
= FALSE
;
2061 if (m
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
2062 MonoDynamicMethod
*dm
= (MonoDynamicMethod
*)m
;
2067 if (ass
->wrap_non_exception_throws_inited
)
2068 return ass
->wrap_non_exception_throws
;
2070 klass
= mono_class_get_runtime_compat_attr_class ();
2072 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
2073 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2075 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
2076 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
2078 int num_named
, named_type
, name_len
;
2081 if (!attr
->ctor
|| attr
->ctor
->klass
!= klass
)
2083 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2084 p
= (const char*)attr
->data
;
2085 g_assert (read16 (p
) == 0x0001);
2087 num_named
= read16 (p
);
2093 /* data_type = *p; */
2096 if (named_type
!= 0x54)
2098 name_len
= mono_metadata_decode_blob_size (p
, &p
);
2099 name
= (char *)g_malloc (name_len
+ 1);
2100 memcpy (name
, p
, name_len
);
2101 name
[name_len
] = 0;
2103 g_assert (!strcmp (name
, "WrapNonExceptionThrows"));
2105 /* The value is a BOOLEAN */
2108 mono_custom_attrs_free (attrs
);
2111 ass
->wrap_non_exception_throws
= val
;
2112 mono_memory_barrier ();
2113 ass
->wrap_non_exception_throws_inited
= TRUE
;
2118 #define MAX_UNMANAGED_BACKTRACE 128
2120 build_native_trace (MonoError
*error
)
2123 /* This puppy only makes sense on mobile, IOW, ARM. */
2124 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2126 void *native_trace
[MAX_UNMANAGED_BACKTRACE
];
2129 size
= backtrace (native_trace
, MAX_UNMANAGED_BACKTRACE
);
2135 res
= mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, size
, error
);
2136 return_val_if_nok (error
, NULL
);
2138 for (i
= 0; i
< size
; i
++)
2139 mono_array_set_internal (res
, gpointer
, i
, native_trace
[i
]);
2147 remove_wrappers_from_trace (GList
**trace_ips_p
)
2149 GList
*trace_ips
= *trace_ips_p
;
2150 GList
*p
= trace_ips
;
2152 /* jit info, generic info, ip */
2154 MonoJitInfo
*jinfo
= (MonoJitInfo
*) p
->data
;
2155 GList
*next_p
= p
->next
->next
->next
;
2156 /* FIXME Maybe remove more wrapper types */
2157 if (jinfo
->d
.method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2158 trace_ips
= g_list_delete_link (trace_ips
, p
->next
->next
);
2159 trace_ips
= g_list_delete_link (trace_ips
, p
->next
);
2160 trace_ips
= g_list_delete_link (trace_ips
, p
);
2165 *trace_ips_p
= trace_ips
;
2168 /* This can be called more than once on a MonoException. */
2170 setup_stack_trace (MonoException
*mono_ex
, GSList
**dynamic_methods
, GList
*trace_ips
, gboolean remove_wrappers
)
2173 GList
*trace_ips_copy
= g_list_copy (trace_ips
);
2174 if (remove_wrappers
)
2175 remove_wrappers_from_trace (&trace_ips_copy
);
2176 trace_ips_copy
= g_list_reverse (trace_ips_copy
);
2178 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips_copy
, mono_defaults
.int_class
, error
);
2179 mono_error_assert_ok (error
);
2180 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
2181 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, native_trace_ips
, build_native_trace (error
));
2182 mono_error_assert_ok (error
);
2183 if (*dynamic_methods
) {
2184 /* These methods could go away anytime, so save a reference to them in the exception object */
2186 MonoMList
*list
= (MonoMList
*)mono_ex
->dynamic_methods
;
2188 for (l
= *dynamic_methods
; l
; l
= l
->next
) {
2189 MonoGCHandle dis_link
;
2190 MonoDomain
*domain
= mono_domain_get ();
2192 if (domain
->method_to_dyn_method
) {
2193 mono_domain_lock (domain
);
2194 dis_link
= (MonoGCHandle
)g_hash_table_lookup (domain
->method_to_dyn_method
, l
->data
);
2195 mono_domain_unlock (domain
);
2197 MonoObject
*o
= mono_gchandle_get_target_internal (dis_link
);
2199 list
= mono_mlist_prepend_checked (list
, o
, error
);
2200 mono_error_assert_ok (error
);
2206 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, dynamic_methods
, list
);
2208 g_slist_free (*dynamic_methods
);
2209 *dynamic_methods
= NULL
;
2212 g_list_free (trace_ips_copy
);
2217 MONO_FIRST_PASS_UNHANDLED
,
2218 MONO_FIRST_PASS_CALLBACK_TO_NATIVE
,
2219 MONO_FIRST_PASS_HANDLED
,
2220 } MonoFirstPassResult
;
2223 * handle_exception_first_pass:
2225 * The first pass of exception handling. Unwind the stack until a catch
2226 * clause which can catch OBJ is found. Store the index of the filter clause
2227 * which caught the exception into OUT_FILTER_IDX. Return
2228 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2229 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2230 * wrapper and an exception handling callback is installed (in which case
2231 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2233 static MonoFirstPassResult
2234 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
)
2237 MonoDomain
*domain
= mono_domain_get ();
2238 MonoJitInfo
*ji
= NULL
;
2239 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2240 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2241 MonoLMF
*lmf
= mono_get_lmf ();
2242 GList
*trace_ips
= NULL
;
2243 GSList
*dynamic_methods
= NULL
;
2244 MonoException
*mono_ex
;
2245 gboolean stack_overflow
= FALSE
;
2246 MonoContext initial_ctx
;
2248 int frame_count
= 0;
2255 MonoFirstPassResult result
= MONO_FIRST_PASS_UNHANDLED
;
2257 g_assert (ctx
!= NULL
);
2258 *last_mono_wrapper_runtime_invoke
= TRUE
;
2259 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2260 stack_overflow
= TRUE
;
2262 mono_ex
= (MonoException
*)obj
;
2263 MonoArray
*initial_trace_ips
= mono_ex
->trace_ips
;
2264 if (initial_trace_ips
) {
2265 int len
= mono_array_length_internal (initial_trace_ips
) / TRACE_IP_ENTRY_SIZE
;
2267 // If we catch in managed/non-wrapper, we don't save the catching frame
2268 if (!mono_ex
->caught_in_unmanaged
)
2271 for (i
= 0; i
< len
; i
++) {
2272 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
2273 gpointer p
= mono_array_get_internal (initial_trace_ips
, gpointer
, (i
* TRACE_IP_ENTRY_SIZE
) + j
);
2274 trace_ips
= g_list_prepend (trace_ips
, p
);
2279 // Reset the state because we're making it be caught somewhere
2280 if (mono_ex
->caught_in_unmanaged
)
2281 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, caught_in_unmanaged
, 0);
2283 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2284 mono_error_assert_ok (error
);
2289 call_filter
= (int (*) (MonoContext
*, void *))mono_get_call_filter ();
2291 g_assert (jit_tls
->end_of_stack
);
2292 g_assert (jit_tls
->abort_func
);
2295 *out_filter_idx
= -1;
2299 *out_prev_ji
= NULL
;
2303 unwinder_init (&unwinder
);
2306 MonoContext new_ctx
;
2308 int clause_index_start
= 0;
2309 gboolean unwind_res
= TRUE
;
2311 StackFrameInfo frame
;
2316 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2318 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2319 g_list_free (trace_ips
);
2323 switch (frame
.type
) {
2324 case FRAME_TYPE_DEBUGGER_INVOKE
:
2325 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2326 case FRAME_TYPE_TRAMPOLINE
:
2327 case FRAME_TYPE_INTERP_TO_MANAGED
:
2328 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2331 case FRAME_TYPE_INTERP
:
2332 case FRAME_TYPE_MANAGED
:
2335 g_assert_not_reached ();
2339 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2344 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2346 ip
= MONO_CONTEXT_GET_IP (ctx
);
2349 method
= jinfo_get_method (ji
);
2350 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2352 if (mini_debug_options
.reverse_pinvoke_exceptions
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2353 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2354 "The native frame called the managed method:\n%s\n",
2355 mono_method_full_name (method
, TRUE
));
2358 if (method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
2359 // avoid giant stack traces during a stack overflow
2360 if (frame_count
< 1000) {
2361 trace_ips
= g_list_prepend (trace_ips
, ip
);
2362 trace_ips
= g_list_prepend (trace_ips
, get_generic_info_from_stack_frame (ji
, ctx
));
2363 trace_ips
= g_list_prepend (trace_ips
, ji
);
2367 if (method
->dynamic
)
2368 dynamic_methods
= g_slist_prepend (dynamic_methods
, method
);
2370 if (stack_overflow
) {
2371 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2373 free_stack
= 0xffffff;
2376 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2377 result
= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
;
2381 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2382 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2383 gboolean filtered
= FALSE
;
2386 * During stack overflow, wait till the unwinding frees some stack
2387 * space before running handlers/finalizers.
2389 if (free_stack
<= (64 * 1024))
2392 if (is_address_protected (ji
, ei
, ip
)) {
2394 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2397 * Have to unwrap RuntimeWrappedExceptions if the
2398 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2400 if (non_exception
&& !wrap_non_exception_throws (method
))
2401 ex_obj
= non_exception
;
2405 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2406 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2408 #ifndef DISABLE_PERFCOUNTERS
2409 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_filters
);
2412 if (!ji
->is_interp
) {
2413 #ifndef MONO_CROSS_COMPILE
2414 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2416 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2418 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2419 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2421 g_assert (!ji
->from_llvm
);
2422 /* store the exception object in bp + ei->exvar_offset */
2423 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2427 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2429 * Pass the original il clause index to the landing pad so it can
2430 * branch to the landing pad associated with the il clause.
2431 * This is needed because llvm compiled code assumes that the EH
2432 * code always branches to the innermost landing pad.
2435 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2439 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2441 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2442 jit_tls
->orig_ex_ctx_set
= TRUE
;
2443 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2444 jit_tls
->orig_ex_ctx_set
= FALSE
;
2447 if (ji
->is_interp
) {
2448 /* The filter ends where the exception handler starts */
2449 filtered
= mini_get_interp_callbacks ()->run_filter (&frame
, (MonoException
*)ex_obj
, i
, ei
->data
.filter
, ei
->handler_start
);
2451 filtered
= call_filter (ctx
, ei
->data
.filter
);
2453 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2454 if (filtered
&& out_filter_idx
)
2455 *out_filter_idx
= filter_idx
;
2461 g_list_free (trace_ips
);
2462 /* mono_debugger_agent_handle_exception () needs this */
2463 mini_set_abort_threshold (&frame
);
2464 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2465 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2466 *catch_frame
= frame
;
2467 result
= MONO_FIRST_PASS_HANDLED
;
2472 ERROR_DECL (isinst_error
); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2473 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (ex_obj
, catch_class
, error
)) {
2474 /* runtime invokes catch even unhandled exceptions */
2475 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
);
2476 g_list_free (trace_ips
);
2481 /* mono_debugger_agent_handle_exception () needs this */
2483 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2484 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2485 *catch_frame
= frame
;
2486 result
= MONO_FIRST_PASS_HANDLED
;
2487 if (method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2488 //try to find threadpool_perform_wait_callback_method
2489 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &new_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2490 while (unwind_res
) {
2491 if (frame
.ji
&& !frame
.ji
->is_trampoline
&& jinfo_get_method (frame
.ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2492 *last_mono_wrapper_runtime_invoke
= FALSE
;
2495 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &new_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2500 mono_error_cleanup (isinst_error
);
2507 g_assert_not_reached ();
2511 * We implement delaying of aborts when in finally blocks by reusing the
2512 * abort protected block mechanism. The problem is that when throwing an
2513 * exception in a finally block we don't get to exit the protected block.
2514 * We exit it here when unwinding. Given that the order of the clauses
2515 * in the jit info is from inner clauses to the outer clauses, when we
2516 * want to exit the finally blocks inner to the clause that handles the
2517 * exception, we need to search up to its index.
2519 * FIXME We should do this inside interp, but with mixed mode we can
2520 * resume directly, without giving control back to the interp.
2523 interp_exit_finally_abort_blocks (MonoJitInfo
*ji
, int start_clause
, int end_clause
, gpointer ip
)
2526 for (i
= start_clause
; i
< end_clause
; i
++) {
2527 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2528 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
&&
2529 ip
>= ei
->handler_start
&&
2530 ip
< ei
->data
.handler_end
) {
2531 mono_threads_end_abort_protected_block ();
2536 static MonoException
*
2537 mono_get_exception_runtime_wrapped_checked (MonoObject
*wrapped_exception_raw
, MonoError
*error
)
2539 HANDLE_FUNCTION_ENTER ();
2540 MONO_HANDLE_DCL (MonoObject
, wrapped_exception
);
2541 MonoExceptionHandle ret
= mono_get_exception_runtime_wrapped_handle (wrapped_exception
, error
);
2542 HANDLE_FUNCTION_RETURN_OBJ (ret
);
2546 * mono_handle_exception_internal:
2547 * \param ctx saved processor state
2548 * \param obj the exception object
2549 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2552 mono_handle_exception_internal (MonoContext
*ctx
, MonoObject
*obj
, gboolean resume
, MonoJitInfo
**out_ji
)
2555 MonoDomain
*domain
= mono_domain_get ();
2556 MonoJitInfo
*ji
, *prev_ji
;
2557 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2558 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2559 MonoLMF
*lmf
= mono_get_lmf ();
2560 MonoException
*mono_ex
;
2561 gboolean stack_overflow
= FALSE
;
2562 MonoContext initial_ctx
;
2564 int frame_count
= 0;
2565 gint32 filter_idx
, first_filter_idx
= 0;
2567 MonoObject
*ex_obj
= NULL
;
2568 MonoObject
*non_exception
= NULL
;
2571 gboolean is_caught_unmanaged
= FALSE
;
2572 gboolean last_mono_wrapper_runtime_invoke
= TRUE
;
2574 g_assert (ctx
!= NULL
);
2576 MonoException
*ex
= mono_get_exception_null_reference ();
2577 MonoString
*msg
= mono_string_new_checked (domain
, "Object reference not set to an instance of an object", error
);
2578 mono_error_assert_ok (error
);
2579 MONO_OBJECT_SETREF_INTERNAL (ex
, message
, msg
);
2580 obj
= (MonoObject
*)ex
;
2584 * Allocate a new exception object instead of the preconstructed ones.
2586 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
) {
2588 * It is not a good idea to try and put even more pressure on the little stack available.
2589 * obj = mono_get_exception_stack_overflow ();
2591 stack_overflow
= TRUE
;
2593 else if (obj
== (MonoObject
*)domain
->null_reference_ex
) {
2594 obj
= (MonoObject
*)mono_get_exception_null_reference ();
2597 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2598 mono_error_assert_ok (error
);
2599 non_exception
= obj
;
2600 obj
= (MonoObject
*)mono_get_exception_runtime_wrapped_checked (obj
, error
);
2601 mono_error_assert_ok (error
);
2604 mono_ex
= (MonoException
*)obj
;
2606 if (mini_debug_options
.suspend_on_exception
) {
2607 mono_runtime_printf_err ("Exception thrown, suspending...");
2612 if (mono_ex
->caught_in_unmanaged
)
2613 is_caught_unmanaged
= TRUE
;
2616 if (mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2617 mono_ex
= (MonoException
*)obj
;
2619 mono_error_assert_ok (error
);
2623 if (mono_ex
&& jit_tls
->class_cast_from
) {
2624 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "InvalidCastException")) {
2625 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2626 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2627 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
2628 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2631 if (!is_ok (error
)) {
2632 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg
);
2633 mono_error_assert_ok (error
);
2637 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "ArrayTypeMismatchException")) {
2638 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2639 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2640 char *msg
= g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name
, to_name
);
2641 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2644 if (!is_ok (error
)) {
2645 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg
);
2646 mono_error_assert_ok (error
);
2653 call_filter
= (int (*)(MonoContext
*, void*))mono_get_call_filter ();
2655 g_assert (jit_tls
->end_of_stack
);
2656 g_assert (jit_tls
->abort_func
);
2659 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2660 * end up being TRUE on any code path.
2662 memcpy (&jit_tls
->orig_ex_ctx
, ctx
, sizeof (MonoContext
));
2665 MonoContext ctx_cp
= *ctx
;
2666 if (mono_trace_is_enabled ()) {
2668 MonoMethod
*system_exception_get_message
= mono_class_get_method_from_name_checked (mono_defaults
.exception_class
, "get_Message", 0, 0, error
);
2669 mono_error_cleanup (error
);
2671 MonoMethod
*get_message
= system_exception_get_message
== NULL
? NULL
: mono_object_get_virtual_method_internal (obj
, system_exception_get_message
);
2672 MonoObject
*message
;
2673 const char *type_name
= m_class_get_name (mono_object_class (mono_ex
));
2675 if (get_message
== NULL
) {
2677 } else if (!strcmp (type_name
, "OutOfMemoryException") || !strcmp (type_name
, "StackOverflowException")) {
2679 msg
= g_strdup_printf ("(No exception message for: %s)\n", type_name
);
2681 MonoObject
*exc
= NULL
;
2682 message
= mono_runtime_try_invoke (get_message
, obj
, NULL
, &exc
, error
);
2683 g_assert (exc
== NULL
);
2684 mono_error_assert_ok (error
);
2688 msg
= mono_string_to_utf8_checked_internal ((MonoString
*) message
, error
);
2689 if (!is_ok (error
)) {
2690 mono_error_cleanup (error
);
2691 msg
= g_strdup ("(error while display System.Exception.Message property)");
2694 msg
= g_strdup ("(System.Exception.Message property not available)");
2697 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)(gsize
)mono_native_thread_id_get (), m_class_get_name_space (mono_object_class (obj
)), m_class_get_name (mono_object_class (obj
)), msg
);
2699 if (mono_ex
&& mono_trace_eval_exception (mono_object_class (mono_ex
)))
2700 mono_print_thread_dump_from_ctx (ctx
);
2702 jit_tls
->orig_ex_ctx_set
= TRUE
;
2703 MONO_PROFILER_RAISE (exception_throw
, (obj
));
2704 jit_tls
->orig_ex_ctx_set
= FALSE
;
2706 #ifdef ENABLE_NETCORE
2707 mono_first_chance_exception_internal (obj
);
2710 StackFrameInfo catch_frame
;
2711 MonoFirstPassResult res
;
2712 res
= handle_exception_first_pass (&ctx_cp
, obj
, &first_filter_idx
, &ji
, &prev_ji
, non_exception
, &catch_frame
, &last_mono_wrapper_runtime_invoke
);
2714 if (res
== MONO_FIRST_PASS_UNHANDLED
) {
2715 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2716 /* Reached the top interpreted frames, but there might be native frames above us */
2717 throw_exception (obj
, TRUE
);
2718 g_assert_not_reached ();
2720 if (mini_debug_options
.break_on_exc
)
2722 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2724 // FIXME: This runs managed code so it might cause another stack overflow when
2725 // we are handling a stack overflow
2726 mini_set_abort_threshold (&catch_frame
);
2727 mono_unhandled_exception_internal (obj
);
2729 gboolean unhandled
= FALSE
;
2732 * The exceptions caught by the mono_runtime_invoke_checked () calls
2733 * in the threadpool needs to be treated as unhandled (#669836).
2735 * FIXME: The check below is hackish, but its hard to distinguish
2736 * these runtime invoke calls from others in the runtime.
2738 #ifndef ENABLE_NETCORE
2739 if (ji
&& jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2740 if (prev_ji
&& jinfo_get_method (prev_ji
) == mono_defaults
.threadpool_perform_wait_callback_method
)
2746 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2747 else if (!ji
|| (jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
)) {
2748 if (last_mono_wrapper_runtime_invoke
&& !mono_thread_internal_current ()->threadpool_thread
) {
2749 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2750 if (mini_get_debug_options ()->top_runtime_invoke_unhandled
) {
2751 mini_set_abort_threshold (&catch_frame
);
2752 mono_unhandled_exception_internal (obj
);
2755 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2758 else if (res
!= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
)
2759 if (!is_caught_unmanaged
)
2760 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2769 unwinder_init (&unwinder
);
2772 MonoContext new_ctx
;
2774 int clause_index_start
= 0;
2775 gboolean unwind_res
= TRUE
;
2776 StackFrameInfo frame
;
2781 ji
= jit_tls
->resume_state
.ji
;
2782 new_ctx
= jit_tls
->resume_state
.new_ctx
;
2783 clause_index_start
= jit_tls
->resume_state
.clause_index
;
2784 lmf
= jit_tls
->resume_state
.lmf
;
2785 first_filter_idx
= jit_tls
->resume_state
.first_filter_idx
;
2786 filter_idx
= jit_tls
->resume_state
.filter_idx
;
2789 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2791 *(mono_get_lmf_addr ()) = lmf
;
2793 jit_tls
->abort_func (obj
);
2794 g_assert_not_reached ();
2796 switch (frame
.type
) {
2797 case FRAME_TYPE_DEBUGGER_INVOKE
:
2798 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2799 case FRAME_TYPE_TRAMPOLINE
:
2800 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2803 case FRAME_TYPE_INTERP_TO_MANAGED
:
2805 case FRAME_TYPE_INTERP
:
2806 case FRAME_TYPE_MANAGED
:
2809 g_assert_not_reached ();
2812 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2817 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2819 ip
= MONO_CONTEXT_GET_IP (ctx
);
2821 method
= jinfo_get_method (ji
);
2823 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2825 if (stack_overflow
) {
2826 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2828 free_stack
= 0xffffff;
2831 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2832 MonoGCHandle handle
= mono_gchandle_new_internal (obj
, FALSE
);
2833 MONO_STACKDATA (stackptr
);
2835 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr
);
2837 ftnptr_eh_callback (handle
);
2838 g_error ("Did not expect ftnptr_eh_callback to return.");
2841 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2842 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2843 gboolean filtered
= FALSE
;
2846 * During stack overflow, wait till the unwinding frees some stack
2847 * space before running handlers/finalizers.
2849 if (free_stack
<= (64 * 1024))
2852 if (is_address_protected (ji
, ei
, ip
)) {
2854 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2857 * Have to unwrap RuntimeWrappedExceptions if the
2858 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2860 if (non_exception
&& !wrap_non_exception_throws (method
))
2861 ex_obj
= non_exception
;
2865 if (((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
))) {
2866 #ifndef MONO_CROSS_COMPILE
2867 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2868 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2870 g_assert (!ji
->from_llvm
);
2871 /* store the exception object in bp + ei->exvar_offset */
2872 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2877 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2879 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2882 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2884 * Filter clauses should only be run in the
2885 * first pass of exception handling.
2887 filtered
= (filter_idx
== first_filter_idx
);
2892 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
2893 mono_object_isinst_checked (ex_obj
, catch_class
, error
)) || filtered
) {
2895 * This guards against the situation that we abort a thread that is executing a finally clause
2896 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2897 * check for this situation here and resume interruption if we are below the guarded block.
2899 if (G_UNLIKELY (jit_tls
->handler_block
)) {
2900 gboolean is_outside
= FALSE
;
2901 gpointer prot_bp
= MONO_CONTEXT_GET_BP (&jit_tls
->handler_block_context
);
2902 gpointer catch_bp
= MONO_CONTEXT_GET_BP (ctx
);
2903 //FIXME make this stack direction aware
2905 if (catch_bp
> prot_bp
) {
2907 } else if (catch_bp
== prot_bp
) {
2908 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2909 * So we check if the catch handler_start is protected by the guarded handler protected region
2912 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2913 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2914 * There aren't any further finally/fault handler blocks down the stack over this exception.
2915 * This must be ensured by the code that installs the guard trampoline.
2917 g_assert (ji
== mini_jit_info_table_find (domain
, (char *)MONO_CONTEXT_GET_IP (&jit_tls
->handler_block_context
), NULL
));
2919 if (!is_address_protected (ji
, jit_tls
->handler_block
, ei
->handler_start
)) {
2924 jit_tls
->handler_block
= NULL
;
2925 mono_thread_resume_interruption (TRUE
); /*We ignore the exception here, it will be raised later*/
2929 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2930 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2933 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2934 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2935 * clause. Since we specifically want to indicate that we're executing the
2936 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2937 * instead of ei->flags.
2939 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2940 jit_tls
->orig_ex_ctx_set
= TRUE
;
2941 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, MONO_EXCEPTION_CLAUSE_NONE
, ex_obj
));
2942 jit_tls
->orig_ex_ctx_set
= FALSE
;
2945 mini_set_abort_threshold (&frame
);
2948 interp_exit_finally_abort_blocks (ji
, clause_index_start
, i
, ip
);
2950 * ctx->pc points into the interpreter, after the call which transitioned to
2951 * JITted code. Store the unwind state into the
2952 * interpeter state, then resume, the interpreter will unwind itself until
2953 * it reaches the target frame and will continue execution from there.
2954 * The resuming is kinda hackish, from the native code standpoint, it looks
2955 * like the call which transitioned to JITted code has succeeded, but the
2956 * return value register etc. is not set, so we have to be careful.
2958 mini_get_interp_callbacks ()->set_resume_state (jit_tls
, ex_obj
, ei
, frame
.interp_frame
, ei
->handler_start
);
2959 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2960 /* ip == 0 means an interpreter frame */
2961 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
2962 mono_arch_undo_ip_adjustment (ctx
);
2964 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2967 #ifndef DISABLE_PERFCOUNTERS
2968 mono_atomic_fetch_add_i32 (&mono_perfcounters
->exceptions_depth
, frame_count
);
2970 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2971 jit_tls
->handling_stack_ovf
= FALSE
;
2975 mono_error_cleanup (error
);
2976 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) {
2977 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2978 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2980 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2981 jit_tls
->orig_ex_ctx_set
= TRUE
;
2982 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2983 jit_tls
->orig_ex_ctx_set
= FALSE
;
2986 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2987 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2988 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2990 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2991 jit_tls
->orig_ex_ctx_set
= TRUE
;
2992 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2993 jit_tls
->orig_ex_ctx_set
= FALSE
;
2996 #ifndef DISABLE_PERFCOUNTERS
2997 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_finallys
);
3000 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
|| ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
3002 if (ji
->from_llvm
) {
3004 * LLVM compiled finally handlers follow the design
3005 * of the c++ ehabi, i.e. they call a resume function
3006 * at the end instead of returning to the caller.
3007 * So save the exception handling state,
3008 * mono_resume_unwind () will call us again to continue
3011 jit_tls
->resume_state
.ex_obj
= obj
;
3012 jit_tls
->resume_state
.ji
= ji
;
3013 jit_tls
->resume_state
.clause_index
= i
+ 1;
3014 jit_tls
->resume_state
.ctx
= *ctx
;
3015 jit_tls
->resume_state
.new_ctx
= new_ctx
;
3016 jit_tls
->resume_state
.lmf
= lmf
;
3017 jit_tls
->resume_state
.first_filter_idx
= first_filter_idx
;
3018 jit_tls
->resume_state
.filter_idx
= filter_idx
;
3019 mini_set_abort_threshold (&frame
);
3020 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
3023 mini_set_abort_threshold (&frame
);
3025 gboolean has_ex
= mini_get_interp_callbacks ()->run_finally (&frame
, i
, ei
->handler_start
, ei
->data
.handler_end
);
3028 * If run_finally didn't resume to a context, it means that the handler frame
3029 * is linked to the frame calling finally through interpreter frames. This
3030 * means that we will reach the handler frame by resuming the current context.
3032 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
3033 mono_arch_undo_ip_adjustment (ctx
);
3037 call_filter (ctx
, ei
->handler_start
);
3045 interp_exit_finally_abort_blocks (ji
, clause_index_start
, ji
->num_clauses
, ip
);
3047 if (MONO_PROFILER_ENABLED (method_exception_leave
) &&
3048 mono_profiler_get_call_instrumentation_flags (method
) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
) {
3049 jit_tls
->orig_ex_ctx_set
= TRUE
;
3050 MONO_PROFILER_RAISE (method_exception_leave
, (method
, ex_obj
));
3051 jit_tls
->orig_ex_ctx_set
= FALSE
;
3057 g_assert_not_reached ();
3061 * mono_debugger_run_finally:
3062 * \param start_ctx saved processor state
3063 * This method is called by the Mono Debugger to call all \c finally clauses of the
3064 * current stack frame. It's used when the user issues a \c return command to make
3065 * the current stack frame return. After returning from this method, the debugger
3066 * unwinds the stack one frame and gives control back to the user.
3067 * NOTE: This method is only used when running inside the Mono Debugger.
3070 mono_debugger_run_finally (MonoContext
*start_ctx
)
3072 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
3073 MonoDomain
*domain
= mono_domain_get ();
3074 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3075 MonoLMF
*lmf
= mono_get_lmf ();
3076 MonoContext ctx
, new_ctx
;
3077 MonoJitInfo
*ji
, rji
;
3082 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
3083 if (!ji
|| ji
== (gpointer
)-1)
3087 call_filter
= (int (*)(MonoContext
*, void *))mono_get_call_filter ();
3089 for (i
= 0; i
< ji
->num_clauses
; i
++) {
3090 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
3092 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (&ctx
)) &&
3093 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
3094 call_filter (&ctx
, ei
->handler_start
);
3100 * mono_handle_exception:
3101 * \param ctx saved processor state
3102 * \param obj the exception object
3104 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3108 mono_handle_exception (MonoContext
*ctx
, gpointer void_obj
)
3110 MonoObject
*obj
= (MonoObject
*)void_obj
;
3112 MONO_REQ_GC_UNSAFE_MODE
;
3114 #ifndef DISABLE_PERFCOUNTERS
3115 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_thrown
);
3118 return mono_handle_exception_internal (ctx
, obj
, FALSE
, NULL
);
3121 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3123 #ifndef MONO_ARCH_USE_SIGACTION
3124 #error "Can't use sigaltstack without sigaction"
3128 mono_setup_altstack (MonoJitTlsData
*tls
)
3132 guint8
*staddr
= NULL
;
3133 #if defined(TARGET_OSX) || defined(_AIX)
3135 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3136 * stack pages. Stack overflow on main thread will kill the app.
3138 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3139 * do this for thread 1 with its stack at the top of memory. Other threads seem
3140 * fine for the altstack guard page, though.
3142 gboolean disable_stack_guard
= mono_threads_platform_is_main_thread ();
3144 gboolean disable_stack_guard
= FALSE
;
3147 if (mono_running_on_valgrind ())
3150 mono_thread_info_get_stack_bounds (&staddr
, &stsize
);
3154 tls
->end_of_stack
= staddr
+ stsize
;
3155 tls
->stack_size
= stsize
;
3157 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3159 if (!disable_stack_guard
) {
3160 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
3161 tls
->stack_ovf_guard_size
= ALIGN_TO (MONO_STACK_OVERFLOW_GUARD_SIZE
, mono_pagesize ());
3163 g_assert ((guint8
*)&sa
>= (guint8
*)tls
->stack_ovf_guard_base
+ tls
->stack_ovf_guard_size
);
3165 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
3166 /* mprotect can fail for the main thread stack */
3167 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
);
3169 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
3170 tls
->stack_ovf_valloced
= TRUE
;
3172 g_warning ("couldn't allocate guard page, continue without it");
3173 tls
->stack_ovf_guard_base
= NULL
;
3174 tls
->stack_ovf_guard_size
= 0;
3179 /* Setup an alternate signal stack */
3180 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
);
3181 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3183 g_assert (tls
->signal_stack
);
3185 sa
.ss_sp
= tls
->signal_stack
;
3186 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3188 g_assert (sigaltstack (&sa
, NULL
) == 0);
3190 if (tls
->stack_ovf_guard_base
)
3191 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
);
3193 mono_gc_register_altstack (staddr
, stsize
, tls
->signal_stack
, tls
->signal_stack_size
);
3198 mono_free_altstack (MonoJitTlsData
*tls
)
3203 sa
.ss_sp
= tls
->signal_stack
;
3204 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3205 sa
.ss_flags
= SS_DISABLE
;
3206 err
= sigaltstack (&sa
, NULL
);
3207 g_assert (err
== 0);
3209 if (tls
->signal_stack
)
3210 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3212 if (!tls
->stack_ovf_guard_base
)
3214 if (tls
->stack_ovf_valloced
)
3215 mono_vfree (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3217 mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3220 #elif HAVE_API_SUPPORT_WIN32_SET_THREAD_STACK_GUARANTEE && defined(HOST_WIN32)
3222 mono_setup_altstack (MonoJitTlsData
*tls
)
3224 // Alt stack is not supported on Windows, but we can use this point to at least
3225 // reserve a stack guarantee of available stack memory when handling stack overflow.
3226 ULONG new_stack_guarantee
= (ULONG
)ALIGN_TO (MONO_STACK_OVERFLOW_GUARD_SIZE
, ((gssize
)mono_pagesize ()));
3227 SetThreadStackGuarantee (&new_stack_guarantee
);
3231 mono_free_altstack (MonoJitTlsData
*tls
)
3235 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3238 mono_setup_altstack (MonoJitTlsData
*tls
)
3243 mono_free_altstack (MonoJitTlsData
*tls
)
3247 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3250 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*siginfo
, guint8
* fault_addr
)
3258 /* we got a stack overflow in the soft-guard pages
3259 * There are two cases:
3260 * 1) managed code caused the overflow: we unprotect the soft-guard page
3261 * and let the arch-specific code trigger the exception handling mechanism
3262 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3263 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3264 * and hope we can continue with those enabled, at least until the hard-guard page
3265 * is hit. The alternative to continuing here is to just print a message and abort.
3266 * We may add in the future the code to protect the pages again in the codepath
3267 * when we return from unmanaged to managed code.
3269 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
3270 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
3271 gboolean handled
= FALSE
;
3273 mono_mprotect (jit_tls
->stack_ovf_guard_base
, jit_tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3274 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3276 mono_arch_handle_altstack_exception (ctx
, siginfo
, fault_addr
, TRUE
);
3281 /* We print a message: after this even managed stack overflows
3282 * may crash the runtime
3284 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx
), fault_addr
);
3285 if (!jit_tls
->handling_stack_ovf
) {
3286 jit_tls
->handling_stack_ovf
= 1;
3288 /*fprintf (stderr, "Already handling stack overflow\n");*/
3297 MonoMethod
*omethod
;
3299 } PrintOverflowUserData
;
3302 print_overflow_stack_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3304 MonoMethod
*method
= NULL
;
3305 PrintOverflowUserData
*user_data
= (PrintOverflowUserData
*)data
;
3308 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3309 method
= jinfo_get_method (frame
->ji
);
3312 if (user_data
->count
== 0) {
3313 /* The first frame is in its prolog, so a line number cannot be computed */
3314 user_data
->count
++;
3318 /* If this is a one method overflow, skip the other instances */
3319 if (method
== user_data
->omethod
)
3322 location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, mono_domain_get ());
3323 mono_runtime_printf_err (" %s", location
);
3326 if (user_data
->count
== 1) {
3327 mono_runtime_printf_err (" <...>");
3328 user_data
->omethod
= method
;
3330 user_data
->omethod
= NULL
;
3333 user_data
->count
++;
3335 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame
->native_offset
);
3341 mono_handle_hard_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, MonoContext
*mctx
, guint8
* fault_addr
)
3343 PrintOverflowUserData ud
;
3345 /* we don't do much now, but we can warn the user with a useful message */
3346 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx
), fault_addr
);
3348 mono_runtime_printf_err ("Stacktrace:");
3350 memset (&ud
, 0, sizeof (ud
));
3352 mono_walk_stack_with_ctx (print_overflow_stack_frame
, mctx
, MONO_UNWIND_LOOKUP_ACTUAL_METHOD
, &ud
);
3358 print_stack_frame_signal_safe (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3360 MonoMethod
*method
= NULL
;
3362 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3363 method
= jinfo_get_method (frame
->ji
);
3366 const char *name_space
= m_class_get_name_space (method
->klass
);
3367 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
);
3369 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame
->native_offset
);
3375 static G_GNUC_UNUSED gboolean
3376 print_stack_frame_to_string (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3378 GString
*p
= (GString
*)data
;
3379 MonoMethod
*method
= NULL
;
3381 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3382 method
= jinfo_get_method (frame
->ji
);
3384 if (method
&& frame
->domain
) {
3385 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
3386 g_string_append_printf (p
, " %s\n", location
);
3389 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
3394 #ifndef MONO_CROSS_COMPILE
3397 * mono_handle_native_crash:
3399 * Handle a native crash (e.g. SIGSEGV) while in native code by
3400 * printing diagnostic information and aborting.
3403 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3405 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3407 #ifdef MONO_ARCH_USE_SIGACTION
3408 struct sigaction sa
;
3409 sa
.sa_handler
= SIG_DFL
;
3410 sigemptyset (&sa
.sa_mask
);
3413 /* Remove our SIGABRT handler */
3414 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
3416 /* On some systems we get a SIGILL when calling abort (), because it might
3417 * fail to raise SIGABRT */
3418 g_assert (sigaction (SIGILL
, &sa
, NULL
) != -1);
3420 /* Remove SIGCHLD, it uses the finalizer thread */
3421 g_assert (sigaction (SIGCHLD
, &sa
, NULL
) != -1);
3423 /* Remove SIGQUIT, we are already dumping threads */
3424 g_assert (sigaction (SIGQUIT
, &sa
, NULL
) != -1);
3428 if (mini_debug_options
.suspend_on_native_crash
) {
3429 g_async_safe_printf ("Received %s, suspending...\n", signal
);
3431 // Sleep for 1 second.
3432 g_usleep (1000 * 1000);
3437 * A crash indicates something went very wrong so we can no longer depend
3438 * on anything working. So try to print out lots of diagnostics, starting
3439 * with ones which have a greater chance of working.
3442 g_async_safe_printf("\n=================================================================\n");
3443 g_async_safe_printf("\tNative Crash Reporting\n");
3444 g_async_safe_printf("=================================================================\n");
3445 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal
);
3446 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3447 g_async_safe_printf("used by your application.\n");
3448 g_async_safe_printf("=================================================================\n");
3449 mono_dump_native_crash_info (signal
, mctx
, info
);
3451 /* !jit_tls means the thread was not registered with the runtime */
3452 // This must be below the native crash dump, because we can't safely
3453 // do runtime state probing after we have walked the managed stack here.
3454 if (jit_tls
&& mono_thread_internal_current () && mctx
) {
3455 g_async_safe_printf ("\n=================================================================\n");
3456 g_async_safe_printf ("\tManaged Stacktrace:\n");
3457 g_async_safe_printf ("=================================================================\n");
3459 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
);
3460 g_async_safe_printf ("=================================================================\n");
3463 mono_post_native_crash_handler (signal
, mctx
, info
, mono_do_crash_chaining
);
3469 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3471 g_assert_not_reached ();
3474 #endif /* !MONO_CROSS_COMPILE */
3477 mono_print_thread_dump_internal (void *sigctx
, MonoContext
*start_ctx
)
3479 MonoInternalThread
*thread
= mono_thread_internal_current ();
3486 text
= g_string_new (0);
3488 mono_gstring_append_thread_name (text
, thread
);
3490 g_string_append_printf (text
, " tid=%p this=%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
3491 mono_thread_internal_describe (thread
, text
);
3492 g_string_append (text
, "\n");
3495 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
3497 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
3499 mono_sigctx_to_monoctx (sigctx
, &ctx
);
3501 mono_walk_stack_with_ctx (print_stack_frame_to_string
, &ctx
, MONO_UNWIND_LOOKUP_ALL
, text
);
3503 mono_runtime_printf ("%s", text
->str
);
3505 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3506 OutputDebugStringA(text
->str
);
3509 g_string_free (text
, TRUE
);
3510 mono_runtime_stdout_fflush ();
3514 * mono_print_thread_dump:
3516 * Print information about the current thread to stdout.
3517 * \p sigctx can be NULL, allowing this to be called from gdb.
3520 mono_print_thread_dump (void *sigctx
)
3522 mono_print_thread_dump_internal (sigctx
, NULL
);
3526 mono_print_thread_dump_from_ctx (MonoContext
*ctx
)
3528 mono_print_thread_dump_internal (NULL
, ctx
);
3532 * mono_resume_unwind:
3534 * This is called by a trampoline from LLVM compiled finally clauses to continue
3538 mono_resume_unwind (MonoContext
*ctx
)
3540 MONO_REQ_GC_UNSAFE_MODE
;
3542 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3543 MonoContext new_ctx
;
3545 MONO_CONTEXT_SET_IP (ctx
, MONO_CONTEXT_GET_IP (&jit_tls
->resume_state
.ctx
));
3546 MONO_CONTEXT_SET_SP (ctx
, MONO_CONTEXT_GET_SP (&jit_tls
->resume_state
.ctx
));
3549 mono_handle_exception_internal (&new_ctx
, (MonoObject
*)jit_tls
->resume_state
.ex_obj
, TRUE
, NULL
);
3551 mono_restore_context (&new_ctx
);
3557 MonoJitExceptionInfo
*ei
;
3558 } FindHandlerBlockData
;
3561 find_last_handler_block (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3565 FindHandlerBlockData
*pdata
= (FindHandlerBlockData
*)data
;
3566 MonoJitInfo
*ji
= frame
->ji
;
3571 ip
= MONO_CONTEXT_GET_IP (ctx
);
3573 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
3574 MonoJitExceptionInfo
*ei
= ji
->clauses
+ i
;
3575 if (ei
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
3577 /*If ip points to the first instruction it means the handler block didn't start
3578 so we can leave its execution to the EH machinery*/
3579 if (ei
->handler_start
<= ip
&& ip
< ei
->data
.handler_end
) {
3591 install_handler_block_guard (MonoJitInfo
*ji
, MonoContext
*ctx
)
3594 MonoJitExceptionInfo
*clause
= NULL
;
3598 ip
= MONO_CONTEXT_GET_IP (ctx
);
3600 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
3601 clause
= &ji
->clauses
[i
];
3602 if (clause
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
3604 if (clause
->handler_start
<= ip
&& clause
->data
.handler_end
> ip
)
3608 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3609 g_assert (i
< ji
->num_clauses
);
3612 bp
= (guint8
*)MONO_CONTEXT_GET_BP (ctx
);
3613 *(bp
+ clause
->exvar_offset
) = 1;
3617 * Finds the bottom handler block running and install a block guard if needed.
3620 mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
)
3622 FindHandlerBlockData data
= { 0 };
3623 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
];
3625 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3626 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3628 if (!jit_tls
|| jit_tls
->handler_block
)
3631 /* Do an async safe stack walk */
3632 mono_thread_info_set_is_async_context (TRUE
);
3633 mono_walk_stack_with_state (find_last_handler_block
, ctx
, MONO_UNWIND_NONE
, &data
);
3634 mono_thread_info_set_is_async_context (FALSE
);
3639 memcpy (&jit_tls
->handler_block_context
, &data
.ctx
, sizeof (MonoContext
));
3641 install_handler_block_guard (data
.ji
, &data
.ctx
);
3643 jit_tls
->handler_block
= data
.ei
;
3649 mono_uninstall_current_handler_block_guard (void)
3651 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3653 jit_tls
->handler_block
= NULL
;
3658 mono_current_thread_has_handle_block_guard (void)
3660 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3661 return jit_tls
&& jit_tls
->handler_block
!= NULL
;
3665 mono_set_cast_details (MonoClass
*from
, MonoClass
*to
)
3667 MonoJitTlsData
*jit_tls
= NULL
;
3669 if (mini_debug_options
.better_cast_details
) {
3670 jit_tls
= mono_tls_get_jit_tls ();
3671 jit_tls
->class_cast_from
= from
;
3672 jit_tls
->class_cast_to
= to
;
3677 /*returns false if the thread is not attached*/
3679 mono_thread_state_init_from_sigctx (MonoThreadUnwindState
*ctx
, void *sigctx
)
3681 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3688 mono_sigctx_to_monoctx (sigctx
, &ctx
->ctx
);
3690 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3691 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3692 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3695 mono_thread_state_init (ctx
);
3698 if (!ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] || !ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
])
3706 mono_thread_state_init (MonoThreadUnwindState
*ctx
)
3708 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3710 #if defined(MONO_CROSS_COMPILE)
3711 ctx
->valid
= FALSE
; //A cross compiler doesn't need to suspend.
3712 #elif MONO_ARCH_HAS_MONO_CONTEXT
3713 MONO_CONTEXT_GET_CURRENT (ctx
->ctx
);
3715 g_error ("Use a null sigctx requires a working mono-context");
3718 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3719 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3720 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
? thread
->jit_data
: NULL
;
3726 mono_thread_state_init_from_monoctx (MonoThreadUnwindState
*ctx
, MonoContext
*mctx
)
3728 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3735 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3736 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3737 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3742 /*returns false if the thread is not attached*/
3744 mono_thread_state_init_from_current (MonoThreadUnwindState
*ctx
)
3746 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3747 MONO_ARCH_CONTEXT_DEF
3749 mono_arch_flush_register_windows ();
3751 if (!thread
|| !thread
->jit_data
) {
3755 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
->ctx
, mono_thread_state_init_from_current
);
3757 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3758 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3759 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3765 mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
)
3767 mono_handle_exception (ctx
, (MonoObject
*)exc
);
3768 mono_restore_context (ctx
);
3771 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3773 mono_setup_async_callback (MonoContext
*ctx
, void (*async_cb
)(void *fun
), gpointer user_data
)
3775 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3776 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3777 jit_tls
->ex_ctx
= *ctx
;
3779 mono_arch_setup_async_callback (ctx
, async_cb
, user_data
);
3781 g_error ("This target doesn't support mono_arch_setup_async_callback");
3786 * mono_restore_context:
3788 * Call the architecture specific restore context function.
3791 mono_restore_context (MonoContext
*ctx
)
3793 static void (*restore_context
) (MonoContext
*);
3795 if (!restore_context
)
3796 restore_context
= (void (*)(MonoContext
*))mono_get_restore_context ();
3797 restore_context (ctx
);
3798 g_assert_not_reached ();
3802 * mono_jinfo_get_unwind_info:
3804 * Return the unwind info for JI.
3807 mono_jinfo_get_unwind_info (MonoJitInfo
*ji
, guint32
*unwind_info_len
)
3809 if (ji
->has_unwind_info
) {
3810 /* The address/length in the MonoJitInfo structure itself */
3811 MonoUnwindJitInfo
*info
= mono_jit_info_get_unwind_info (ji
);
3812 *unwind_info_len
= info
->unw_info_len
;
3813 return info
->unw_info
;
3814 } else if (ji
->from_aot
)
3815 return mono_aot_get_unwind_info (ji
, unwind_info_len
);
3817 return mono_get_cached_unwind_info (ji
->unwind_info
, unwind_info_len
);
3821 mono_jinfo_get_epilog_size (MonoJitInfo
*ji
)
3823 MonoArchEHJitInfo
*info
;
3825 info
= mono_jit_info_get_arch_eh_info (ji
);
3828 return info
->epilog_size
;
3832 * mono_install_ftnptr_eh_callback:
3834 * Install a callback that should be called when there is a managed exception
3835 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3836 * managed exception to a native exception, to properly unwind the native
3837 * stack; this native exception will then be converted back to a managed
3838 * exception in their managed-to-native wrapper.
3841 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback
)
3843 ftnptr_eh_callback
= callback
;
3847 * LLVM/Bitcode exception handling.
3851 throw_exception (MonoObject
*ex
, gboolean rethrow
)
3853 MONO_REQ_GC_UNSAFE_MODE
;
3856 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3857 MonoException
*mono_ex
;
3859 if (!mono_object_isinst_checked (ex
, mono_defaults
.exception_class
, error
)) {
3860 mono_error_assert_ok (error
);
3861 mono_ex
= mono_get_exception_runtime_wrapped_checked (ex
, error
);
3862 mono_error_assert_ok (error
);
3863 jit_tls
->thrown_non_exc
= mono_gchandle_new_internal (ex
, FALSE
);
3866 mono_ex
= (MonoException
*)ex
;
3869 jit_tls
->thrown_exc
= mono_gchandle_new_internal ((MonoObject
*)mono_ex
, FALSE
);
3872 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3873 GList
*l
, *ips
= NULL
;
3876 _Unwind_Backtrace (build_stack_trace
, &ips
);
3877 /* The list contains ip-gshared info pairs */
3879 ips
= g_list_reverse (ips
);
3880 for (l
= ips
; l
; l
= l
->next
) {
3881 trace
= g_list_append (trace
, l
->data
);
3882 trace
= g_list_append (trace
, NULL
);
3883 trace
= g_list_append (trace
, NULL
);
3885 MonoArray
*ips_arr
= mono_glist_to_array (trace
, mono_defaults
.int_class
, error
);
3886 mono_error_assert_ok (error
);
3887 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
3889 g_list_free (trace
);
3893 mono_llvm_cpp_throw_exception ();
3897 mono_llvm_throw_exception (MonoObject
*ex
)
3899 throw_exception (ex
, FALSE
);
3903 mono_llvm_rethrow_exception (MonoObject
*ex
)
3905 throw_exception (ex
, TRUE
);
3909 mono_llvm_raise_exception (MonoException
*e
)
3911 mono_llvm_throw_exception ((MonoObject
*)e
);
3915 mono_llvm_reraise_exception (MonoException
*e
)
3917 mono_llvm_rethrow_exception ((MonoObject
*)e
);
3921 mono_llvm_throw_corlib_exception (guint32 ex_token_index
)
3923 guint32 ex_token
= MONO_TOKEN_TYPE_DEF
| ex_token_index
;
3926 ex
= mono_exception_from_token (m_class_get_image (mono_defaults
.exception_class
), ex_token
);
3928 mono_llvm_throw_exception ((MonoObject
*)ex
);
3932 * mono_llvm_resume_exception:
3934 * Resume exception propagation.
3937 mono_llvm_resume_exception (void)
3939 mono_llvm_cpp_throw_exception ();
3943 * mono_llvm_load_exception:
3945 * Return the currently thrown exception.
3948 mono_llvm_load_exception (void)
3951 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3953 MonoException
*mono_ex
= (MonoException
*)mono_gchandle_get_target_internal (jit_tls
->thrown_exc
);
3955 MonoArray
*ta
= mono_ex
->trace_ips
;
3958 GList
*trace_ips
= NULL
;
3959 gpointer ip
= MONO_RETURN_ADDRESS ();
3961 size_t upper
= mono_array_length_internal (ta
);
3963 for (int i
= 0; i
< upper
; i
+= TRACE_IP_ENTRY_SIZE
) {
3964 gpointer curr_ip
= mono_array_get_internal (ta
, gpointer
, i
);
3965 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
3966 gpointer p
= mono_array_get_internal (ta
, gpointer
, i
+ j
);
3967 trace_ips
= g_list_append (trace_ips
, p
);
3973 // FIXME: Does this work correctly for rethrows?
3974 // We may be discarding useful information
3975 // when this gets GC'ed
3976 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips
, mono_defaults
.int_class
, error
);
3977 mono_error_assert_ok (error
);
3978 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
3979 g_list_free (trace_ips
);
3982 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3984 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, 0, error
));
3985 mono_error_assert_ok (error
);
3986 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, stack_trace
, mono_array_new_checked (mono_domain_get (), mono_defaults
.stack_frame_class
, 0, error
));
3987 mono_error_assert_ok (error
);
3990 return &mono_ex
->object
;
3994 * mono_llvm_clear_exception:
3996 * Mark the currently thrown exception as handled.
3999 mono_llvm_clear_exception (void)
4001 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
4002 mono_gchandle_free_internal (jit_tls
->thrown_exc
);
4003 jit_tls
->thrown_exc
= 0;
4004 if (jit_tls
->thrown_non_exc
)
4005 mono_gchandle_free_internal (jit_tls
->thrown_non_exc
);
4006 jit_tls
->thrown_non_exc
= 0;
4008 mono_memory_barrier ();
4012 * mono_llvm_match_exception:
4014 * Return the innermost clause containing REGION_START-REGION_END which can handle
4015 * the current exception.
4018 mono_llvm_match_exception (MonoJitInfo
*jinfo
, guint32 region_start
, guint32 region_end
, gpointer rgctx
, MonoObject
*this_obj
)
4021 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
4025 g_assert (jit_tls
->thrown_exc
);
4026 exc
= mono_gchandle_get_target_internal (jit_tls
->thrown_exc
);
4027 if (jit_tls
->thrown_non_exc
) {
4029 * Have to unwrap RuntimeWrappedExceptions if the
4030 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
4032 if (!wrap_non_exception_throws (jinfo_get_method (jinfo
)))
4033 exc
= mono_gchandle_get_target_internal (jit_tls
->thrown_non_exc
);
4036 for (int i
= 0; i
< jinfo
->num_clauses
; i
++) {
4037 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
4038 MonoClass
*catch_class
;
4040 if (! (ei
->try_offset
== region_start
&& ei
->try_offset
+ ei
->try_len
== region_end
) )
4043 catch_class
= ei
->data
.catch_class
;
4044 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class
))) {
4045 MonoGenericContext context
;
4046 MonoType
*inflated_type
;
4048 g_assert (rgctx
|| this_obj
);
4049 context
= mono_get_generic_context_from_stack_frame (jinfo
, rgctx
? rgctx
: this_obj
->vtable
);
4050 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
4051 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
4053 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
4054 mono_metadata_free_type (inflated_type
);
4057 // FIXME: Handle edge cases handled in get_exception_catch_class
4058 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (exc
, catch_class
, error
)) {
4059 index
= ei
->clause_index
;
4062 mono_error_assert_ok (error
);
4064 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
4065 g_assert_not_reached ();
4072 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4073 G_EXTERN_C _Unwind_Reason_Code
mono_debug_personality (int a
, _Unwind_Action b
,
4074 uint64_t c
, struct _Unwind_Exception
*d
, struct _Unwind_Context
*e
)
4076 g_assert_not_reached ();
4079 G_EXTERN_C
void mono_debug_personality (void);
4082 mono_debug_personality (void)
4084 g_assert_not_reached ();