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>
75 #include "debugger-agent.h"
76 #include "debugger-engine.h"
77 #include "seq-points.h"
78 #include "llvm-runtime.h"
79 #include "mini-llvm.h"
80 #include "aot-runtime.h"
81 #include "mini-runtime.h"
82 #include "interp/interp.h"
85 #include "mini-llvm-cpp.h"
92 #ifndef MONO_ARCH_CONTEXT_DEF
93 #define MONO_ARCH_CONTEXT_DEF
96 #if !defined(DISABLE_CRASH_REPORTING)
99 #include "mono/utils/mono-tls-inline.h"
102 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
103 * This structure represents one entry.
104 * This should consists of pointers only.
109 gpointer generic_info
;
110 /* Only for interpreter frames */
114 /* Number of words in trace_ips belonging to one entry */
115 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
117 static gpointer restore_context_func
, call_filter_func
;
118 static gpointer throw_exception_func
, rethrow_exception_func
, rethrow_preserve_exception_func
;
119 static gpointer throw_corlib_exception_func
;
121 static MonoFtnPtrEHCallback ftnptr_eh_callback
;
123 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
);
124 static void mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
);
125 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
);
126 static gboolean
mono_current_thread_has_handle_block_guard (void);
127 static gboolean
mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
);
128 static void mono_uninstall_current_handler_block_guard (void);
129 static gboolean
mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
);
130 static void throw_exception (MonoObject
*ex
, gboolean rethrow
);
132 static void mono_summarize_managed_stack (MonoThreadSummary
*out
);
133 static void mono_summarize_unmanaged_stack (MonoThreadSummary
*out
);
134 static void mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
);
135 static void mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
);
136 static void mono_crash_reporting_allow_all_native_libraries (void);
139 first_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer addr
)
141 gpointer
*data
= (gpointer
*)addr
;
147 // FIXME: Happens with llvm_only
152 *data
= frame
->frame_addr
;
158 mono_thread_get_managed_sp (void)
160 gpointer addr
= NULL
;
161 mono_walk_stack (first_managed
, MONO_UNWIND_SIGNAL_SAFE
, &addr
);
166 mini_clear_abort_threshold (void)
168 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
169 jit_tls
->abort_exc_stack_threshold
= NULL
;
173 mini_set_abort_threshold (StackFrameInfo
*frame
)
175 gpointer sp
= frame
->frame_addr
;
176 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
177 // Only move it up, to avoid thrown/caught
178 // exceptions lower in the stack from triggering
180 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
181 if (!jit_tls
->abort_exc_stack_threshold
|| above_threshold
) {
182 jit_tls
->abort_exc_stack_threshold
= sp
;
186 // Note: In the case that the frame is above where the thread abort
187 // was set we bump the threshold so that functions called from the new,
188 // higher threshold don't trigger the thread abort exception
190 mini_above_abort_threshold (void)
192 gpointer sp
= mono_thread_get_managed_sp ();
193 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
198 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
201 jit_tls
->abort_exc_stack_threshold
= sp
;
203 return above_threshold
;
207 mono_get_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
210 if (mono_find_prev_seq_point_for_native_offset (domain
, method
, native_offset
, NULL
, &sp
))
216 mono_exceptions_init (void)
218 MonoRuntimeExceptionHandlingCallbacks cbs
;
219 if (mono_ee_features
.use_aot_trampolines
) {
220 restore_context_func
= mono_aot_get_trampoline ("restore_context");
221 call_filter_func
= mono_aot_get_trampoline ("call_filter");
222 throw_exception_func
= mono_aot_get_trampoline ("throw_exception");
223 rethrow_exception_func
= mono_aot_get_trampoline ("rethrow_exception");
224 rethrow_preserve_exception_func
= mono_aot_get_trampoline ("rethrow_preserve_exception");
225 } else if (!mono_llvm_only
) {
228 restore_context_func
= mono_arch_get_restore_context (&info
, FALSE
);
229 mono_tramp_info_register (info
, NULL
);
230 call_filter_func
= mono_arch_get_call_filter (&info
, FALSE
);
231 mono_tramp_info_register (info
, NULL
);
232 throw_exception_func
= mono_arch_get_throw_exception (&info
, FALSE
);
233 mono_tramp_info_register (info
, NULL
);
234 rethrow_exception_func
= mono_arch_get_rethrow_exception (&info
, FALSE
);
235 mono_tramp_info_register (info
, NULL
);
236 rethrow_preserve_exception_func
= mono_arch_get_rethrow_preserve_exception (&info
, FALSE
);
237 mono_tramp_info_register (info
, NULL
);
240 mono_arch_exceptions_init ();
242 cbs
.mono_walk_stack_with_ctx
= mono_runtime_walk_stack_with_ctx
;
243 cbs
.mono_walk_stack_with_state
= mono_walk_stack_with_state
;
244 cbs
.mono_summarize_managed_stack
= mono_summarize_managed_stack
;
245 cbs
.mono_summarize_unmanaged_stack
= mono_summarize_unmanaged_stack
;
246 cbs
.mono_summarize_exception
= mono_summarize_exception
;
247 cbs
.mono_register_native_library
= mono_crash_reporting_register_native_library
;
248 cbs
.mono_allow_all_native_libraries
= mono_crash_reporting_allow_all_native_libraries
;
250 if (mono_llvm_only
) {
251 cbs
.mono_raise_exception
= mono_llvm_raise_exception
;
252 cbs
.mono_reraise_exception
= mono_llvm_reraise_exception
;
254 cbs
.mono_raise_exception
= (void (*)(MonoException
*))mono_get_throw_exception ();
255 cbs
.mono_reraise_exception
= (void (*)(MonoException
*))mono_get_rethrow_exception ();
257 cbs
.mono_raise_exception_with_ctx
= mono_raise_exception_with_ctx
;
258 cbs
.mono_exception_walk_trace
= mono_exception_walk_trace
;
259 cbs
.mono_install_handler_block_guard
= mono_install_handler_block_guard
;
260 cbs
.mono_uninstall_current_handler_block_guard
= mono_uninstall_current_handler_block_guard
;
261 cbs
.mono_current_thread_has_handle_block_guard
= mono_current_thread_has_handle_block_guard
;
262 cbs
.mono_clear_abort_threshold
= mini_clear_abort_threshold
;
263 cbs
.mono_above_abort_threshold
= mini_above_abort_threshold
;
264 mono_install_eh_callbacks (&cbs
);
265 mono_install_get_seq_point (mono_get_seq_point_for_native_offset
);
269 mono_get_throw_exception (void)
271 g_assert (throw_exception_func
);
272 return throw_exception_func
;
276 mono_get_rethrow_exception (void)
278 g_assert (rethrow_exception_func
);
279 return rethrow_exception_func
;
283 mono_get_rethrow_preserve_exception (void)
285 g_assert (rethrow_preserve_exception_func
);
286 return rethrow_preserve_exception_func
;
290 no_call_filter (void)
292 g_assert_not_reached ();
296 mono_get_call_filter (void)
298 /* This is called even in llvmonly mode etc. */
299 if (!call_filter_func
)
300 return (gpointer
)no_call_filter
;
301 return call_filter_func
;
305 mono_get_restore_context (void)
307 g_assert (restore_context_func
);
308 return restore_context_func
;
312 mono_get_throw_corlib_exception (void)
314 gpointer code
= NULL
;
317 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
318 if (throw_corlib_exception_func
)
319 return throw_corlib_exception_func
;
321 if (mono_ee_features
.use_aot_trampolines
)
322 code
= mono_aot_get_trampoline ("throw_corlib_exception");
324 code
= mono_arch_get_throw_corlib_exception (&info
, FALSE
);
325 mono_tramp_info_register (info
, NULL
);
328 mono_memory_barrier ();
330 throw_corlib_exception_func
= code
;
332 return throw_corlib_exception_func
;
336 * mono_get_throw_exception_addr:
338 * Return an address which stores the result of
339 * mono_get_throw_exception.
342 mono_get_throw_exception_addr (void)
344 return &throw_exception_func
;
348 mono_get_rethrow_preserve_exception_addr (void)
350 return &rethrow_preserve_exception_func
;
354 is_address_protected (MonoJitInfo
*ji
, MonoJitExceptionInfo
*ei
, gpointer ip
)
356 MonoTryBlockHoleTableJitInfo
*table
;
361 if (ei
->try_start
> ip
|| ip
>= ei
->try_end
)
364 if (!ji
->has_try_block_holes
)
367 table
= mono_jit_info_get_try_block_hole_table_info (ji
);
368 offset
= (guint32
)((char*)ip
- (char*)ji
->code_start
);
369 clause
= (guint16
)(ei
- ji
->clauses
);
370 g_assert (clause
< ji
->num_clauses
);
372 for (i
= 0; i
< table
->num_holes
; ++i
) {
373 MonoTryBlockHoleJitInfo
*hole
= &table
->holes
[i
];
374 if (hole
->clause
== clause
&& hole
->offset
<= offset
&& hole
->offset
+ hole
->length
> offset
)
380 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
383 static gboolean show_native_addresses
= TRUE
;
385 static gboolean show_native_addresses
= FALSE
;
388 static _Unwind_Reason_Code
389 build_stack_trace (struct _Unwind_Context
*frame_ctx
, void *state
)
391 MonoDomain
*domain
= mono_domain_get ();
392 uintptr_t ip
= _Unwind_GetIP (frame_ctx
);
394 if (show_native_addresses
|| mono_jit_info_table_find (domain
, (char*)ip
)) {
395 GList
**trace_ips
= (GList
**)state
;
396 *trace_ips
= g_list_prepend (*trace_ips
, (gpointer
)ip
);
399 return _URC_NO_REASON
;
403 get_unwind_backtrace (void)
407 _Unwind_Backtrace (build_stack_trace
, &ips
);
409 return g_slist_reverse (ips
);
415 get_unwind_backtrace (void)
423 arch_unwind_frame (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
424 MonoJitInfo
*ji
, MonoContext
*ctx
,
425 MonoContext
*new_ctx
, MonoLMF
**lmf
,
426 host_mgreg_t
**save_locations
,
427 StackFrameInfo
*frame
)
430 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
431 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
433 memset (frame
, 0, sizeof (StackFrameInfo
));
438 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
440 * This LMF entry is created by the soft debug code to mark transitions to
441 * managed code done during invokes.
443 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
444 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
445 } else if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT
|| ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
446 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED
;
447 frame
->interp_exit_data
= ext
->interp_exit_data
;
448 if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
449 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
450 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
453 g_assert_not_reached ();
456 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~3);
462 return mono_arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
468 * Translate between the mono_arch_unwind_frame function and the old API.
471 find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
472 MonoContext
*new_ctx
, MonoLMF
**lmf
, gboolean
*managed
)
474 StackFrameInfo frame
;
477 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
479 /* Avoid costly table lookup during stack overflow */
480 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
483 ji
= mini_jit_info_table_find (domain
, ip
, NULL
);
488 err
= arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, NULL
, &frame
);
490 return (MonoJitInfo
*)-1;
492 if (*lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
494 * Remove any unused lmf.
495 * Mask out the lower bits which might be used to hold additional information.
497 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
500 /* Convert between the new and the old APIs */
501 switch (frame
.type
) {
502 case FRAME_TYPE_MANAGED
:
506 case FRAME_TYPE_TRAMPOLINE
:
508 case FRAME_TYPE_MANAGED_TO_NATIVE
:
512 memset (res
, 0, sizeof (MonoJitInfo
));
513 res
->d
.method
= frame
.method
;
516 case FRAME_TYPE_DEBUGGER_INVOKE
: {
520 * The normal exception handling code can't handle this frame, so just
523 ji
= find_jit_info (domain
, jit_tls
, res
, NULL
, new_ctx
, &tmp_ctx
, lmf
, managed
);
524 memcpy (new_ctx
, &tmp_ctx
, sizeof (MonoContext
));
528 g_assert_not_reached ();
533 /* mono_find_jit_info:
535 * This function is used to gather information from @ctx. It return the
536 * MonoJitInfo of the corresponding function, unwinds one stack frame and
537 * stores the resulting context into @new_ctx. It also stores a string
538 * describing the stack location into @trace (if not NULL), and modifies
539 * the @lmf if necessary. @native_offset return the IP offset from the
540 * start of the function or -1 if that info is not available.
543 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
544 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
548 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
550 MonoMethod
*method
= NULL
;
561 ji
= find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
563 if (ji
== (gpointer
)-1)
566 if (ji
&& !ji
->is_trampoline
)
567 method
= jinfo_get_method (ji
);
569 if (managed2
|| (method
&& method
->wrapper_type
)) {
570 const char *real_ip
, *start
;
573 start
= (const char *)ji
->code_start
;
575 /* ctx->ip points into native code */
576 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
578 real_ip
= (const char*)ip
;
580 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
581 offset
= real_ip
- start
;
586 *native_offset
= offset
;
589 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
593 *trace
= mono_debug_print_stack_frame (method
, offset
, domain
);
596 char *fname
= mono_method_full_name (jinfo_get_method (res
), TRUE
);
597 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
606 * mono_find_jit_info_ext:
608 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
610 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
611 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
612 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
613 * to obtain the last managed frame.
614 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
615 * On return, it will be filled with the locations where callee saved registers are saved
616 * by the current frame. This is returned outside of StackFrameInfo because it can be
617 * quite large on some platforms.
618 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
622 mono_find_jit_info_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
623 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
624 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
625 host_mgreg_t
**save_locations
,
626 StackFrameInfo
*frame
)
629 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
631 MonoDomain
*target_domain
= domain
;
632 MonoMethod
*method
= NULL
;
633 gboolean async
= mono_thread_info_is_async_context ();
638 /* Avoid costly table lookup during stack overflow */
639 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
642 ji
= mini_jit_info_table_find_ext (domain
, ip
, TRUE
, &target_domain
);
645 target_domain
= domain
;
648 memset (save_locations
, 0, MONO_MAX_IREGS
* sizeof (host_mgreg_t
*));
650 err
= arch_unwind_frame (target_domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
654 gboolean not_i2m
= frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED
&& frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
656 if (not_i2m
&& *lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
658 * Remove any unused lmf.
659 * Mask out the lower bits which might be used to hold additional information.
661 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
664 if (frame
->ji
&& !frame
->ji
->is_trampoline
&& !frame
->ji
->async
)
665 method
= jinfo_get_method (frame
->ji
);
667 if (frame
->type
== FRAME_TYPE_MANAGED
&& method
) {
668 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
669 frame
->managed
= TRUE
;
672 if (frame
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
) {
674 * This type of frame is just a marker, the caller should unwind once more to get the
675 * last managed frame.
678 frame
->method
= NULL
;
681 frame
->native_offset
= -1;
682 frame
->domain
= target_domain
;
683 frame
->async_context
= async
;
684 frame
->frame_addr
= MONO_CONTEXT_GET_SP (ctx
);
688 if (frame
->type
== FRAME_TYPE_MANAGED
)
689 frame
->method
= method
;
691 if (ji
&& (frame
->managed
|| (method
&& method
->wrapper_type
))) {
692 const char *real_ip
, *start
;
694 start
= (const char *)ji
->code_start
;
695 if (frame
->type
== FRAME_TYPE_MANAGED
)
696 real_ip
= (const char*)ip
;
698 /* ctx->ip points into native code */
699 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
701 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
702 frame
->native_offset
= real_ip
- start
;
704 frame
->native_offset
= -1;
708 *trace
= mono_debug_print_stack_frame (method
, frame
->native_offset
, domain
);
710 if (trace
&& frame
->method
) {
711 char *fname
= mono_method_full_name (frame
->method
, TRUE
);
712 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
722 MonoInterpStackIter interp_iter
;
723 gpointer last_frame_addr
;
727 unwinder_init (Unwinder
*unwinder
)
729 memset (unwinder
, 0, sizeof (Unwinder
));
732 #if defined(__GNUC__) && defined(TARGET_ARM64)
733 /* gcc 4.9.2 seems to miscompile this on arm64 */
734 static __attribute__((optimize("O0"))) gboolean
738 unwinder_unwind_frame (Unwinder
*unwinder
,
739 MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
740 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
741 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
742 host_mgreg_t
**save_locations
,
743 StackFrameInfo
*frame
)
745 if (unwinder
->in_interp
) {
746 memcpy (new_ctx
, ctx
, sizeof (MonoContext
));
748 /* Process debugger invokes */
749 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
750 if (unwinder
->last_frame_addr
< (gpointer
)(*lmf
)) {
751 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
752 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
753 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
754 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~7);
755 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
761 unwinder
->in_interp
= mini_get_interp_callbacks ()->frame_iter_next (&unwinder
->interp_iter
, frame
);
762 if (frame
->type
== FRAME_TYPE_INTERP
) {
763 const gpointer parent
= mini_get_interp_callbacks ()->frame_get_parent (frame
->interp_frame
);
764 unwinder
->last_frame_addr
= parent
;
767 if (!unwinder
->in_interp
)
768 return unwinder_unwind_frame (unwinder
, domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
, save_locations
, frame
);
771 gboolean res
= mono_find_jit_info_ext (domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
,
772 save_locations
, frame
);
775 if (frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
) {
776 unwinder
->in_interp
= TRUE
;
777 mini_get_interp_callbacks ()->frame_iter_init (&unwinder
->interp_iter
, frame
->interp_exit_data
);
779 unwinder
->last_frame_addr
= frame
->frame_addr
;
785 * This function is async-safe.
788 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
790 MonoGenericJitInfo
*gi
;
794 if (!ji
->has_generic_jit_info
)
796 gi
= mono_jit_info_get_generic_jit_info (ji
);
802 * Search location list if available, it contains the precise location of the
803 * argument for every pc offset, even if the method was interrupted while it was in
807 int offset
= (gsize
)MONO_CONTEXT_GET_IP (ctx
) - (gsize
)ji
->code_start
;
810 for (i
= 0; i
< gi
->nlocs
; ++i
) {
811 MonoDwarfLocListEntry
*entry
= &gi
->locations
[i
];
813 if (offset
>= entry
->from
&& (offset
< entry
->to
|| entry
->to
== 0)) {
815 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, entry
->reg
);
817 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, entry
->reg
) + entry
->offset
);
821 g_assert (i
< gi
->nlocs
);
824 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
826 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
830 method
= jinfo_get_method (ji
);
831 if (mono_method_get_context (method
)->method_inst
) {
832 /* A MonoMethodRuntimeGenericContext* */
834 } else if ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) || m_class_is_valuetype (method
->klass
)) {
838 /* Avoid returning a managed object */
839 MonoObject
*this_obj
= (MonoObject
*)info
;
841 return this_obj
->vtable
;
846 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
849 mono_get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
851 MonoGenericContext context
= { NULL
, NULL
};
852 MonoClass
*klass
, *method_container_class
;
855 g_assert (generic_info
);
857 method
= jinfo_get_method (ji
);
858 g_assert (method
->is_inflated
);
859 if (mono_method_get_context (method
)->method_inst
) {
860 MonoMethodRuntimeGenericContext
*mrgctx
= (MonoMethodRuntimeGenericContext
*)generic_info
;
862 klass
= mrgctx
->class_vtable
->klass
;
863 context
.method_inst
= mrgctx
->method_inst
;
864 g_assert (context
.method_inst
);
866 MonoVTable
*vtable
= (MonoVTable
*)generic_info
;
868 klass
= vtable
->klass
;
871 //g_assert (!mono_class_is_gtd (method->klass));
872 if (mono_class_is_ginst (method
->klass
))
873 method_container_class
= mono_class_get_generic_class (method
->klass
)->container_class
;
875 method_container_class
= method
->klass
;
877 /* class might refer to a subclass of method's class */
878 while (!(klass
== method
->klass
|| (mono_class_is_ginst (klass
) && mono_class_get_generic_class (klass
)->container_class
== method_container_class
))) {
879 klass
= m_class_get_parent (klass
);
883 if (mono_class_is_ginst (klass
) || mono_class_is_gtd (klass
))
884 context
.class_inst
= mini_class_get_context (klass
)->class_inst
;
886 if (mono_class_is_ginst (klass
))
887 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass
)->container_class
, method_container_class
));
889 g_assert (mono_class_has_parent_and_ignore_generics (klass
, method_container_class
));
896 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
899 MonoGenericContext context
;
902 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
903 return jinfo_get_method (ji
);
904 context
= mono_get_generic_context_from_stack_frame (ji
, generic_info
);
906 method
= jinfo_get_method (ji
);
907 method
= mono_method_get_declaring_generic_method (method
);
908 method
= mono_class_inflate_generic_method_checked (method
, &context
, error
);
909 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
915 * mono_exception_walk_native_trace:
916 * \param ex The exception object whose frames should be walked
917 * \param func callback to call for each stack frame
918 * \param user_data data passed to the callback
919 * This function walks the stacktrace of an exception. For
920 * each frame the callback function is called with the relevant info.
921 * The walk ends when no more stack frames are found or when the callback
922 * returns a TRUE value.
926 mono_exception_walk_trace (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
930 MONO_ENTER_GC_UNSAFE
;
931 res
= mono_exception_walk_trace_internal (ex
, func
, user_data
);
937 mono_exception_stackframe_obj_walk (MonoStackFrame
*captured_frame
, MonoExceptionFrameWalk func
, gpointer user_data
)
942 gpointer ip
= (gpointer
) (captured_frame
->method_address
+ captured_frame
->native_offset
);
943 MonoJitInfo
*ji
= mono_jit_info_table_find_internal (mono_domain_get (), ip
, TRUE
, TRUE
);
945 // Other domain maybe?
948 MonoMethod
*method
= jinfo_get_method (ji
);
950 gboolean r
= func (method
, (gpointer
) captured_frame
->method_address
, captured_frame
->native_offset
, TRUE
, user_data
);
958 mono_exception_stacktrace_obj_walk (MonoStackTrace
*st
, MonoExceptionFrameWalk func
, gpointer user_data
)
960 int num_captured
= st
->captured_traces
? mono_array_length_internal (st
->captured_traces
) : 0;
961 for (int i
=0; i
< num_captured
; i
++) {
962 MonoStackTrace
*curr_trace
= mono_array_get_fast (st
->captured_traces
, MonoStackTrace
*, i
);
963 mono_exception_stacktrace_obj_walk (curr_trace
, func
, user_data
);
966 int num_frames
= st
->frames
? mono_array_length_internal (st
->frames
) : 0;
967 for (int frame
= 0; frame
< num_frames
; frame
++) {
968 gboolean r
= mono_exception_stackframe_obj_walk (mono_array_get_fast (st
->frames
, MonoStackFrame
*, frame
), func
, user_data
);
977 mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
979 MONO_REQ_GC_UNSAFE_MODE
;
981 MonoDomain
*domain
= mono_domain_get ();
982 MonoArray
*ta
= ex
->trace_ips
;
984 /* Exception is not thrown yet */
988 int len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
989 gboolean otherwise_has_traces
= len
> 0;
991 for (int i
= 0; i
< len
; i
++) {
992 ExceptionTraceIp trace_ip
;
994 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
995 gpointer ip
= trace_ip
.ip
;
996 gpointer generic_info
= trace_ip
.generic_info
;
998 MonoJitInfo
*ji
= NULL
;
1002 ji
= mono_jit_info_table_find (domain
, ip
);
1008 r
= func (NULL
, ip
, 0, FALSE
, user_data
);
1013 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
1014 if (func (method
, ji
->code_start
, (char *) ip
- (char *) ji
->code_start
, TRUE
, user_data
))
1019 ta
= (MonoArray
*) ex
->captured_traces
;
1020 len
= ta
? mono_array_length_internal (ta
) : 0;
1021 gboolean captured_has_traces
= len
> 0;
1023 for (int i
= 0; i
< len
; i
++) {
1024 MonoStackTrace
*captured_trace
= mono_array_get_fast (ta
, MonoStackTrace
*, i
);
1025 if (!captured_trace
)
1028 mono_exception_stacktrace_obj_walk (captured_trace
, func
, user_data
);
1031 return captured_has_traces
|| otherwise_has_traces
;
1035 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
1038 MonoDomain
*domain
= mono_domain_get ();
1040 MonoArray
*ta
= exc
->trace_ips
;
1041 MonoDebugSourceLocation
*location
;
1045 /* Exception is not thrown yet */
1046 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, 0, error
);
1047 mono_error_set_pending_exception (error
);
1051 HANDLE_FUNCTION_ENTER ();
1053 MONO_HANDLE_PIN (ta
);
1055 len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
1057 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0, error
);
1061 MONO_HANDLE_PIN (res
);
1063 MonoObjectHandle sf_h
;
1064 sf_h
= MONO_HANDLE_NEW (MonoObject
, NULL
);
1066 for (i
= skip
; i
< len
; i
++) {
1068 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
1071 MONO_HANDLE_ASSIGN_RAW (sf_h
, sf
);
1073 ExceptionTraceIp trace_ip
;
1074 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
1075 gpointer ip
= trace_ip
.ip
;
1076 gpointer generic_info
= trace_ip
.generic_info
;
1082 ji
= mono_jit_info_table_find (domain
, ip
);
1084 /* Unmanaged frame */
1085 mono_array_setref_internal (res
, i
, sf
);
1090 g_assert (ji
!= NULL
);
1092 if (mono_llvm_only
|| !generic_info
)
1093 /* Can't resolve actual method */
1094 method
= jinfo_get_method (ji
);
1096 method
= get_method_from_stack_frame (ji
, generic_info
);
1097 if (jinfo_get_method (ji
)->wrapper_type
) {
1101 s
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_REFLECTION
);
1102 MonoString
*name
= mono_string_new_checked (domain
, s
, error
);
1106 MONO_OBJECT_SETREF_INTERNAL (sf
, internal_method_name
, name
);
1109 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
1112 MONO_OBJECT_SETREF_INTERNAL (sf
, method
, rm
);
1115 sf
->method_index
= ji
->from_aot
? mono_aot_find_method_index (method
) : 0xffffff;
1116 sf
->method_address
= (gsize
) ji
->code_start
;
1117 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
1120 * mono_debug_lookup_source_location() returns both the file / line number information
1121 * and the IL offset. Note that computing the IL offset is already an expensive
1122 * operation, so we shouldn't call this method twice.
1124 location
= mono_debug_lookup_source_location (jinfo_get_method (ji
), sf
->native_offset
, domain
);
1126 sf
->il_offset
= location
->il_offset
;
1129 if (mono_find_prev_seq_point_for_native_offset (domain
, jinfo_get_method (ji
), sf
->native_offset
, NULL
, &sp
))
1130 sf
->il_offset
= sp
.il_offset
;
1135 if (need_file_info
) {
1136 if (location
&& location
->source_file
) {
1137 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1140 MONO_OBJECT_SETREF_INTERNAL (sf
, filename
, filename
);
1141 sf
->line
= location
->row
;
1142 sf
->column
= location
->column
;
1144 sf
->line
= sf
->column
= 0;
1145 sf
->filename
= NULL
;
1149 mono_debug_free_source_location (location
);
1150 mono_array_setref_internal (res
, i
- skip
, sf
);
1155 mono_error_set_pending_exception (error
);
1158 HANDLE_FUNCTION_RETURN_VAL (res
);
1162 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1165 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1166 if (jit_tls
&& jit_tls
->orig_ex_ctx_set
)
1167 start_ctx
= &jit_tls
->orig_ex_ctx
;
1169 mono_walk_stack_with_ctx (func
, start_ctx
, unwind_options
, user_data
);
1172 * mono_walk_stack_with_ctx:
1173 * Unwind the current thread starting at \p start_ctx.
1174 * If \p start_ctx is null, we capture the current context.
1177 mono_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1179 MonoContext extra_ctx
;
1180 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1181 MONO_ARCH_CONTEXT_DEF
1183 if (!thread
|| !thread
->jit_data
)
1187 mono_arch_flush_register_windows ();
1188 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx
, mono_walk_stack_with_ctx
);
1189 start_ctx
= &extra_ctx
;
1192 mono_walk_stack_full (func
, start_ctx
, mono_domain_get (), thread
->jit_data
, mono_get_lmf (), unwind_options
, user_data
, FALSE
);
1196 * mono_walk_stack_with_state:
1197 * Unwind a thread described by \p state.
1199 * State must be valid (state->valid == TRUE).
1201 * If you are using this function to unwind another thread, make sure it is suspended.
1203 * If \p state is null, we capture the current context.
1206 mono_walk_stack_with_state (MonoJitStackWalk func
, MonoThreadUnwindState
*state
, MonoUnwindOptions unwind_options
, void *user_data
)
1208 MonoThreadUnwindState extra_state
;
1210 g_assert (!mono_thread_info_is_async_context ());
1211 if (!mono_thread_state_init_from_current (&extra_state
))
1213 state
= &extra_state
;
1216 g_assert (state
->valid
);
1218 if (!state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
])
1222 mono_walk_stack_full (func
,
1224 (MonoDomain
*)state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
],
1225 (MonoJitTlsData
*)state
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
],
1226 (MonoLMF
*)state
->unwind_data
[MONO_UNWIND_DATA_LMF
],
1227 unwind_options
, user_data
, FALSE
);
1231 mono_walk_stack (MonoJitStackWalk func
, MonoUnwindOptions options
, void *user_data
)
1233 MonoThreadUnwindState state
;
1234 if (!mono_thread_state_init_from_current (&state
))
1236 mono_walk_stack_with_state (func
, &state
, options
, user_data
);
1240 * mono_walk_stack_full:
1241 * \param func callback to call for each stack frame
1242 * \param domain starting appdomain, can be NULL to use the current domain
1243 * \param unwind_options what extra information the unwinder should gather
1244 * \param start_ctx starting state of the stack walk, can be NULL.
1245 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1246 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1247 * \param user_data data passed to the callback
1248 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1249 * This function walks the stack of a thread, starting from the state
1250 * represented by \p start_ctx. For each frame the callback
1251 * function is called with the relevant info. The walk ends when no more
1252 * managed stack frames are found or when the callback returns a TRUE value.
1255 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
)
1258 MonoContext ctx
, new_ctx
;
1259 StackFrameInfo frame
;
1261 host_mgreg_t
*reg_locations
[MONO_MAX_IREGS
];
1262 host_mgreg_t
*new_reg_locations
[MONO_MAX_IREGS
];
1263 gboolean get_reg_locations
= unwind_options
& MONO_UNWIND_REG_LOCATIONS
;
1264 gboolean async
= mono_thread_info_is_async_context ();
1267 memset (&frame
, 0, sizeof (StackFrameInfo
));
1270 if (mono_llvm_only
) {
1276 ips
= get_unwind_backtrace ();
1277 for (l
= ips
; l
; l
= l
->next
) {
1278 guint8
*ip
= (guint8
*)l
->data
;
1279 memset (&frame
, 0, sizeof (StackFrameInfo
));
1280 frame
.ji
= mini_jit_info_table_find (domain
, ip
, &frame
.domain
);
1281 if (!frame
.ji
|| frame
.ji
->is_trampoline
)
1283 frame
.type
= FRAME_TYPE_MANAGED
;
1284 frame
.method
= jinfo_get_method (frame
.ji
);
1285 // FIXME: Cannot lookup the actual method
1286 frame
.actual_method
= frame
.method
;
1287 if (frame
.type
== FRAME_TYPE_MANAGED
) {
1288 if (!frame
.method
->wrapper_type
|| frame
.method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1289 frame
.managed
= TRUE
;
1291 frame
.native_offset
= ip
- (guint8
*)frame
.ji
->code_start
;
1292 frame
.il_offset
= -1;
1294 if (func (&frame
, NULL
, user_data
))
1303 g_warning ("start_ctx required for stack walk");
1308 g_warning ("domain required for stack walk");
1313 g_warning ("jit_tls required for stack walk");
1317 /*The LMF will be null if the target have no managed frames.*/
1318 /* g_assert (lmf); */
1319 if (async
&& (unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
)) {
1320 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1324 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
1325 memset (reg_locations
, 0, sizeof (reg_locations
));
1327 unwinder_init (&unwinder
);
1329 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
1331 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, get_reg_locations
? new_reg_locations
: NULL
, &frame
);
1335 if (frame
.type
== FRAME_TYPE_TRAMPOLINE
)
1338 if ((unwind_options
& MONO_UNWIND_LOOKUP_IL_OFFSET
) && frame
.ji
) {
1339 MonoDebugSourceLocation
*source
= NULL
;
1341 // Don't do this when we can be in a signal handler
1343 source
= mono_debug_lookup_source_location (jinfo_get_method (frame
.ji
), frame
.native_offset
, domain
);
1345 il_offset
= source
->il_offset
;
1347 MonoSeqPointInfo
*seq_points
= NULL
;
1349 // It's more reliable to look into the global cache if possible
1351 seq_points
= (MonoSeqPointInfo
*) frame
.ji
->seq_points
;
1353 seq_points
= mono_get_seq_points (domain
, jinfo_get_method (frame
.ji
));
1356 if (seq_points
&& mono_seq_point_find_prev_by_native_offset (seq_points
, frame
.native_offset
, &sp
))
1357 il_offset
= sp
.il_offset
;
1361 mono_debug_free_source_location (source
);
1365 frame
.il_offset
= il_offset
;
1367 if ((unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
) && frame
.ji
) {
1368 frame
.actual_method
= get_method_from_stack_frame (frame
.ji
, get_generic_info_from_stack_frame (frame
.ji
, &ctx
));
1370 frame
.actual_method
= frame
.method
;
1373 if (get_reg_locations
)
1374 frame
.reg_locations
= reg_locations
;
1376 if (func (&frame
, &ctx
, user_data
))
1380 if (get_reg_locations
) {
1381 for (int i
= 0; i
< MONO_MAX_IREGS
; ++i
)
1382 if (new_reg_locations
[i
])
1383 reg_locations
[i
] = new_reg_locations
[i
];
1390 #ifdef DISABLE_CRASH_REPORTING
1393 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1399 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1405 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1411 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1417 mono_crash_reporting_allow_all_native_libraries ()
1426 MonoFrameSummary
*frames
;
1429 MonoStackHash
*hashes
;
1431 } MonoSummarizeUserData
;
1434 copy_summary_string_safe (char *dest
, const char *src
)
1436 g_strlcpy (dest
, src
, MONO_MAX_SUMMARY_NAME_LEN
);
1440 fill_frame_managed_info (MonoFrameSummary
*frame
, MonoMethod
* method
)
1442 MonoImage
*image
= mono_class_get_image (method
->klass
);
1443 // Used for hashing, more stable across rebuilds than using GUID
1444 copy_summary_string_safe (frame
->str_descr
, image
->assembly_name
);
1446 frame
->managed_data
.guid
= image
->guid
;
1447 frame
->managed_data
.token
= method
->token
;
1448 frame
->managed_data
.filename
= image
->module_name
;
1450 MonoDotNetHeader
*header
= &image
->image_info
->cli_header
;
1451 frame
->managed_data
.image_size
= header
->nt
.pe_image_size
;
1452 frame
->managed_data
.time_date_stamp
= image
->time_date_stamp
;
1457 char *exported_name
;
1458 } MonoLibAllowlistEntry
;
1460 static GList
*native_library_allowlist
;
1461 static gboolean allow_all_native_libraries
= FALSE
;
1464 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1466 // Examples: libsystem_pthread.dylib -> "pthread"
1467 // Examples: libsystem_platform.dylib -> "platform"
1468 // Examples: mono-sgen -> "mono" from above line
1469 MonoLibAllowlistEntry
*entry
= g_new0 (MonoLibAllowlistEntry
, 1);
1470 entry
->suffix
= g_strdup (module_path
);
1471 entry
->exported_name
= g_strdup (module_name
);
1472 native_library_allowlist
= g_list_append (native_library_allowlist
, entry
);
1476 mono_crash_reporting_allow_all_native_libraries ()
1478 allow_all_native_libraries
= TRUE
;
1482 check_allowlisted_module (const char *in_name
, const char **out_module
)
1484 #ifndef MONO_PRIVATE_CRASHES
1487 if (g_str_has_suffix (in_name
, "mono-sgen")) {
1489 copy_summary_string_safe ((char *) *out_module
, "mono");
1492 if (allow_all_native_libraries
) {
1494 /* for a module name, use the basename of the full path in in_name */
1495 char *basename
= (char *) in_name
, *p
= (char *) in_name
;
1496 while (*p
!= '\0') {
1502 copy_summary_string_safe ((char *) *out_module
, basename
);
1504 copy_summary_string_safe ((char *) *out_module
, "unknown");
1510 for (GList
*cursor
= native_library_allowlist
; cursor
; cursor
= cursor
->next
) {
1511 MonoLibAllowlistEntry
*iter
= (MonoLibAllowlistEntry
*) cursor
->data
;
1512 if (!g_str_has_suffix (in_name
, iter
->suffix
))
1515 copy_summary_string_safe ((char *) *out_module
, iter
->exported_name
);
1524 mono_make_portable_ip (intptr_t in_ip
, intptr_t module_base
)
1526 // FIXME: Make generalize away from llvm tools?
1527 // So lldb starts the pointer base at 0x100000000
1528 // and expects to get pointers as (offset + constant)
1531 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1532 // *CoreSymbolicationDT.framework version: 63750*/
1533 intptr_t offset
= in_ip
- module_base
;
1534 intptr_t magic_value
= offset
+ 0x100000000;
1539 mono_get_portable_ip (intptr_t in_ip
, intptr_t *out_ip
, gint32
*out_offset
, const char **out_module
, char *out_name
)
1541 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1542 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1543 // non-recursive lock twice on this thread, and will deadlock.
1544 char sname
[256], fname
[256];
1545 void *saddr
= NULL
, *fbase
= NULL
;
1546 gboolean success
= g_module_address ((void*)in_ip
, fname
, 256, &fbase
, sname
, 256, &saddr
);
1550 if (!check_allowlisted_module (fname
, out_module
))
1553 *out_ip
= mono_make_portable_ip ((intptr_t) saddr
, (intptr_t) fbase
);
1554 *out_offset
= in_ip
- (intptr_t) saddr
;
1556 if (saddr
&& out_name
)
1557 copy_summary_string_safe (out_name
, sname
);
1562 summarize_offset_free_hash (guint64 accum
, MonoFrameSummary
*frame
)
1564 if (!frame
->is_managed
)
1567 // See: mono_ptrarray_hash
1568 guint64 hash_accum
= accum
;
1570 // The assembly and the method token, no offsets
1571 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1572 hash_accum
+= frame
->managed_data
.token
;
1578 summarize_offset_rich_hash (guint64 accum
, MonoFrameSummary
*frame
)
1580 // See: mono_ptrarray_hash
1581 guint64 hash_accum
= accum
;
1583 if (!frame
->is_managed
) {
1584 hash_accum
+= frame
->unmanaged_data
.ip
;
1586 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1587 hash_accum
+= frame
->managed_data
.token
;
1588 hash_accum
+= frame
->managed_data
.il_offset
;
1595 summarize_frame_internal (MonoMethod
*method
, gpointer ip
, size_t native_offset
, int il_offset
, gboolean managed
, gpointer user_data
)
1597 MonoSummarizeUserData
*ud
= (MonoSummarizeUserData
*) user_data
;
1599 gboolean valid_state
= ud
->num_frames
+ 1 < ud
->max_frames
;
1601 ud
->error
= "Exceeded the maximum number of frames";
1605 MonoFrameSummary
*dest
= &ud
->frames
[ud
->num_frames
];
1607 dest
->unmanaged_data
.ip
= (intptr_t) ip
;
1608 dest
->is_managed
= managed
;
1609 dest
->unmanaged_data
.module
[0] = '\0';
1611 if (!managed
&& method
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
&& method
->wrapper_type
< MONO_WRAPPER_NUM
) {
1612 dest
->is_managed
= FALSE
;
1613 dest
->unmanaged_data
.has_name
= TRUE
;
1614 copy_summary_string_safe (dest
->str_descr
, mono_wrapper_type_to_str (method
->wrapper_type
));
1617 #ifndef MONO_PRIVATE_CRASHES
1619 dest
->managed_data
.name
= (char *) method
->name
;
1624 ud
->error
= "Managed method frame, but no provided managed method";
1627 fill_frame_managed_info (dest
, method
);
1628 dest
->managed_data
.native_offset
= native_offset
;
1629 dest
->managed_data
.il_offset
= il_offset
;
1631 dest
->managed_data
.token
= -1;
1635 ud
->hashes
->offset_free_hash
= summarize_offset_free_hash (ud
->hashes
->offset_free_hash
, dest
);
1636 ud
->hashes
->offset_rich_hash
= summarize_offset_rich_hash (ud
->hashes
->offset_rich_hash
, dest
);
1638 // We return FALSE, so we're continuing walking
1639 // And we increment the pointer because we're done with this cell in the array
1645 summarize_frame_managed_walk (MonoMethod
*method
, gpointer ip
, size_t frame_native_offset
, gboolean managed
, gpointer user_data
)
1649 if (managed
&& method
) {
1650 MonoDebugSourceLocation
*location
= mono_debug_lookup_source_location (method
, frame_native_offset
, mono_domain_get ());
1652 il_offset
= location
->il_offset
;
1653 mono_debug_free_source_location (location
);
1657 intptr_t portable_ip
= 0;
1659 mono_get_portable_ip ((intptr_t) ip
, &portable_ip
, &offset
, NULL
, NULL
);
1661 return summarize_frame_internal (method
, (gpointer
) portable_ip
, frame_native_offset
, il_offset
, managed
, user_data
);
1666 summarize_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
1668 // Don't record trampolines between managed frames
1669 if (frame
->ji
&& frame
->ji
->is_trampoline
)
1672 if (frame
->ji
&& (frame
->ji
->is_trampoline
|| frame
->ji
->async
))
1673 return FALSE
; // Keep unwinding
1677 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx
), &ip
, &offset
, NULL
, NULL
);
1678 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1680 gboolean is_managed
= (frame
->type
== FRAME_TYPE_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP
);
1681 MonoMethod
*method
= NULL
;
1682 if (frame
&& frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
1683 method
= jinfo_get_method (frame
->ji
);
1686 method
= jinfo_get_method (frame
->ji
);
1688 return summarize_frame_internal (method
, (gpointer
) ip
, offset
, frame
->il_offset
, is_managed
, data
);
1692 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1694 memset (out
, 0, sizeof (MonoThreadSummary
));
1696 MonoException
*inner_exc
= exc
;
1699 for (exc_index
= 0; exc_index
< MONO_MAX_SUMMARY_EXCEPTIONS
; exc_index
++) {
1700 if (inner_exc
== NULL
)
1703 // Set up state to walk this MonoException's stack
1704 MonoSummarizeUserData data
;
1705 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1706 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1707 data
.num_frames
= 0;
1708 data
.frames
= out
->exceptions
[exc_index
].managed_frames
;
1710 // Accumulate all hashes from all exceptions in traveral order
1711 data
.hashes
= &out
->hashes
;
1713 mono_exception_walk_trace (inner_exc
, summarize_frame_managed_walk
, &data
);
1715 // Save per-MonoException info
1716 out
->exceptions
[exc_index
].managed_exc_type
= inner_exc
->object
.vtable
->klass
;
1717 out
->exceptions
[exc_index
].num_managed_frames
= data
.num_frames
;
1719 // Continue to traverse nesting of exceptions
1720 inner_exc
= (MonoException
*) inner_exc
->inner_ex
;
1723 out
->num_exceptions
= exc_index
;
1728 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1730 MonoSummarizeUserData data
;
1731 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1732 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1733 data
.num_frames
= 0;
1734 data
.frames
= out
->managed_frames
;
1735 data
.hashes
= &out
->hashes
;
1737 // FIXME: collect stack pointer for both and sort frames by SP
1738 // so people can see relative ordering of both managed and unmanaged frames.
1741 // Summarize managed stack
1743 mono_walk_stack_full (summarize_frame
, out
->ctx
, out
->domain
, out
->jit_tls
, out
->lmf
, MONO_UNWIND_LOOKUP_IL_OFFSET
, &data
, TRUE
);
1744 out
->num_managed_frames
= data
.num_frames
;
1746 if (data
.error
!= NULL
)
1747 out
->error_msg
= data
.error
;
1748 out
->is_managed
= (out
->num_managed_frames
!= 0);
1751 // Always runs on the dumped thread
1753 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1755 MONO_ARCH_CONTEXT_DEF
1757 // Summarize unmanaged stack
1759 #ifdef HAVE_BACKTRACE_SYMBOLS
1760 intptr_t frame_ips
[MONO_MAX_SUMMARY_FRAMES
];
1762 out
->num_unmanaged_frames
= backtrace ((void **)frame_ips
, MONO_MAX_SUMMARY_FRAMES
);
1764 for (int i
=0; i
< out
->num_unmanaged_frames
; ++i
) {
1765 intptr_t ip
= frame_ips
[i
];
1766 MonoFrameSummary
*frame
= &out
->unmanaged_frames
[i
];
1767 const char* module_buf
= frame
->unmanaged_data
.module
;
1768 int success
= mono_get_portable_ip (ip
, &frame
->unmanaged_data
.ip
, &frame
->unmanaged_data
.offset
, &module_buf
, (char *) frame
->str_descr
);
1770 /* attempt to look up any managed method at that ip */
1771 /* TODO: Trampolines - follow examples from mono_print_method_from_ip() */
1774 MonoDomain
*domain
= mono_domain_get ();
1775 MonoDomain
*target_domain
;
1776 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
1778 frame
->is_managed
= TRUE
;
1779 if (!ji
->async
&& !ji
->is_trampoline
) {
1780 MonoMethod
*method
= jinfo_get_method (ji
);
1781 fill_frame_managed_info (frame
, method
);
1782 #ifndef MONO_PRIVATE_CRASHES
1783 frame
->managed_data
.name
= method
->name
;
1788 if (!success
&& !ji
) {
1789 frame
->unmanaged_data
.ip
= ip
;
1793 if (out
->unmanaged_frames
[i
].str_descr
[0] != '\0')
1794 out
->unmanaged_frames
[i
].unmanaged_data
.has_name
= TRUE
;
1796 out
->hashes
.offset_free_hash
= summarize_offset_free_hash (out
->hashes
.offset_free_hash
, frame
);
1797 out
->hashes
.offset_rich_hash
= summarize_offset_rich_hash (out
->hashes
.offset_rich_hash
, frame
);
1801 out
->lmf
= mono_get_lmf ();
1803 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1804 out
->info_addr
= (intptr_t) thread
;
1805 out
->jit_tls
= thread
->jit_data
;
1806 out
->domain
= mono_domain_get ();
1809 out
->ctx
= &out
->ctx_mem
;
1810 mono_arch_flush_register_windows ();
1811 MONO_INIT_CONTEXT_FROM_FUNC (out
->ctx
, mono_summarize_unmanaged_stack
);
1820 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
1821 MonoReflectionMethod
**method
,
1822 gint32
*iloffset
, gint32
*native_offset
,
1823 MonoString
**file
, gint32
*line
, gint32
*column
)
1826 MonoDomain
*domain
= mono_domain_get ();
1827 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1828 MonoLMF
*lmf
= mono_get_lmf ();
1829 MonoJitInfo
*ji
= NULL
;
1830 MonoContext ctx
, new_ctx
;
1831 MonoDebugSourceLocation
*location
;
1832 MonoMethod
*jmethod
= NULL
, *actual_method
;
1833 StackFrameInfo frame
;
1838 MONO_ARCH_CONTEXT_DEF
;
1840 g_assert (skip
>= 0);
1842 if (mono_llvm_only
) {
1844 MonoDomain
*frame_domain
;
1845 guint8
*frame_ip
= NULL
;
1847 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1849 ips
= get_unwind_backtrace ();
1850 for (l
= ips
; l
&& skip
>= 0; l
= l
->next
) {
1851 guint8
*ip
= (guint8
*)l
->data
;
1855 ji
= mini_jit_info_table_find (mono_domain_get (), ip
, &frame_domain
);
1856 if (!ji
|| ji
->is_trampoline
)
1859 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1860 jmethod
= jinfo_get_method (ji
);
1861 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1868 /* No way to resolve generic instances */
1869 actual_method
= jmethod
;
1870 *native_offset
= frame_ip
- (guint8
*)ji
->code_start
;
1872 mono_arch_flush_register_windows ();
1873 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
1875 unwinder_init (&unwinder
);
1880 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
1883 switch (frame
.type
) {
1884 case FRAME_TYPE_MANAGED_TO_NATIVE
:
1885 case FRAME_TYPE_DEBUGGER_INVOKE
:
1886 case FRAME_TYPE_TRAMPOLINE
:
1887 case FRAME_TYPE_INTERP_TO_MANAGED
:
1888 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
1890 case FRAME_TYPE_INTERP
:
1891 case FRAME_TYPE_MANAGED
:
1893 *native_offset
= frame
.native_offset
;
1895 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1896 jmethod
= jinfo_get_method (ji
);
1897 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1902 g_assert_not_reached ();
1904 } while (skip
>= 0);
1906 if (frame
.type
== FRAME_TYPE_INTERP
) {
1907 jmethod
= frame
.method
;
1908 actual_method
= frame
.actual_method
;
1910 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &ctx
));
1914 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, actual_method
, NULL
, error
);
1915 if (!is_ok (error
)) {
1916 mono_error_set_pending_exception (error
);
1919 mono_gc_wbarrier_generic_store_internal (method
, (MonoObject
*) rm
);
1921 if (il_offset
!= -1) {
1922 location
= mono_debug_lookup_source_location_by_il (jmethod
, il_offset
, domain
);
1924 location
= mono_debug_lookup_source_location (jmethod
, *native_offset
, domain
);
1927 *iloffset
= location
->il_offset
;
1931 if (need_file_info
) {
1933 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1934 if (!is_ok (error
)) {
1935 mono_error_set_pending_exception (error
);
1938 mono_gc_wbarrier_generic_store_internal (file
, (MonoObject
*)filename
);
1939 *line
= location
->row
;
1940 *column
= location
->column
;
1943 *line
= *column
= 0;
1947 mono_debug_free_source_location (location
);
1953 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
1956 MonoClass
*catch_class
= ei
->data
.catch_class
;
1957 MonoType
*inflated_type
;
1958 MonoGenericContext context
;
1960 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1961 if (!catch_class
|| ei
->flags
!= MONO_EXCEPTION_CLAUSE_NONE
)
1964 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
1966 context
= mono_get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
1968 /* FIXME: we shouldn't inflate but instead put the
1969 type in the rgctx and fetch it from there. It
1970 might be a good idea to do this lazily, i.e. only
1971 when the exception is actually thrown, so as not to
1972 waste space for exception clauses which might never
1974 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
1975 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1977 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
1978 mono_metadata_free_type (inflated_type
);
1984 * mini_jit_info_table_find_ext:
1986 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1987 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1988 * OUT_DOMAIN if it is not NULL.
1991 mini_jit_info_table_find_ext (MonoDomain
*domain
, gpointer addr
, gboolean allow_trampolines
, MonoDomain
**out_domain
)
1994 MonoInternalThread
*t
= mono_thread_internal_current ();
2000 ji
= mono_jit_info_table_find_internal (domain
, addr
, TRUE
, allow_trampolines
);
2003 *out_domain
= domain
;
2007 /* maybe it is shared code, so we also search in the root domain */
2008 if (domain
!= mono_get_root_domain ()) {
2009 ji
= mono_jit_info_table_find_internal (mono_get_root_domain (), addr
, TRUE
, allow_trampolines
);
2012 *out_domain
= mono_get_root_domain ();
2020 refs
= (gpointer
*)((t
->appdomain_refs
) ? *(gpointer
*) t
->appdomain_refs
: NULL
);
2021 for (; refs
&& *refs
; refs
++) {
2022 if (*refs
!= domain
&& *refs
!= mono_get_root_domain ()) {
2023 ji
= mono_jit_info_table_find_internal ((MonoDomain
*) *refs
, addr
, TRUE
, allow_trampolines
);
2026 *out_domain
= (MonoDomain
*) *refs
;
2036 mini_jit_info_table_find (MonoDomain
*domain
, gpointer addr
, MonoDomain
**out_domain
)
2038 return mini_jit_info_table_find_ext (domain
, addr
, FALSE
, out_domain
);
2041 /* Class lazy loading functions */
2042 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr
, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
2045 * wrap_non_exception_throws:
2047 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
2048 * WrapNonExceptionThrows flag set.
2051 wrap_non_exception_throws (MonoMethod
*m
)
2054 MonoAssembly
*ass
= m_class_get_image (m
->klass
)->assembly
;
2055 MonoCustomAttrInfo
* attrs
;
2058 gboolean val
= FALSE
;
2060 if (m
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
2061 MonoDynamicMethod
*dm
= (MonoDynamicMethod
*)m
;
2066 if (ass
->wrap_non_exception_throws_inited
)
2067 return ass
->wrap_non_exception_throws
;
2069 klass
= mono_class_get_runtime_compat_attr_class ();
2071 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
2072 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2074 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
2075 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
2077 int num_named
, named_type
, name_len
;
2080 if (!attr
->ctor
|| attr
->ctor
->klass
!= klass
)
2082 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2083 p
= (const char*)attr
->data
;
2084 g_assert (read16 (p
) == 0x0001);
2086 num_named
= read16 (p
);
2092 /* data_type = *p; */
2095 if (named_type
!= 0x54)
2097 name_len
= mono_metadata_decode_blob_size (p
, &p
);
2098 name
= (char *)g_malloc (name_len
+ 1);
2099 memcpy (name
, p
, name_len
);
2100 name
[name_len
] = 0;
2102 g_assert (!strcmp (name
, "WrapNonExceptionThrows"));
2104 /* The value is a BOOLEAN */
2107 mono_custom_attrs_free (attrs
);
2110 ass
->wrap_non_exception_throws
= val
;
2111 mono_memory_barrier ();
2112 ass
->wrap_non_exception_throws_inited
= TRUE
;
2117 #define MAX_UNMANAGED_BACKTRACE 128
2119 build_native_trace (MonoError
*error
)
2122 /* This puppy only makes sense on mobile, IOW, ARM. */
2123 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2125 void *native_trace
[MAX_UNMANAGED_BACKTRACE
];
2128 size
= backtrace (native_trace
, MAX_UNMANAGED_BACKTRACE
);
2134 res
= mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, size
, error
);
2135 return_val_if_nok (error
, NULL
);
2137 for (i
= 0; i
< size
; i
++)
2138 mono_array_set_internal (res
, gpointer
, i
, native_trace
[i
]);
2146 remove_wrappers_from_trace (GList
**trace_ips_p
)
2148 GList
*trace_ips
= *trace_ips_p
;
2149 GList
*p
= trace_ips
;
2151 /* jit info, generic info, ip */
2153 MonoJitInfo
*jinfo
= (MonoJitInfo
*) p
->data
;
2154 GList
*next_p
= p
->next
->next
->next
;
2155 /* FIXME Maybe remove more wrapper types */
2156 if (jinfo
->d
.method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2157 trace_ips
= g_list_delete_link (trace_ips
, p
->next
->next
);
2158 trace_ips
= g_list_delete_link (trace_ips
, p
->next
);
2159 trace_ips
= g_list_delete_link (trace_ips
, p
);
2164 *trace_ips_p
= trace_ips
;
2167 /* This can be called more than once on a MonoException. */
2169 setup_stack_trace (MonoException
*mono_ex
, GSList
**dynamic_methods
, GList
*trace_ips
, gboolean remove_wrappers
)
2172 GList
*trace_ips_copy
= g_list_copy (trace_ips
);
2173 if (remove_wrappers
)
2174 remove_wrappers_from_trace (&trace_ips_copy
);
2175 trace_ips_copy
= g_list_reverse (trace_ips_copy
);
2177 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips_copy
, mono_defaults
.int_class
, error
);
2178 mono_error_assert_ok (error
);
2179 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
2180 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, native_trace_ips
, build_native_trace (error
));
2181 mono_error_assert_ok (error
);
2182 if (*dynamic_methods
) {
2183 /* These methods could go away anytime, so save a reference to them in the exception object */
2185 MonoMList
*list
= (MonoMList
*)mono_ex
->dynamic_methods
;
2187 for (l
= *dynamic_methods
; l
; l
= l
->next
) {
2188 MonoGCHandle dis_link
;
2189 MonoDomain
*domain
= mono_domain_get ();
2191 if (domain
->method_to_dyn_method
) {
2192 mono_domain_lock (domain
);
2193 dis_link
= (MonoGCHandle
)g_hash_table_lookup (domain
->method_to_dyn_method
, l
->data
);
2194 mono_domain_unlock (domain
);
2196 MonoObject
*o
= mono_gchandle_get_target_internal (dis_link
);
2198 list
= mono_mlist_prepend_checked (list
, o
, error
);
2199 mono_error_assert_ok (error
);
2205 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, dynamic_methods
, list
);
2207 g_slist_free (*dynamic_methods
);
2208 *dynamic_methods
= NULL
;
2211 g_list_free (trace_ips_copy
);
2216 MONO_FIRST_PASS_UNHANDLED
,
2217 MONO_FIRST_PASS_CALLBACK_TO_NATIVE
,
2218 MONO_FIRST_PASS_HANDLED
,
2219 } MonoFirstPassResult
;
2222 * handle_exception_first_pass:
2224 * The first pass of exception handling. Unwind the stack until a catch
2225 * clause which can catch OBJ is found. Store the index of the filter clause
2226 * which caught the exception into OUT_FILTER_IDX. Return
2227 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2228 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2229 * wrapper and an exception handling callback is installed (in which case
2230 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2232 static MonoFirstPassResult
2233 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
)
2236 MonoDomain
*domain
= mono_domain_get ();
2237 MonoJitInfo
*ji
= NULL
;
2238 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2239 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2240 MonoLMF
*lmf
= mono_get_lmf ();
2241 GList
*trace_ips
= NULL
;
2242 GSList
*dynamic_methods
= NULL
;
2243 MonoException
*mono_ex
;
2244 gboolean stack_overflow
= FALSE
;
2245 MonoContext initial_ctx
;
2247 int frame_count
= 0;
2254 MonoFirstPassResult result
= MONO_FIRST_PASS_UNHANDLED
;
2256 g_assert (ctx
!= NULL
);
2257 *last_mono_wrapper_runtime_invoke
= TRUE
;
2258 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2259 stack_overflow
= TRUE
;
2261 mono_ex
= (MonoException
*)obj
;
2262 MonoArray
*initial_trace_ips
= mono_ex
->trace_ips
;
2263 if (initial_trace_ips
) {
2264 int len
= mono_array_length_internal (initial_trace_ips
) / TRACE_IP_ENTRY_SIZE
;
2266 // If we catch in managed/non-wrapper, we don't save the catching frame
2267 if (!mono_ex
->caught_in_unmanaged
)
2270 for (i
= 0; i
< len
; i
++) {
2271 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
2272 gpointer p
= mono_array_get_internal (initial_trace_ips
, gpointer
, (i
* TRACE_IP_ENTRY_SIZE
) + j
);
2273 trace_ips
= g_list_prepend (trace_ips
, p
);
2278 // Reset the state because we're making it be caught somewhere
2279 if (mono_ex
->caught_in_unmanaged
)
2280 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, caught_in_unmanaged
, 0);
2282 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2283 mono_error_assert_ok (error
);
2288 call_filter
= (int (*) (MonoContext
*, void *))mono_get_call_filter ();
2290 g_assert (jit_tls
->end_of_stack
);
2291 g_assert (jit_tls
->abort_func
);
2294 *out_filter_idx
= -1;
2298 *out_prev_ji
= NULL
;
2302 unwinder_init (&unwinder
);
2305 MonoContext new_ctx
;
2307 int clause_index_start
= 0;
2308 gboolean unwind_res
= TRUE
;
2310 StackFrameInfo frame
;
2315 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2317 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2318 g_list_free (trace_ips
);
2322 switch (frame
.type
) {
2323 case FRAME_TYPE_DEBUGGER_INVOKE
:
2324 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2325 case FRAME_TYPE_TRAMPOLINE
:
2326 case FRAME_TYPE_INTERP_TO_MANAGED
:
2327 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2330 case FRAME_TYPE_INTERP
:
2331 case FRAME_TYPE_MANAGED
:
2334 g_assert_not_reached ();
2338 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2343 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2345 ip
= MONO_CONTEXT_GET_IP (ctx
);
2348 method
= jinfo_get_method (ji
);
2349 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2351 if (mini_debug_options
.reverse_pinvoke_exceptions
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2352 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2353 "The native frame called the managed method:\n%s\n",
2354 mono_method_full_name (method
, TRUE
));
2357 if (method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
2358 // avoid giant stack traces during a stack overflow
2359 if (frame_count
< 1000) {
2360 trace_ips
= g_list_prepend (trace_ips
, ip
);
2361 trace_ips
= g_list_prepend (trace_ips
, get_generic_info_from_stack_frame (ji
, ctx
));
2362 trace_ips
= g_list_prepend (trace_ips
, ji
);
2366 if (method
->dynamic
)
2367 dynamic_methods
= g_slist_prepend (dynamic_methods
, method
);
2369 if (stack_overflow
) {
2370 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2372 free_stack
= 0xffffff;
2375 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2376 result
= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
;
2380 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2381 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2382 gboolean filtered
= FALSE
;
2385 * During stack overflow, wait till the unwinding frees some stack
2386 * space before running handlers/finalizers.
2388 if (free_stack
<= (64 * 1024))
2391 if (is_address_protected (ji
, ei
, ip
)) {
2393 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2396 * Have to unwrap RuntimeWrappedExceptions if the
2397 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2399 if (non_exception
&& !wrap_non_exception_throws (method
))
2400 ex_obj
= non_exception
;
2404 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2405 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2407 #ifndef DISABLE_PERFCOUNTERS
2408 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_filters
);
2411 if (!ji
->is_interp
) {
2412 #ifndef MONO_CROSS_COMPILE
2413 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2415 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2417 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2418 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2420 g_assert (!ji
->from_llvm
);
2421 /* store the exception object in bp + ei->exvar_offset */
2422 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2426 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2428 * Pass the original il clause index to the landing pad so it can
2429 * branch to the landing pad associated with the il clause.
2430 * This is needed because llvm compiled code assumes that the EH
2431 * code always branches to the innermost landing pad.
2434 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2438 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2440 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2441 jit_tls
->orig_ex_ctx_set
= TRUE
;
2442 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2443 jit_tls
->orig_ex_ctx_set
= FALSE
;
2446 if (ji
->is_interp
) {
2447 /* The filter ends where the exception handler starts */
2448 filtered
= mini_get_interp_callbacks ()->run_filter (&frame
, (MonoException
*)ex_obj
, i
, ei
->data
.filter
, ei
->handler_start
);
2450 filtered
= call_filter (ctx
, ei
->data
.filter
);
2452 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2453 if (filtered
&& out_filter_idx
)
2454 *out_filter_idx
= filter_idx
;
2460 g_list_free (trace_ips
);
2461 /* mono_debugger_agent_handle_exception () needs this */
2462 mini_set_abort_threshold (&frame
);
2463 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2464 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2465 *catch_frame
= frame
;
2466 result
= MONO_FIRST_PASS_HANDLED
;
2471 ERROR_DECL (isinst_error
); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2472 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (ex_obj
, catch_class
, error
)) {
2473 /* runtime invokes catch even unhandled exceptions */
2474 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
);
2475 g_list_free (trace_ips
);
2480 /* mono_debugger_agent_handle_exception () needs this */
2482 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2483 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2484 *catch_frame
= frame
;
2485 result
= MONO_FIRST_PASS_HANDLED
;
2486 if (method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2487 //try to find threadpool_perform_wait_callback_method
2488 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &new_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2489 while (unwind_res
) {
2490 if (frame
.ji
&& !frame
.ji
->is_trampoline
&& jinfo_get_method (frame
.ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2491 *last_mono_wrapper_runtime_invoke
= FALSE
;
2494 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &new_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2499 mono_error_cleanup (isinst_error
);
2506 g_assert_not_reached ();
2510 * We implement delaying of aborts when in finally blocks by reusing the
2511 * abort protected block mechanism. The problem is that when throwing an
2512 * exception in a finally block we don't get to exit the protected block.
2513 * We exit it here when unwinding. Given that the order of the clauses
2514 * in the jit info is from inner clauses to the outer clauses, when we
2515 * want to exit the finally blocks inner to the clause that handles the
2516 * exception, we need to search up to its index.
2518 * FIXME We should do this inside interp, but with mixed mode we can
2519 * resume directly, without giving control back to the interp.
2522 interp_exit_finally_abort_blocks (MonoJitInfo
*ji
, int start_clause
, int end_clause
, gpointer ip
)
2525 for (i
= start_clause
; i
< end_clause
; i
++) {
2526 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2527 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
&&
2528 ip
>= ei
->handler_start
&&
2529 ip
< ei
->data
.handler_end
) {
2530 mono_threads_end_abort_protected_block ();
2535 static MonoException
*
2536 mono_get_exception_runtime_wrapped_checked (MonoObject
*wrapped_exception_raw
, MonoError
*error
)
2538 HANDLE_FUNCTION_ENTER ();
2539 MONO_HANDLE_DCL (MonoObject
, wrapped_exception
);
2540 MonoExceptionHandle ret
= mono_get_exception_runtime_wrapped_handle (wrapped_exception
, error
);
2541 HANDLE_FUNCTION_RETURN_OBJ (ret
);
2545 * mono_handle_exception_internal:
2546 * \param ctx saved processor state
2547 * \param obj the exception object
2548 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2551 mono_handle_exception_internal (MonoContext
*ctx
, MonoObject
*obj
, gboolean resume
, MonoJitInfo
**out_ji
)
2554 MonoDomain
*domain
= mono_domain_get ();
2555 MonoJitInfo
*ji
, *prev_ji
;
2556 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2557 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2558 MonoLMF
*lmf
= mono_get_lmf ();
2559 MonoException
*mono_ex
;
2560 gboolean stack_overflow
= FALSE
;
2561 MonoContext initial_ctx
;
2563 int frame_count
= 0;
2564 gint32 filter_idx
, first_filter_idx
= 0;
2566 MonoObject
*ex_obj
= NULL
;
2567 MonoObject
*non_exception
= NULL
;
2570 gboolean is_caught_unmanaged
= FALSE
;
2571 gboolean last_mono_wrapper_runtime_invoke
= TRUE
;
2573 g_assert (ctx
!= NULL
);
2575 MonoException
*ex
= mono_get_exception_null_reference ();
2576 MonoString
*msg
= mono_string_new_checked (domain
, "Object reference not set to an instance of an object", error
);
2577 mono_error_assert_ok (error
);
2578 MONO_OBJECT_SETREF_INTERNAL (ex
, message
, msg
);
2579 obj
= (MonoObject
*)ex
;
2583 * Allocate a new exception object instead of the preconstructed ones.
2585 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
) {
2587 * It is not a good idea to try and put even more pressure on the little stack available.
2588 * obj = mono_get_exception_stack_overflow ();
2590 stack_overflow
= TRUE
;
2592 else if (obj
== (MonoObject
*)domain
->null_reference_ex
) {
2593 obj
= (MonoObject
*)mono_get_exception_null_reference ();
2596 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2597 mono_error_assert_ok (error
);
2598 non_exception
= obj
;
2599 obj
= (MonoObject
*)mono_get_exception_runtime_wrapped_checked (obj
, error
);
2600 mono_error_assert_ok (error
);
2603 mono_ex
= (MonoException
*)obj
;
2605 if (mini_debug_options
.suspend_on_exception
) {
2606 mono_runtime_printf_err ("Exception thrown, suspending...");
2611 if (mono_ex
->caught_in_unmanaged
)
2612 is_caught_unmanaged
= TRUE
;
2615 if (mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2616 mono_ex
= (MonoException
*)obj
;
2618 mono_error_assert_ok (error
);
2622 if (mono_ex
&& jit_tls
->class_cast_from
) {
2623 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "InvalidCastException")) {
2624 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2625 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2626 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
2627 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2630 if (!is_ok (error
)) {
2631 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg
);
2632 mono_error_assert_ok (error
);
2636 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "ArrayTypeMismatchException")) {
2637 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2638 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2639 char *msg
= g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name
, to_name
);
2640 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2643 if (!is_ok (error
)) {
2644 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg
);
2645 mono_error_assert_ok (error
);
2652 call_filter
= (int (*)(MonoContext
*, void*))mono_get_call_filter ();
2654 g_assert (jit_tls
->end_of_stack
);
2655 g_assert (jit_tls
->abort_func
);
2658 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2659 * end up being TRUE on any code path.
2661 memcpy (&jit_tls
->orig_ex_ctx
, ctx
, sizeof (MonoContext
));
2664 MonoContext ctx_cp
= *ctx
;
2665 if (mono_trace_is_enabled ()) {
2667 MonoMethod
*system_exception_get_message
= mono_class_get_method_from_name_checked (mono_defaults
.exception_class
, "get_Message", 0, 0, error
);
2668 mono_error_cleanup (error
);
2670 MonoMethod
*get_message
= system_exception_get_message
== NULL
? NULL
: mono_object_get_virtual_method_internal (obj
, system_exception_get_message
);
2671 MonoObject
*message
;
2672 const char *type_name
= m_class_get_name (mono_object_class (mono_ex
));
2674 if (get_message
== NULL
) {
2676 } else if (!strcmp (type_name
, "OutOfMemoryException") || !strcmp (type_name
, "StackOverflowException")) {
2678 msg
= g_strdup_printf ("(No exception message for: %s)\n", type_name
);
2680 MonoObject
*exc
= NULL
;
2681 message
= mono_runtime_try_invoke (get_message
, obj
, NULL
, &exc
, error
);
2682 g_assert (exc
== NULL
);
2683 mono_error_assert_ok (error
);
2687 msg
= mono_string_to_utf8_checked_internal ((MonoString
*) message
, error
);
2688 if (!is_ok (error
)) {
2689 mono_error_cleanup (error
);
2690 msg
= g_strdup ("(error while display System.Exception.Message property)");
2693 msg
= g_strdup ("(System.Exception.Message property not available)");
2696 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
);
2698 if (mono_ex
&& mono_trace_eval_exception (mono_object_class (mono_ex
)))
2699 mono_print_thread_dump_from_ctx (ctx
);
2701 jit_tls
->orig_ex_ctx_set
= TRUE
;
2702 MONO_PROFILER_RAISE (exception_throw
, (obj
));
2703 jit_tls
->orig_ex_ctx_set
= FALSE
;
2705 #ifdef ENABLE_NETCORE
2706 mono_first_chance_exception_internal (obj
);
2709 StackFrameInfo catch_frame
;
2710 MonoFirstPassResult res
;
2711 res
= handle_exception_first_pass (&ctx_cp
, obj
, &first_filter_idx
, &ji
, &prev_ji
, non_exception
, &catch_frame
, &last_mono_wrapper_runtime_invoke
);
2713 if (res
== MONO_FIRST_PASS_UNHANDLED
) {
2714 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2715 /* Reached the top interpreted frames, but there might be native frames above us */
2716 throw_exception (obj
, TRUE
);
2717 g_assert_not_reached ();
2719 if (mini_debug_options
.break_on_exc
)
2721 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2723 // FIXME: This runs managed code so it might cause another stack overflow when
2724 // we are handling a stack overflow
2725 mini_set_abort_threshold (&catch_frame
);
2726 mono_unhandled_exception_internal (obj
);
2728 gboolean unhandled
= FALSE
;
2731 * The exceptions caught by the mono_runtime_invoke_checked () calls
2732 * in the threadpool needs to be treated as unhandled (#669836).
2734 * FIXME: The check below is hackish, but its hard to distinguish
2735 * these runtime invoke calls from others in the runtime.
2737 #ifndef ENABLE_NETCORE
2738 if (ji
&& jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2739 if (prev_ji
&& jinfo_get_method (prev_ji
) == mono_defaults
.threadpool_perform_wait_callback_method
)
2745 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2746 else if (!ji
|| (jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
)) {
2747 if (last_mono_wrapper_runtime_invoke
&& !mono_thread_internal_current ()->threadpool_thread
) {
2748 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2749 if (mini_get_debug_options ()->top_runtime_invoke_unhandled
) {
2750 mini_set_abort_threshold (&catch_frame
);
2751 mono_unhandled_exception_internal (obj
);
2754 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2757 else if (res
!= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
)
2758 if (!is_caught_unmanaged
)
2759 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2768 unwinder_init (&unwinder
);
2771 MonoContext new_ctx
;
2773 int clause_index_start
= 0;
2774 gboolean unwind_res
= TRUE
;
2775 StackFrameInfo frame
;
2780 ji
= jit_tls
->resume_state
.ji
;
2781 new_ctx
= jit_tls
->resume_state
.new_ctx
;
2782 clause_index_start
= jit_tls
->resume_state
.clause_index
;
2783 lmf
= jit_tls
->resume_state
.lmf
;
2784 first_filter_idx
= jit_tls
->resume_state
.first_filter_idx
;
2785 filter_idx
= jit_tls
->resume_state
.filter_idx
;
2788 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2790 *(mono_get_lmf_addr ()) = lmf
;
2792 jit_tls
->abort_func (obj
);
2793 g_assert_not_reached ();
2795 switch (frame
.type
) {
2796 case FRAME_TYPE_DEBUGGER_INVOKE
:
2797 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2798 case FRAME_TYPE_TRAMPOLINE
:
2799 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2802 case FRAME_TYPE_INTERP_TO_MANAGED
:
2804 case FRAME_TYPE_INTERP
:
2805 case FRAME_TYPE_MANAGED
:
2808 g_assert_not_reached ();
2811 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2816 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2818 ip
= MONO_CONTEXT_GET_IP (ctx
);
2820 method
= jinfo_get_method (ji
);
2822 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2824 if (stack_overflow
) {
2825 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2827 free_stack
= 0xffffff;
2830 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2831 MonoGCHandle handle
= mono_gchandle_new_internal (obj
, FALSE
);
2832 MONO_STACKDATA (stackptr
);
2834 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr
);
2836 ftnptr_eh_callback (handle
);
2837 g_error ("Did not expect ftnptr_eh_callback to return.");
2840 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2841 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2842 gboolean filtered
= FALSE
;
2845 * During stack overflow, wait till the unwinding frees some stack
2846 * space before running handlers/finalizers.
2848 if (free_stack
<= (64 * 1024))
2851 if (is_address_protected (ji
, ei
, ip
)) {
2853 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2856 * Have to unwrap RuntimeWrappedExceptions if the
2857 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2859 if (non_exception
&& !wrap_non_exception_throws (method
))
2860 ex_obj
= non_exception
;
2864 if (((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
))) {
2865 #ifndef MONO_CROSS_COMPILE
2866 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2867 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2869 g_assert (!ji
->from_llvm
);
2870 /* store the exception object in bp + ei->exvar_offset */
2871 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2876 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2878 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2881 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2883 * Filter clauses should only be run in the
2884 * first pass of exception handling.
2886 filtered
= (filter_idx
== first_filter_idx
);
2891 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
2892 mono_object_isinst_checked (ex_obj
, catch_class
, error
)) || filtered
) {
2894 * This guards against the situation that we abort a thread that is executing a finally clause
2895 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2896 * check for this situation here and resume interruption if we are below the guarded block.
2898 if (G_UNLIKELY (jit_tls
->handler_block
)) {
2899 gboolean is_outside
= FALSE
;
2900 gpointer prot_bp
= MONO_CONTEXT_GET_BP (&jit_tls
->handler_block_context
);
2901 gpointer catch_bp
= MONO_CONTEXT_GET_BP (ctx
);
2902 //FIXME make this stack direction aware
2904 if (catch_bp
> prot_bp
) {
2906 } else if (catch_bp
== prot_bp
) {
2907 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2908 * So we check if the catch handler_start is protected by the guarded handler protected region
2911 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2912 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2913 * There aren't any further finally/fault handler blocks down the stack over this exception.
2914 * This must be ensured by the code that installs the guard trampoline.
2916 g_assert (ji
== mini_jit_info_table_find (domain
, (char *)MONO_CONTEXT_GET_IP (&jit_tls
->handler_block_context
), NULL
));
2918 if (!is_address_protected (ji
, jit_tls
->handler_block
, ei
->handler_start
)) {
2923 jit_tls
->handler_block
= NULL
;
2924 mono_thread_resume_interruption (TRUE
); /*We ignore the exception here, it will be raised later*/
2928 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2929 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2932 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2933 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2934 * clause. Since we specifically want to indicate that we're executing the
2935 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2936 * instead of ei->flags.
2938 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2939 jit_tls
->orig_ex_ctx_set
= TRUE
;
2940 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, MONO_EXCEPTION_CLAUSE_NONE
, ex_obj
));
2941 jit_tls
->orig_ex_ctx_set
= FALSE
;
2944 mini_set_abort_threshold (&frame
);
2947 interp_exit_finally_abort_blocks (ji
, clause_index_start
, i
, ip
);
2949 * ctx->pc points into the interpreter, after the call which transitioned to
2950 * JITted code. Store the unwind state into the
2951 * interpeter state, then resume, the interpreter will unwind itself until
2952 * it reaches the target frame and will continue execution from there.
2953 * The resuming is kinda hackish, from the native code standpoint, it looks
2954 * like the call which transitioned to JITted code has succeeded, but the
2955 * return value register etc. is not set, so we have to be careful.
2957 mini_get_interp_callbacks ()->set_resume_state (jit_tls
, ex_obj
, ei
, frame
.interp_frame
, ei
->handler_start
);
2958 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2959 /* ip == 0 means an interpreter frame */
2960 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
2961 mono_arch_undo_ip_adjustment (ctx
);
2963 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2966 #ifndef DISABLE_PERFCOUNTERS
2967 mono_atomic_fetch_add_i32 (&mono_perfcounters
->exceptions_depth
, frame_count
);
2969 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2970 jit_tls
->handling_stack_ovf
= FALSE
;
2974 mono_error_cleanup (error
);
2975 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) {
2976 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2977 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2979 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2980 jit_tls
->orig_ex_ctx_set
= TRUE
;
2981 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2982 jit_tls
->orig_ex_ctx_set
= FALSE
;
2985 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2986 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2987 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2989 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2990 jit_tls
->orig_ex_ctx_set
= TRUE
;
2991 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2992 jit_tls
->orig_ex_ctx_set
= FALSE
;
2995 #ifndef DISABLE_PERFCOUNTERS
2996 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_finallys
);
2999 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
|| ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
3001 if (ji
->from_llvm
) {
3003 * LLVM compiled finally handlers follow the design
3004 * of the c++ ehabi, i.e. they call a resume function
3005 * at the end instead of returning to the caller.
3006 * So save the exception handling state,
3007 * mono_resume_unwind () will call us again to continue
3010 jit_tls
->resume_state
.ex_obj
= obj
;
3011 jit_tls
->resume_state
.ji
= ji
;
3012 jit_tls
->resume_state
.clause_index
= i
+ 1;
3013 jit_tls
->resume_state
.ctx
= *ctx
;
3014 jit_tls
->resume_state
.new_ctx
= new_ctx
;
3015 jit_tls
->resume_state
.lmf
= lmf
;
3016 jit_tls
->resume_state
.first_filter_idx
= first_filter_idx
;
3017 jit_tls
->resume_state
.filter_idx
= filter_idx
;
3018 mini_set_abort_threshold (&frame
);
3019 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
3022 mini_set_abort_threshold (&frame
);
3024 gboolean has_ex
= mini_get_interp_callbacks ()->run_finally (&frame
, i
, ei
->handler_start
, ei
->data
.handler_end
);
3027 * If run_finally didn't resume to a context, it means that the handler frame
3028 * is linked to the frame calling finally through interpreter frames. This
3029 * means that we will reach the handler frame by resuming the current context.
3031 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
3032 mono_arch_undo_ip_adjustment (ctx
);
3036 call_filter (ctx
, ei
->handler_start
);
3044 interp_exit_finally_abort_blocks (ji
, clause_index_start
, ji
->num_clauses
, ip
);
3046 if (MONO_PROFILER_ENABLED (method_exception_leave
) &&
3047 mono_profiler_get_call_instrumentation_flags (method
) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
) {
3048 jit_tls
->orig_ex_ctx_set
= TRUE
;
3049 MONO_PROFILER_RAISE (method_exception_leave
, (method
, ex_obj
));
3050 jit_tls
->orig_ex_ctx_set
= FALSE
;
3056 g_assert_not_reached ();
3060 * mono_debugger_run_finally:
3061 * \param start_ctx saved processor state
3062 * This method is called by the Mono Debugger to call all \c finally clauses of the
3063 * current stack frame. It's used when the user issues a \c return command to make
3064 * the current stack frame return. After returning from this method, the debugger
3065 * unwinds the stack one frame and gives control back to the user.
3066 * NOTE: This method is only used when running inside the Mono Debugger.
3069 mono_debugger_run_finally (MonoContext
*start_ctx
)
3071 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
3072 MonoDomain
*domain
= mono_domain_get ();
3073 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3074 MonoLMF
*lmf
= mono_get_lmf ();
3075 MonoContext ctx
, new_ctx
;
3076 MonoJitInfo
*ji
, rji
;
3081 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
3082 if (!ji
|| ji
== (gpointer
)-1)
3086 call_filter
= (int (*)(MonoContext
*, void *))mono_get_call_filter ();
3088 for (i
= 0; i
< ji
->num_clauses
; i
++) {
3089 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
3091 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (&ctx
)) &&
3092 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
3093 call_filter (&ctx
, ei
->handler_start
);
3099 * mono_handle_exception:
3100 * \param ctx saved processor state
3101 * \param obj the exception object
3103 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3107 mono_handle_exception (MonoContext
*ctx
, gpointer void_obj
)
3109 MonoObject
*obj
= (MonoObject
*)void_obj
;
3111 MONO_REQ_GC_UNSAFE_MODE
;
3113 #ifndef DISABLE_PERFCOUNTERS
3114 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_thrown
);
3117 return mono_handle_exception_internal (ctx
, obj
, FALSE
, NULL
);
3120 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3122 #ifndef MONO_ARCH_USE_SIGACTION
3123 #error "Can't use sigaltstack without sigaction"
3127 mono_setup_altstack (MonoJitTlsData
*tls
)
3131 guint8
*staddr
= NULL
;
3132 #if defined(TARGET_OSX) || defined(_AIX)
3134 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3135 * stack pages. Stack overflow on main thread will kill the app.
3137 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3138 * do this for thread 1 with its stack at the top of memory. Other threads seem
3139 * fine for the altstack guard page, though.
3141 gboolean disable_stack_guard
= mono_threads_platform_is_main_thread ();
3143 gboolean disable_stack_guard
= FALSE
;
3146 if (mono_running_on_valgrind ())
3149 mono_thread_info_get_stack_bounds (&staddr
, &stsize
);
3153 tls
->end_of_stack
= staddr
+ stsize
;
3154 tls
->stack_size
= stsize
;
3156 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3158 if (!disable_stack_guard
) {
3159 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
3160 tls
->stack_ovf_guard_size
= ALIGN_TO (MONO_STACK_OVERFLOW_GUARD_SIZE
, mono_pagesize ());
3162 g_assert ((guint8
*)&sa
>= (guint8
*)tls
->stack_ovf_guard_base
+ tls
->stack_ovf_guard_size
);
3164 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
3165 /* mprotect can fail for the main thread stack */
3166 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
);
3168 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
3169 tls
->stack_ovf_valloced
= TRUE
;
3171 g_warning ("couldn't allocate guard page, continue without it");
3172 tls
->stack_ovf_guard_base
= NULL
;
3173 tls
->stack_ovf_guard_size
= 0;
3178 /* Setup an alternate signal stack */
3179 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
);
3180 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3182 g_assert (tls
->signal_stack
);
3184 sa
.ss_sp
= tls
->signal_stack
;
3185 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3187 g_assert (sigaltstack (&sa
, NULL
) == 0);
3189 if (tls
->stack_ovf_guard_base
)
3190 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
);
3192 mono_gc_register_altstack (staddr
, stsize
, tls
->signal_stack
, tls
->signal_stack_size
);
3197 mono_free_altstack (MonoJitTlsData
*tls
)
3202 sa
.ss_sp
= tls
->signal_stack
;
3203 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3204 sa
.ss_flags
= SS_DISABLE
;
3205 err
= sigaltstack (&sa
, NULL
);
3206 g_assert (err
== 0);
3208 if (tls
->signal_stack
)
3209 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3211 if (!tls
->stack_ovf_guard_base
)
3213 if (tls
->stack_ovf_valloced
)
3214 mono_vfree (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3216 mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3219 #elif G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32)
3221 mono_setup_altstack (MonoJitTlsData
*tls
)
3223 // Alt stack is not supported on Windows, but we can use this point to at least
3224 // reserve a stack guarantee of available stack memory when handling stack overflow.
3225 ULONG new_stack_guarantee
= (ULONG
)ALIGN_TO (MONO_STACK_OVERFLOW_GUARD_SIZE
, ((gssize
)mono_pagesize ()));
3226 SetThreadStackGuarantee (&new_stack_guarantee
);
3230 mono_free_altstack (MonoJitTlsData
*tls
)
3234 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3237 mono_setup_altstack (MonoJitTlsData
*tls
)
3242 mono_free_altstack (MonoJitTlsData
*tls
)
3246 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3249 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*siginfo
, guint8
* fault_addr
)
3257 /* we got a stack overflow in the soft-guard pages
3258 * There are two cases:
3259 * 1) managed code caused the overflow: we unprotect the soft-guard page
3260 * and let the arch-specific code trigger the exception handling mechanism
3261 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3262 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3263 * and hope we can continue with those enabled, at least until the hard-guard page
3264 * is hit. The alternative to continuing here is to just print a message and abort.
3265 * We may add in the future the code to protect the pages again in the codepath
3266 * when we return from unmanaged to managed code.
3268 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
3269 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
3270 gboolean handled
= FALSE
;
3272 mono_mprotect (jit_tls
->stack_ovf_guard_base
, jit_tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3273 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3275 mono_arch_handle_altstack_exception (ctx
, siginfo
, fault_addr
, TRUE
);
3280 /* We print a message: after this even managed stack overflows
3281 * may crash the runtime
3283 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx
), fault_addr
);
3284 if (!jit_tls
->handling_stack_ovf
) {
3285 jit_tls
->handling_stack_ovf
= 1;
3287 /*fprintf (stderr, "Already handling stack overflow\n");*/
3296 MonoMethod
*omethod
;
3298 } PrintOverflowUserData
;
3301 print_overflow_stack_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3303 MonoMethod
*method
= NULL
;
3304 PrintOverflowUserData
*user_data
= (PrintOverflowUserData
*)data
;
3307 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3308 method
= jinfo_get_method (frame
->ji
);
3311 if (user_data
->count
== 0) {
3312 /* The first frame is in its prolog, so a line number cannot be computed */
3313 user_data
->count
++;
3317 /* If this is a one method overflow, skip the other instances */
3318 if (method
== user_data
->omethod
)
3321 location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, mono_domain_get ());
3322 mono_runtime_printf_err (" %s", location
);
3325 if (user_data
->count
== 1) {
3326 mono_runtime_printf_err (" <...>");
3327 user_data
->omethod
= method
;
3329 user_data
->omethod
= NULL
;
3332 user_data
->count
++;
3334 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame
->native_offset
);
3340 mono_handle_hard_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, MonoContext
*mctx
, guint8
* fault_addr
)
3342 PrintOverflowUserData ud
;
3344 /* we don't do much now, but we can warn the user with a useful message */
3345 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx
), fault_addr
);
3347 mono_runtime_printf_err ("Stacktrace:");
3349 memset (&ud
, 0, sizeof (ud
));
3351 mono_walk_stack_with_ctx (print_overflow_stack_frame
, mctx
, MONO_UNWIND_LOOKUP_ACTUAL_METHOD
, &ud
);
3357 print_stack_frame_signal_safe (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3359 MonoMethod
*method
= NULL
;
3361 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3362 method
= jinfo_get_method (frame
->ji
);
3365 const char *name_space
= m_class_get_name_space (method
->klass
);
3366 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
);
3368 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame
->native_offset
);
3374 static G_GNUC_UNUSED gboolean
3375 print_stack_frame_to_string (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3377 GString
*p
= (GString
*)data
;
3378 MonoMethod
*method
= NULL
;
3380 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3381 method
= jinfo_get_method (frame
->ji
);
3383 if (method
&& frame
->domain
) {
3384 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
3385 g_string_append_printf (p
, " %s\n", location
);
3388 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
3393 #ifndef MONO_CROSS_COMPILE
3396 * mono_handle_native_crash:
3398 * Handle a native crash (e.g. SIGSEGV) while in native code by
3399 * printing diagnostic information and aborting.
3402 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3404 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3406 #ifdef MONO_ARCH_USE_SIGACTION
3407 struct sigaction sa
;
3408 sa
.sa_handler
= SIG_DFL
;
3409 sigemptyset (&sa
.sa_mask
);
3412 /* Remove our SIGABRT handler */
3413 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
3415 /* On some systems we get a SIGILL when calling abort (), because it might
3416 * fail to raise SIGABRT */
3417 g_assert (sigaction (SIGILL
, &sa
, NULL
) != -1);
3419 /* Remove SIGCHLD, it uses the finalizer thread */
3420 g_assert (sigaction (SIGCHLD
, &sa
, NULL
) != -1);
3422 /* Remove SIGQUIT, we are already dumping threads */
3423 g_assert (sigaction (SIGQUIT
, &sa
, NULL
) != -1);
3427 if (mini_debug_options
.suspend_on_native_crash
) {
3428 g_async_safe_printf ("Received %s, suspending...\n", signal
);
3430 // Sleep for 1 second.
3431 g_usleep (1000 * 1000);
3436 * A crash indicates something went very wrong so we can no longer depend
3437 * on anything working. So try to print out lots of diagnostics, starting
3438 * with ones which have a greater chance of working.
3441 g_async_safe_printf("\n=================================================================\n");
3442 g_async_safe_printf("\tNative Crash Reporting\n");
3443 g_async_safe_printf("=================================================================\n");
3444 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal
);
3445 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3446 g_async_safe_printf("used by your application.\n");
3447 g_async_safe_printf("=================================================================\n");
3448 mono_dump_native_crash_info (signal
, mctx
, info
);
3450 /* !jit_tls means the thread was not registered with the runtime */
3451 // This must be below the native crash dump, because we can't safely
3452 // do runtime state probing after we have walked the managed stack here.
3453 if (jit_tls
&& mono_thread_internal_current () && mctx
) {
3454 g_async_safe_printf ("\n=================================================================\n");
3455 g_async_safe_printf ("\tManaged Stacktrace:\n");
3456 g_async_safe_printf ("=================================================================\n");
3458 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
);
3459 g_async_safe_printf ("=================================================================\n");
3462 mono_post_native_crash_handler (signal
, mctx
, info
, mono_do_crash_chaining
);
3468 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3470 g_assert_not_reached ();
3473 #endif /* !MONO_CROSS_COMPILE */
3476 mono_print_thread_dump_internal (void *sigctx
, MonoContext
*start_ctx
)
3478 MonoInternalThread
*thread
= mono_thread_internal_current ();
3485 text
= g_string_new (0);
3487 mono_gstring_append_thread_name (text
, thread
);
3489 g_string_append_printf (text
, " tid=%p this=%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
3490 mono_thread_internal_describe (thread
, text
);
3491 g_string_append (text
, "\n");
3494 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
3496 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
3498 mono_sigctx_to_monoctx (sigctx
, &ctx
);
3500 mono_walk_stack_with_ctx (print_stack_frame_to_string
, &ctx
, MONO_UNWIND_LOOKUP_ALL
, text
);
3502 mono_runtime_printf ("%s", text
->str
);
3504 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3505 OutputDebugStringA(text
->str
);
3508 g_string_free (text
, TRUE
);
3509 mono_runtime_stdout_fflush ();
3513 * mono_print_thread_dump:
3515 * Print information about the current thread to stdout.
3516 * \p sigctx can be NULL, allowing this to be called from gdb.
3519 mono_print_thread_dump (void *sigctx
)
3521 mono_print_thread_dump_internal (sigctx
, NULL
);
3525 mono_print_thread_dump_from_ctx (MonoContext
*ctx
)
3527 mono_print_thread_dump_internal (NULL
, ctx
);
3531 * mono_resume_unwind:
3533 * This is called by a trampoline from LLVM compiled finally clauses to continue
3537 mono_resume_unwind (MonoContext
*ctx
)
3539 MONO_REQ_GC_UNSAFE_MODE
;
3541 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3542 MonoContext new_ctx
;
3544 MONO_CONTEXT_SET_IP (ctx
, MONO_CONTEXT_GET_IP (&jit_tls
->resume_state
.ctx
));
3545 MONO_CONTEXT_SET_SP (ctx
, MONO_CONTEXT_GET_SP (&jit_tls
->resume_state
.ctx
));
3548 mono_handle_exception_internal (&new_ctx
, (MonoObject
*)jit_tls
->resume_state
.ex_obj
, TRUE
, NULL
);
3550 mono_restore_context (&new_ctx
);
3556 MonoJitExceptionInfo
*ei
;
3557 } FindHandlerBlockData
;
3560 find_last_handler_block (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3564 FindHandlerBlockData
*pdata
= (FindHandlerBlockData
*)data
;
3565 MonoJitInfo
*ji
= frame
->ji
;
3570 ip
= MONO_CONTEXT_GET_IP (ctx
);
3572 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
3573 MonoJitExceptionInfo
*ei
= ji
->clauses
+ i
;
3574 if (ei
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
3576 /*If ip points to the first instruction it means the handler block didn't start
3577 so we can leave its execution to the EH machinery*/
3578 if (ei
->handler_start
<= ip
&& ip
< ei
->data
.handler_end
) {
3590 install_handler_block_guard (MonoJitInfo
*ji
, MonoContext
*ctx
)
3593 MonoJitExceptionInfo
*clause
= NULL
;
3597 ip
= MONO_CONTEXT_GET_IP (ctx
);
3599 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
3600 clause
= &ji
->clauses
[i
];
3601 if (clause
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
3603 if (clause
->handler_start
<= ip
&& clause
->data
.handler_end
> ip
)
3607 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3608 g_assert (i
< ji
->num_clauses
);
3611 bp
= (guint8
*)MONO_CONTEXT_GET_BP (ctx
);
3612 *(bp
+ clause
->exvar_offset
) = 1;
3616 * Finds the bottom handler block running and install a block guard if needed.
3619 mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
)
3621 FindHandlerBlockData data
= { 0 };
3622 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
];
3624 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3625 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3627 if (!jit_tls
|| jit_tls
->handler_block
)
3630 /* Do an async safe stack walk */
3631 mono_thread_info_set_is_async_context (TRUE
);
3632 mono_walk_stack_with_state (find_last_handler_block
, ctx
, MONO_UNWIND_NONE
, &data
);
3633 mono_thread_info_set_is_async_context (FALSE
);
3638 memcpy (&jit_tls
->handler_block_context
, &data
.ctx
, sizeof (MonoContext
));
3640 install_handler_block_guard (data
.ji
, &data
.ctx
);
3642 jit_tls
->handler_block
= data
.ei
;
3648 mono_uninstall_current_handler_block_guard (void)
3650 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3652 jit_tls
->handler_block
= NULL
;
3657 mono_current_thread_has_handle_block_guard (void)
3659 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3660 return jit_tls
&& jit_tls
->handler_block
!= NULL
;
3664 mono_set_cast_details (MonoClass
*from
, MonoClass
*to
)
3666 MonoJitTlsData
*jit_tls
= NULL
;
3668 if (mini_debug_options
.better_cast_details
) {
3669 jit_tls
= mono_tls_get_jit_tls ();
3670 jit_tls
->class_cast_from
= from
;
3671 jit_tls
->class_cast_to
= to
;
3676 /*returns false if the thread is not attached*/
3678 mono_thread_state_init_from_sigctx (MonoThreadUnwindState
*ctx
, void *sigctx
)
3680 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3687 mono_sigctx_to_monoctx (sigctx
, &ctx
->ctx
);
3689 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3690 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3691 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3694 mono_thread_state_init (ctx
);
3697 if (!ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] || !ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
])
3705 mono_thread_state_init (MonoThreadUnwindState
*ctx
)
3707 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3709 #if defined(MONO_CROSS_COMPILE)
3710 ctx
->valid
= FALSE
; //A cross compiler doesn't need to suspend.
3711 #elif MONO_ARCH_HAS_MONO_CONTEXT
3712 MONO_CONTEXT_GET_CURRENT (ctx
->ctx
);
3714 g_error ("Use a null sigctx requires a working mono-context");
3717 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3718 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3719 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
? thread
->jit_data
: NULL
;
3725 mono_thread_state_init_from_monoctx (MonoThreadUnwindState
*ctx
, MonoContext
*mctx
)
3727 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3734 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3735 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3736 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3741 /*returns false if the thread is not attached*/
3743 mono_thread_state_init_from_current (MonoThreadUnwindState
*ctx
)
3745 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3746 MONO_ARCH_CONTEXT_DEF
3748 mono_arch_flush_register_windows ();
3750 if (!thread
|| !thread
->jit_data
) {
3754 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
->ctx
, mono_thread_state_init_from_current
);
3756 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3757 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3758 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3764 mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
)
3766 mono_handle_exception (ctx
, (MonoObject
*)exc
);
3767 mono_restore_context (ctx
);
3770 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3772 mono_setup_async_callback (MonoContext
*ctx
, void (*async_cb
)(void *fun
), gpointer user_data
)
3774 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3775 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3776 jit_tls
->ex_ctx
= *ctx
;
3778 mono_arch_setup_async_callback (ctx
, async_cb
, user_data
);
3780 g_error ("This target doesn't support mono_arch_setup_async_callback");
3785 * mono_restore_context:
3787 * Call the architecture specific restore context function.
3790 mono_restore_context (MonoContext
*ctx
)
3792 static void (*restore_context
) (MonoContext
*);
3794 if (!restore_context
)
3795 restore_context
= (void (*)(MonoContext
*))mono_get_restore_context ();
3796 restore_context (ctx
);
3797 g_assert_not_reached ();
3801 * mono_jinfo_get_unwind_info:
3803 * Return the unwind info for JI.
3806 mono_jinfo_get_unwind_info (MonoJitInfo
*ji
, guint32
*unwind_info_len
)
3808 if (ji
->has_unwind_info
) {
3809 /* The address/length in the MonoJitInfo structure itself */
3810 MonoUnwindJitInfo
*info
= mono_jit_info_get_unwind_info (ji
);
3811 *unwind_info_len
= info
->unw_info_len
;
3812 return info
->unw_info
;
3813 } else if (ji
->from_aot
)
3814 return mono_aot_get_unwind_info (ji
, unwind_info_len
);
3816 return mono_get_cached_unwind_info (ji
->unwind_info
, unwind_info_len
);
3820 mono_jinfo_get_epilog_size (MonoJitInfo
*ji
)
3822 MonoArchEHJitInfo
*info
;
3824 info
= mono_jit_info_get_arch_eh_info (ji
);
3827 return info
->epilog_size
;
3831 * mono_install_ftnptr_eh_callback:
3833 * Install a callback that should be called when there is a managed exception
3834 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3835 * managed exception to a native exception, to properly unwind the native
3836 * stack; this native exception will then be converted back to a managed
3837 * exception in their managed-to-native wrapper.
3840 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback
)
3842 ftnptr_eh_callback
= callback
;
3846 * LLVM/Bitcode exception handling.
3850 throw_exception (MonoObject
*ex
, gboolean rethrow
)
3852 MONO_REQ_GC_UNSAFE_MODE
;
3855 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3856 MonoException
*mono_ex
;
3858 if (!mono_object_isinst_checked (ex
, mono_defaults
.exception_class
, error
)) {
3859 mono_error_assert_ok (error
);
3860 mono_ex
= mono_get_exception_runtime_wrapped_checked (ex
, error
);
3861 mono_error_assert_ok (error
);
3862 jit_tls
->thrown_non_exc
= mono_gchandle_new_internal (ex
, FALSE
);
3865 mono_ex
= (MonoException
*)ex
;
3868 jit_tls
->thrown_exc
= mono_gchandle_new_internal ((MonoObject
*)mono_ex
, FALSE
);
3871 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3872 GList
*l
, *ips
= NULL
;
3875 _Unwind_Backtrace (build_stack_trace
, &ips
);
3876 /* The list contains ip-gshared info pairs */
3878 ips
= g_list_reverse (ips
);
3879 for (l
= ips
; l
; l
= l
->next
) {
3880 trace
= g_list_append (trace
, l
->data
);
3881 trace
= g_list_append (trace
, NULL
);
3882 trace
= g_list_append (trace
, NULL
);
3884 MonoArray
*ips_arr
= mono_glist_to_array (trace
, mono_defaults
.int_class
, error
);
3885 mono_error_assert_ok (error
);
3886 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
3888 g_list_free (trace
);
3892 mono_llvm_cpp_throw_exception ();
3896 mono_llvm_throw_exception (MonoObject
*ex
)
3898 throw_exception (ex
, FALSE
);
3902 mono_llvm_rethrow_exception (MonoObject
*ex
)
3904 throw_exception (ex
, TRUE
);
3908 mono_llvm_raise_exception (MonoException
*e
)
3910 mono_llvm_throw_exception ((MonoObject
*)e
);
3914 mono_llvm_reraise_exception (MonoException
*e
)
3916 mono_llvm_rethrow_exception ((MonoObject
*)e
);
3920 mono_llvm_throw_corlib_exception (guint32 ex_token_index
)
3922 guint32 ex_token
= MONO_TOKEN_TYPE_DEF
| ex_token_index
;
3925 ex
= mono_exception_from_token (m_class_get_image (mono_defaults
.exception_class
), ex_token
);
3927 mono_llvm_throw_exception ((MonoObject
*)ex
);
3931 * mono_llvm_resume_exception:
3933 * Resume exception propagation.
3936 mono_llvm_resume_exception (void)
3938 mono_llvm_cpp_throw_exception ();
3942 * mono_llvm_load_exception:
3944 * Return the currently thrown exception.
3947 mono_llvm_load_exception (void)
3950 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3952 MonoException
*mono_ex
= (MonoException
*)mono_gchandle_get_target_internal (jit_tls
->thrown_exc
);
3954 MonoArray
*ta
= mono_ex
->trace_ips
;
3957 GList
*trace_ips
= NULL
;
3958 gpointer ip
= MONO_RETURN_ADDRESS ();
3960 size_t upper
= mono_array_length_internal (ta
);
3962 for (int i
= 0; i
< upper
; i
+= TRACE_IP_ENTRY_SIZE
) {
3963 gpointer curr_ip
= mono_array_get_internal (ta
, gpointer
, i
);
3964 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
3965 gpointer p
= mono_array_get_internal (ta
, gpointer
, i
+ j
);
3966 trace_ips
= g_list_append (trace_ips
, p
);
3972 // FIXME: Does this work correctly for rethrows?
3973 // We may be discarding useful information
3974 // when this gets GC'ed
3975 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips
, mono_defaults
.int_class
, error
);
3976 mono_error_assert_ok (error
);
3977 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
3978 g_list_free (trace_ips
);
3981 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3983 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, 0, error
));
3984 mono_error_assert_ok (error
);
3985 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, stack_trace
, mono_array_new_checked (mono_domain_get (), mono_defaults
.stack_frame_class
, 0, error
));
3986 mono_error_assert_ok (error
);
3989 return &mono_ex
->object
;
3993 * mono_llvm_clear_exception:
3995 * Mark the currently thrown exception as handled.
3998 mono_llvm_clear_exception (void)
4000 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
4001 mono_gchandle_free_internal (jit_tls
->thrown_exc
);
4002 jit_tls
->thrown_exc
= 0;
4003 if (jit_tls
->thrown_non_exc
)
4004 mono_gchandle_free_internal (jit_tls
->thrown_non_exc
);
4005 jit_tls
->thrown_non_exc
= 0;
4007 mono_memory_barrier ();
4011 * mono_llvm_match_exception:
4013 * Return the innermost clause containing REGION_START-REGION_END which can handle
4014 * the current exception.
4017 mono_llvm_match_exception (MonoJitInfo
*jinfo
, guint32 region_start
, guint32 region_end
, gpointer rgctx
, MonoObject
*this_obj
)
4020 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
4024 g_assert (jit_tls
->thrown_exc
);
4025 exc
= mono_gchandle_get_target_internal (jit_tls
->thrown_exc
);
4026 if (jit_tls
->thrown_non_exc
) {
4028 * Have to unwrap RuntimeWrappedExceptions if the
4029 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
4031 if (!wrap_non_exception_throws (jinfo_get_method (jinfo
)))
4032 exc
= mono_gchandle_get_target_internal (jit_tls
->thrown_non_exc
);
4035 for (int i
= 0; i
< jinfo
->num_clauses
; i
++) {
4036 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
4037 MonoClass
*catch_class
;
4039 if (! (ei
->try_offset
== region_start
&& ei
->try_offset
+ ei
->try_len
== region_end
) )
4042 catch_class
= ei
->data
.catch_class
;
4043 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class
))) {
4044 MonoGenericContext context
;
4045 MonoType
*inflated_type
;
4047 g_assert (rgctx
|| this_obj
);
4048 context
= mono_get_generic_context_from_stack_frame (jinfo
, rgctx
? rgctx
: this_obj
->vtable
);
4049 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
4050 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
4052 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
4053 mono_metadata_free_type (inflated_type
);
4056 // FIXME: Handle edge cases handled in get_exception_catch_class
4057 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (exc
, catch_class
, error
)) {
4058 index
= ei
->clause_index
;
4061 mono_error_assert_ok (error
);
4063 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
4064 g_assert_not_reached ();
4071 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4072 G_EXTERN_C _Unwind_Reason_Code
mono_debug_personality (int a
, _Unwind_Action b
,
4073 uint64_t c
, struct _Unwind_Exception
*d
, struct _Unwind_Context
*e
)
4075 g_assert_not_reached ();
4078 G_EXTERN_C
void mono_debug_personality (void);
4081 mono_debug_personality (void)
4083 g_assert_not_reached ();