3 * generic exception support
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Mono Team (mono-list@lists.ximian.com)
9 * Copyright 2001-2003 Ximian, Inc.
10 * Copyright 2003-2008 Novell, Inc.
11 * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #ifdef HAVE_EXECINFO_H
24 #ifdef HAVE_SYS_TYPES_H
25 #include <sys/types.h>
28 #ifdef HAVE_SYS_WAIT_H
36 #ifdef HAVE_SYS_SYSCALL_H
37 #include <sys/syscall.h>
40 #ifdef HAVE_SYS_PRCTL_H
41 #include <sys/prctl.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/tabledefs.h>
50 #include <mono/metadata/threads.h>
51 #include <mono/metadata/threads-types.h>
52 #include <mono/metadata/debug-helpers.h>
53 #include <mono/metadata/exception.h>
54 #include <mono/metadata/exception-internals.h>
55 #include <mono/metadata/object-internals.h>
56 #include <mono/metadata/reflection-internals.h>
57 #include <mono/metadata/gc-internals.h>
58 #include <mono/metadata/debug-internals.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/metadata/profiler-private.h>
61 #include <mono/metadata/mono-endian.h>
62 #include <mono/metadata/environment.h>
63 #include <mono/metadata/mono-mlist.h>
64 #include <mono/utils/mono-merp.h>
65 #include <mono/utils/mono-mmap.h>
66 #include <mono/utils/mono-logger-internals.h>
67 #include <mono/utils/mono-error.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/mono-state.h>
70 #include <mono/utils/mono-threads-debug.h>
74 #include "debugger-agent.h"
75 #include "debugger-engine.h"
76 #include "seq-points.h"
77 #include "llvm-runtime.h"
78 #include "mini-llvm.h"
79 #include "aot-runtime.h"
80 #include "mini-runtime.h"
81 #include "interp/interp.h"
84 #include "mini-llvm-cpp.h"
91 #ifndef MONO_ARCH_CONTEXT_DEF
92 #define MONO_ARCH_CONTEXT_DEF
95 #if !defined(DISABLE_CRASH_REPORTING)
98 #include "mono/utils/mono-tls-inline.h"
101 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
102 * This structure represents one entry.
103 * This should consists of pointers only.
108 gpointer generic_info
;
109 /* Only for interpreter frames */
113 /* Number of words in trace_ips belonging to one entry */
114 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
116 static gpointer restore_context_func
, call_filter_func
;
117 static gpointer throw_exception_func
, rethrow_exception_func
, rethrow_preserve_exception_func
;
118 static gpointer throw_corlib_exception_func
;
120 static MonoFtnPtrEHCallback ftnptr_eh_callback
;
122 static void mono_walk_stack_full (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoLMF
*lmf
, MonoUnwindOptions unwind_options
, gpointer user_data
, gboolean crash_context
);
123 static void mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
);
124 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
);
125 static gboolean
mono_current_thread_has_handle_block_guard (void);
126 static gboolean
mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
);
127 static void mono_uninstall_current_handler_block_guard (void);
128 static gboolean
mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
);
129 static void throw_exception (MonoObject
*ex
, gboolean rethrow
);
131 static void mono_summarize_managed_stack (MonoThreadSummary
*out
);
132 static void mono_summarize_unmanaged_stack (MonoThreadSummary
*out
);
133 static void mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
);
134 static void mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
);
135 static void mono_crash_reporting_allow_all_native_libraries (void);
138 first_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer addr
)
140 gpointer
*data
= (gpointer
*)addr
;
146 // FIXME: Happens with llvm_only
151 *data
= frame
->frame_addr
;
157 mono_thread_get_managed_sp (void)
159 gpointer addr
= NULL
;
160 mono_walk_stack (first_managed
, MONO_UNWIND_SIGNAL_SAFE
, &addr
);
165 mini_clear_abort_threshold (void)
167 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
168 jit_tls
->abort_exc_stack_threshold
= NULL
;
172 mini_set_abort_threshold (StackFrameInfo
*frame
)
174 gpointer sp
= frame
->frame_addr
;
175 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
176 // Only move it up, to avoid thrown/caught
177 // exceptions lower in the stack from triggering
179 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
180 if (!jit_tls
->abort_exc_stack_threshold
|| above_threshold
) {
181 jit_tls
->abort_exc_stack_threshold
= sp
;
185 // Note: In the case that the frame is above where the thread abort
186 // was set we bump the threshold so that functions called from the new,
187 // higher threshold don't trigger the thread abort exception
189 mini_above_abort_threshold (void)
191 gpointer sp
= mono_thread_get_managed_sp ();
192 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
197 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
200 jit_tls
->abort_exc_stack_threshold
= sp
;
202 return above_threshold
;
206 mono_get_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
209 if (mono_find_prev_seq_point_for_native_offset (domain
, method
, native_offset
, NULL
, &sp
))
215 mono_exceptions_init (void)
217 MonoRuntimeExceptionHandlingCallbacks cbs
;
218 if (mono_ee_features
.use_aot_trampolines
) {
219 restore_context_func
= mono_aot_get_trampoline ("restore_context");
220 call_filter_func
= mono_aot_get_trampoline ("call_filter");
221 throw_exception_func
= mono_aot_get_trampoline ("throw_exception");
222 rethrow_exception_func
= mono_aot_get_trampoline ("rethrow_exception");
223 rethrow_preserve_exception_func
= mono_aot_get_trampoline ("rethrow_preserve_exception");
224 } else if (!mono_llvm_only
) {
227 restore_context_func
= mono_arch_get_restore_context (&info
, FALSE
);
228 mono_tramp_info_register (info
, NULL
);
229 call_filter_func
= mono_arch_get_call_filter (&info
, FALSE
);
230 mono_tramp_info_register (info
, NULL
);
231 throw_exception_func
= mono_arch_get_throw_exception (&info
, FALSE
);
232 mono_tramp_info_register (info
, NULL
);
233 rethrow_exception_func
= mono_arch_get_rethrow_exception (&info
, FALSE
);
234 mono_tramp_info_register (info
, NULL
);
235 rethrow_preserve_exception_func
= mono_arch_get_rethrow_preserve_exception (&info
, FALSE
);
236 mono_tramp_info_register (info
, NULL
);
239 mono_arch_exceptions_init ();
241 cbs
.mono_walk_stack_with_ctx
= mono_runtime_walk_stack_with_ctx
;
242 cbs
.mono_walk_stack_with_state
= mono_walk_stack_with_state
;
243 cbs
.mono_summarize_managed_stack
= mono_summarize_managed_stack
;
244 cbs
.mono_summarize_unmanaged_stack
= mono_summarize_unmanaged_stack
;
245 cbs
.mono_summarize_exception
= mono_summarize_exception
;
246 cbs
.mono_register_native_library
= mono_crash_reporting_register_native_library
;
247 cbs
.mono_allow_all_native_libraries
= mono_crash_reporting_allow_all_native_libraries
;
249 if (mono_llvm_only
) {
250 cbs
.mono_raise_exception
= mono_llvm_raise_exception
;
251 cbs
.mono_reraise_exception
= mono_llvm_reraise_exception
;
253 cbs
.mono_raise_exception
= (void (*)(MonoException
*))mono_get_throw_exception ();
254 cbs
.mono_reraise_exception
= (void (*)(MonoException
*))mono_get_rethrow_exception ();
256 cbs
.mono_raise_exception_with_ctx
= mono_raise_exception_with_ctx
;
257 cbs
.mono_exception_walk_trace
= mono_exception_walk_trace
;
258 cbs
.mono_install_handler_block_guard
= mono_install_handler_block_guard
;
259 cbs
.mono_uninstall_current_handler_block_guard
= mono_uninstall_current_handler_block_guard
;
260 cbs
.mono_current_thread_has_handle_block_guard
= mono_current_thread_has_handle_block_guard
;
261 cbs
.mono_clear_abort_threshold
= mini_clear_abort_threshold
;
262 cbs
.mono_above_abort_threshold
= mini_above_abort_threshold
;
263 mono_install_eh_callbacks (&cbs
);
264 mono_install_get_seq_point (mono_get_seq_point_for_native_offset
);
268 mono_get_throw_exception (void)
270 g_assert (throw_exception_func
);
271 return throw_exception_func
;
275 mono_get_rethrow_exception (void)
277 g_assert (rethrow_exception_func
);
278 return rethrow_exception_func
;
282 mono_get_rethrow_preserve_exception (void)
284 g_assert (rethrow_preserve_exception_func
);
285 return rethrow_preserve_exception_func
;
289 no_call_filter (void)
291 g_assert_not_reached ();
295 mono_get_call_filter (void)
297 /* This is called even in llvmonly mode etc. */
298 if (!call_filter_func
)
299 return (gpointer
)no_call_filter
;
300 return call_filter_func
;
304 mono_get_restore_context (void)
306 g_assert (restore_context_func
);
307 return restore_context_func
;
311 mono_get_throw_corlib_exception (void)
313 gpointer code
= NULL
;
316 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
317 if (throw_corlib_exception_func
)
318 return throw_corlib_exception_func
;
320 if (mono_ee_features
.use_aot_trampolines
)
321 code
= mono_aot_get_trampoline ("throw_corlib_exception");
323 code
= mono_arch_get_throw_corlib_exception (&info
, FALSE
);
324 mono_tramp_info_register (info
, NULL
);
327 mono_memory_barrier ();
329 throw_corlib_exception_func
= code
;
331 return throw_corlib_exception_func
;
335 * mono_get_throw_exception_addr:
337 * Return an address which stores the result of
338 * mono_get_throw_exception.
341 mono_get_throw_exception_addr (void)
343 return &throw_exception_func
;
347 mono_get_rethrow_preserve_exception_addr (void)
349 return &rethrow_preserve_exception_func
;
353 is_address_protected (MonoJitInfo
*ji
, MonoJitExceptionInfo
*ei
, gpointer ip
)
355 MonoTryBlockHoleTableJitInfo
*table
;
360 if (ei
->try_start
> ip
|| ip
>= ei
->try_end
)
363 if (!ji
->has_try_block_holes
)
366 table
= mono_jit_info_get_try_block_hole_table_info (ji
);
367 offset
= (guint32
)((char*)ip
- (char*)ji
->code_start
);
368 clause
= (guint16
)(ei
- ji
->clauses
);
369 g_assert (clause
< ji
->num_clauses
);
371 for (i
= 0; i
< table
->num_holes
; ++i
) {
372 MonoTryBlockHoleJitInfo
*hole
= &table
->holes
[i
];
373 if (hole
->clause
== clause
&& hole
->offset
<= offset
&& hole
->offset
+ hole
->length
> offset
)
379 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
382 static gboolean show_native_addresses
= TRUE
;
384 static gboolean show_native_addresses
= FALSE
;
387 static _Unwind_Reason_Code
388 build_stack_trace (struct _Unwind_Context
*frame_ctx
, void *state
)
390 MonoDomain
*domain
= mono_domain_get ();
391 uintptr_t ip
= _Unwind_GetIP (frame_ctx
);
393 if (show_native_addresses
|| mono_jit_info_table_find (domain
, (char*)ip
)) {
394 GList
**trace_ips
= (GList
**)state
;
395 *trace_ips
= g_list_prepend (*trace_ips
, (gpointer
)ip
);
398 return _URC_NO_REASON
;
402 get_unwind_backtrace (void)
406 _Unwind_Backtrace (build_stack_trace
, &ips
);
408 return g_slist_reverse (ips
);
414 get_unwind_backtrace (void)
422 arch_unwind_frame (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
423 MonoJitInfo
*ji
, MonoContext
*ctx
,
424 MonoContext
*new_ctx
, MonoLMF
**lmf
,
425 host_mgreg_t
**save_locations
,
426 StackFrameInfo
*frame
)
429 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
430 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
432 memset (frame
, 0, sizeof (StackFrameInfo
));
437 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
439 * This LMF entry is created by the soft debug code to mark transitions to
440 * managed code done during invokes.
442 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
443 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
444 } else if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT
|| ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
445 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED
;
446 frame
->interp_exit_data
= ext
->interp_exit_data
;
447 if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
448 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
449 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
452 g_assert_not_reached ();
455 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~3);
461 return mono_arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
467 * Translate between the mono_arch_unwind_frame function and the old API.
470 find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
471 MonoContext
*new_ctx
, MonoLMF
**lmf
, gboolean
*managed
)
473 StackFrameInfo frame
;
476 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
478 /* Avoid costly table lookup during stack overflow */
479 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
482 ji
= mini_jit_info_table_find (domain
, ip
, NULL
);
487 err
= arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, NULL
, &frame
);
489 return (MonoJitInfo
*)-1;
491 if (*lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
493 * Remove any unused lmf.
494 * Mask out the lower bits which might be used to hold additional information.
496 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
499 /* Convert between the new and the old APIs */
500 switch (frame
.type
) {
501 case FRAME_TYPE_MANAGED
:
505 case FRAME_TYPE_TRAMPOLINE
:
507 case FRAME_TYPE_MANAGED_TO_NATIVE
:
511 memset (res
, 0, sizeof (MonoJitInfo
));
512 res
->d
.method
= frame
.method
;
515 case FRAME_TYPE_DEBUGGER_INVOKE
: {
519 * The normal exception handling code can't handle this frame, so just
522 ji
= find_jit_info (domain
, jit_tls
, res
, NULL
, new_ctx
, &tmp_ctx
, lmf
, managed
);
523 memcpy (new_ctx
, &tmp_ctx
, sizeof (MonoContext
));
527 g_assert_not_reached ();
532 /* mono_find_jit_info:
534 * This function is used to gather information from @ctx. It return the
535 * MonoJitInfo of the corresponding function, unwinds one stack frame and
536 * stores the resulting context into @new_ctx. It also stores a string
537 * describing the stack location into @trace (if not NULL), and modifies
538 * the @lmf if necessary. @native_offset return the IP offset from the
539 * start of the function or -1 if that info is not available.
542 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
543 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
547 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
549 MonoMethod
*method
= NULL
;
560 ji
= find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
562 if (ji
== (gpointer
)-1)
565 if (ji
&& !ji
->is_trampoline
)
566 method
= jinfo_get_method (ji
);
568 if (managed2
|| (method
&& method
->wrapper_type
)) {
569 const char *real_ip
, *start
;
572 start
= (const char *)ji
->code_start
;
574 /* ctx->ip points into native code */
575 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
577 real_ip
= (const char*)ip
;
579 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
580 offset
= real_ip
- start
;
585 *native_offset
= offset
;
588 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
592 *trace
= mono_debug_print_stack_frame (method
, offset
, domain
);
595 char *fname
= mono_method_full_name (jinfo_get_method (res
), TRUE
);
596 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
605 * mono_find_jit_info_ext:
607 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
609 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
610 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
611 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
612 * to obtain the last managed frame.
613 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
614 * On return, it will be filled with the locations where callee saved registers are saved
615 * by the current frame. This is returned outside of StackFrameInfo because it can be
616 * quite large on some platforms.
617 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
621 mono_find_jit_info_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
622 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
623 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
624 host_mgreg_t
**save_locations
,
625 StackFrameInfo
*frame
)
628 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
630 MonoDomain
*target_domain
= domain
;
631 MonoMethod
*method
= NULL
;
632 gboolean async
= mono_thread_info_is_async_context ();
637 /* Avoid costly table lookup during stack overflow */
638 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
641 ji
= mini_jit_info_table_find_ext (domain
, ip
, TRUE
, &target_domain
);
644 target_domain
= domain
;
647 memset (save_locations
, 0, MONO_MAX_IREGS
* sizeof (host_mgreg_t
*));
649 err
= arch_unwind_frame (target_domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
653 gboolean not_i2m
= frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED
&& frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
655 if (not_i2m
&& *lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
657 * Remove any unused lmf.
658 * Mask out the lower bits which might be used to hold additional information.
660 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
663 if (frame
->ji
&& !frame
->ji
->is_trampoline
&& !frame
->ji
->async
)
664 method
= jinfo_get_method (frame
->ji
);
666 if (frame
->type
== FRAME_TYPE_MANAGED
&& method
) {
667 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
668 frame
->managed
= TRUE
;
671 if (frame
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
) {
673 * This type of frame is just a marker, the caller should unwind once more to get the
674 * last managed frame.
677 frame
->method
= NULL
;
680 frame
->native_offset
= -1;
681 frame
->domain
= target_domain
;
682 frame
->async_context
= async
;
683 frame
->frame_addr
= MONO_CONTEXT_GET_SP (ctx
);
687 if (frame
->type
== FRAME_TYPE_MANAGED
)
688 frame
->method
= method
;
690 if (ji
&& (frame
->managed
|| (method
&& method
->wrapper_type
))) {
691 const char *real_ip
, *start
;
693 start
= (const char *)ji
->code_start
;
694 if (frame
->type
== FRAME_TYPE_MANAGED
)
695 real_ip
= (const char*)ip
;
697 /* ctx->ip points into native code */
698 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
700 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
701 frame
->native_offset
= real_ip
- start
;
703 frame
->native_offset
= -1;
707 *trace
= mono_debug_print_stack_frame (method
, frame
->native_offset
, domain
);
709 if (trace
&& frame
->method
) {
710 char *fname
= mono_method_full_name (frame
->method
, TRUE
);
711 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
721 MonoInterpStackIter interp_iter
;
722 gpointer last_frame_addr
;
726 unwinder_init (Unwinder
*unwinder
)
728 memset (unwinder
, 0, sizeof (Unwinder
));
731 #if defined(__GNUC__) && defined(TARGET_ARM64)
732 /* gcc 4.9.2 seems to miscompile this on arm64 */
733 static __attribute__((optimize("O0"))) gboolean
737 unwinder_unwind_frame (Unwinder
*unwinder
,
738 MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
739 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
740 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
741 host_mgreg_t
**save_locations
,
742 StackFrameInfo
*frame
)
745 if (unwinder
->in_interp
) {
746 memcpy (new_ctx
, ctx
, sizeof (MonoContext
));
748 /* Process debugger invokes */
749 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
750 if (unwinder
->last_frame_addr
< (gpointer
)(*lmf
)) {
751 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
752 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
753 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
754 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~7);
755 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
761 unwinder
->in_interp
= mini_get_interp_callbacks ()->frame_iter_next (&unwinder
->interp_iter
, frame
);
762 if (frame
->type
== FRAME_TYPE_INTERP
) {
763 parent
= mini_get_interp_callbacks ()->frame_get_parent (frame
->interp_frame
);
765 unwinder
->last_frame_addr
= mini_get_interp_callbacks ()->frame_get_native_stack_addr (parent
);
767 unwinder
->last_frame_addr
= NULL
;
769 if (!unwinder
->in_interp
)
770 return unwinder_unwind_frame (unwinder
, domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
, save_locations
, frame
);
773 gboolean res
= mono_find_jit_info_ext (domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
,
774 save_locations
, frame
);
777 if (frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
) {
778 unwinder
->in_interp
= TRUE
;
779 mini_get_interp_callbacks ()->frame_iter_init (&unwinder
->interp_iter
, frame
->interp_exit_data
);
781 unwinder
->last_frame_addr
= frame
->frame_addr
;
787 * This function is async-safe.
790 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
792 MonoGenericJitInfo
*gi
;
796 if (!ji
->has_generic_jit_info
)
798 gi
= mono_jit_info_get_generic_jit_info (ji
);
804 * Search location list if available, it contains the precise location of the
805 * argument for every pc offset, even if the method was interrupted while it was in
809 int offset
= (gsize
)MONO_CONTEXT_GET_IP (ctx
) - (gsize
)ji
->code_start
;
812 for (i
= 0; i
< gi
->nlocs
; ++i
) {
813 MonoDwarfLocListEntry
*entry
= &gi
->locations
[i
];
815 if (offset
>= entry
->from
&& (offset
< entry
->to
|| entry
->to
== 0)) {
817 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, entry
->reg
);
819 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, entry
->reg
) + entry
->offset
);
823 g_assert (i
< gi
->nlocs
);
826 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
828 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
832 method
= jinfo_get_method (ji
);
833 if (mono_method_get_context (method
)->method_inst
) {
834 /* A MonoMethodRuntimeGenericContext* */
836 } else if ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) || m_class_is_valuetype (method
->klass
)) {
840 /* Avoid returning a managed object */
841 MonoObject
*this_obj
= (MonoObject
*)info
;
843 return this_obj
->vtable
;
848 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
851 mono_get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
853 MonoGenericContext context
= { NULL
, NULL
};
854 MonoClass
*klass
, *method_container_class
;
857 g_assert (generic_info
);
859 method
= jinfo_get_method (ji
);
860 g_assert (method
->is_inflated
);
861 if (mono_method_get_context (method
)->method_inst
) {
862 MonoMethodRuntimeGenericContext
*mrgctx
= (MonoMethodRuntimeGenericContext
*)generic_info
;
864 klass
= mrgctx
->class_vtable
->klass
;
865 context
.method_inst
= mrgctx
->method_inst
;
866 g_assert (context
.method_inst
);
868 MonoVTable
*vtable
= (MonoVTable
*)generic_info
;
870 klass
= vtable
->klass
;
873 //g_assert (!mono_class_is_gtd (method->klass));
874 if (mono_class_is_ginst (method
->klass
))
875 method_container_class
= mono_class_get_generic_class (method
->klass
)->container_class
;
877 method_container_class
= method
->klass
;
879 /* class might refer to a subclass of method's class */
880 while (!(klass
== method
->klass
|| (mono_class_is_ginst (klass
) && mono_class_get_generic_class (klass
)->container_class
== method_container_class
))) {
881 klass
= m_class_get_parent (klass
);
885 if (mono_class_is_ginst (klass
) || mono_class_is_gtd (klass
))
886 context
.class_inst
= mini_class_get_context (klass
)->class_inst
;
888 if (mono_class_is_ginst (klass
))
889 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass
)->container_class
, method_container_class
));
891 g_assert (mono_class_has_parent_and_ignore_generics (klass
, method_container_class
));
898 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
901 MonoGenericContext context
;
904 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
905 return jinfo_get_method (ji
);
906 context
= mono_get_generic_context_from_stack_frame (ji
, generic_info
);
908 method
= jinfo_get_method (ji
);
909 method
= mono_method_get_declaring_generic_method (method
);
910 method
= mono_class_inflate_generic_method_checked (method
, &context
, error
);
911 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
917 * mono_exception_walk_native_trace:
918 * \param ex The exception object whose frames should be walked
919 * \param func callback to call for each stack frame
920 * \param user_data data passed to the callback
921 * This function walks the stacktrace of an exception. For
922 * each frame the callback function is called with the relevant info.
923 * The walk ends when no more stack frames are found or when the callback
924 * returns a TRUE value.
928 mono_exception_walk_trace (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
932 MONO_ENTER_GC_UNSAFE
;
933 res
= mono_exception_walk_trace_internal (ex
, func
, user_data
);
939 mono_exception_stackframe_obj_walk (MonoStackFrame
*captured_frame
, MonoExceptionFrameWalk func
, gpointer user_data
)
944 gpointer ip
= (gpointer
) (captured_frame
->method_address
+ captured_frame
->native_offset
);
945 MonoJitInfo
*ji
= mono_jit_info_table_find_internal (mono_domain_get (), ip
, TRUE
, TRUE
);
947 // Other domain maybe?
950 MonoMethod
*method
= jinfo_get_method (ji
);
952 gboolean r
= func (method
, (gpointer
) captured_frame
->method_address
, captured_frame
->native_offset
, TRUE
, user_data
);
960 mono_exception_stacktrace_obj_walk (MonoStackTrace
*st
, MonoExceptionFrameWalk func
, gpointer user_data
)
962 int num_captured
= st
->captured_traces
? mono_array_length_internal (st
->captured_traces
) : 0;
963 for (int i
=0; i
< num_captured
; i
++) {
964 MonoStackTrace
*curr_trace
= mono_array_get_fast (st
->captured_traces
, MonoStackTrace
*, i
);
965 mono_exception_stacktrace_obj_walk (curr_trace
, func
, user_data
);
968 int num_frames
= st
->frames
? mono_array_length_internal (st
->frames
) : 0;
969 for (int frame
= 0; frame
< num_frames
; frame
++) {
970 gboolean r
= mono_exception_stackframe_obj_walk (mono_array_get_fast (st
->frames
, MonoStackFrame
*, frame
), func
, user_data
);
979 mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
981 MONO_REQ_GC_UNSAFE_MODE
;
983 MonoDomain
*domain
= mono_domain_get ();
984 MonoArray
*ta
= ex
->trace_ips
;
986 /* Exception is not thrown yet */
990 int len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
991 gboolean otherwise_has_traces
= len
> 0;
993 for (int i
= 0; i
< len
; i
++) {
994 ExceptionTraceIp trace_ip
;
996 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
997 gpointer ip
= trace_ip
.ip
;
998 gpointer generic_info
= trace_ip
.generic_info
;
1000 MonoJitInfo
*ji
= NULL
;
1004 ji
= mono_jit_info_table_find (domain
, ip
);
1010 r
= func (NULL
, ip
, 0, FALSE
, user_data
);
1015 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
1016 if (func (method
, ji
->code_start
, (char *) ip
- (char *) ji
->code_start
, TRUE
, user_data
))
1021 ta
= (MonoArray
*) ex
->captured_traces
;
1022 len
= ta
? mono_array_length_internal (ta
) : 0;
1023 gboolean captured_has_traces
= len
> 0;
1025 for (int i
= 0; i
< len
; i
++) {
1026 MonoStackTrace
*captured_trace
= mono_array_get_fast (ta
, MonoStackTrace
*, i
);
1027 if (!captured_trace
)
1030 mono_exception_stacktrace_obj_walk (captured_trace
, func
, user_data
);
1033 return captured_has_traces
|| otherwise_has_traces
;
1037 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
1040 MonoDomain
*domain
= mono_domain_get ();
1042 MonoArray
*ta
= exc
->trace_ips
;
1043 MonoDebugSourceLocation
*location
;
1047 /* Exception is not thrown yet */
1048 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, 0, error
);
1049 mono_error_set_pending_exception (error
);
1053 len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
1055 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0, error
);
1056 if (mono_error_set_pending_exception (error
))
1059 for (i
= skip
; i
< len
; i
++) {
1061 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
1062 if (!is_ok (error
)) {
1063 mono_error_set_pending_exception (error
);
1066 ExceptionTraceIp trace_ip
;
1067 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
1068 gpointer ip
= trace_ip
.ip
;
1069 gpointer generic_info
= trace_ip
.generic_info
;
1075 ji
= mono_jit_info_table_find (domain
, ip
);
1077 /* Unmanaged frame */
1078 mono_array_setref_internal (res
, i
, sf
);
1083 g_assert (ji
!= NULL
);
1085 if (mono_llvm_only
|| !generic_info
)
1086 /* Can't resolve actual method */
1087 method
= jinfo_get_method (ji
);
1089 method
= get_method_from_stack_frame (ji
, generic_info
);
1090 if (jinfo_get_method (ji
)->wrapper_type
) {
1094 s
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_REFLECTION
);
1095 MonoString
*name
= mono_string_new_checked (domain
, s
, error
);
1097 if (!is_ok (error
)) {
1098 mono_error_set_pending_exception (error
);
1101 MONO_OBJECT_SETREF_INTERNAL (sf
, internal_method_name
, name
);
1104 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
1105 if (!is_ok (error
)) {
1106 mono_error_set_pending_exception (error
);
1109 MONO_OBJECT_SETREF_INTERNAL (sf
, method
, rm
);
1112 sf
->method_index
= ji
->from_aot
? mono_aot_find_method_index (method
) : 0xffffff;
1113 sf
->method_address
= (gsize
) ji
->code_start
;
1114 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
1117 * mono_debug_lookup_source_location() returns both the file / line number information
1118 * and the IL offset. Note that computing the IL offset is already an expensive
1119 * operation, so we shouldn't call this method twice.
1121 location
= mono_debug_lookup_source_location (jinfo_get_method (ji
), sf
->native_offset
, domain
);
1123 sf
->il_offset
= location
->il_offset
;
1126 if (mono_find_prev_seq_point_for_native_offset (domain
, jinfo_get_method (ji
), sf
->native_offset
, NULL
, &sp
))
1127 sf
->il_offset
= sp
.il_offset
;
1132 if (need_file_info
) {
1133 if (location
&& location
->source_file
) {
1134 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1135 if (!is_ok (error
)) {
1136 mono_error_set_pending_exception (error
);
1139 MONO_OBJECT_SETREF_INTERNAL (sf
, filename
, filename
);
1140 sf
->line
= location
->row
;
1141 sf
->column
= location
->column
;
1143 sf
->line
= sf
->column
= 0;
1144 sf
->filename
= NULL
;
1148 mono_debug_free_source_location (location
);
1149 mono_array_setref_internal (res
, i
- skip
, sf
);
1156 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1159 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1160 if (jit_tls
&& jit_tls
->orig_ex_ctx_set
)
1161 start_ctx
= &jit_tls
->orig_ex_ctx
;
1163 mono_walk_stack_with_ctx (func
, start_ctx
, unwind_options
, user_data
);
1166 * mono_walk_stack_with_ctx:
1167 * Unwind the current thread starting at \p start_ctx.
1168 * If \p start_ctx is null, we capture the current context.
1171 mono_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1173 MonoContext extra_ctx
;
1174 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1175 MONO_ARCH_CONTEXT_DEF
1177 if (!thread
|| !thread
->jit_data
)
1181 mono_arch_flush_register_windows ();
1182 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx
, mono_walk_stack_with_ctx
);
1183 start_ctx
= &extra_ctx
;
1186 mono_walk_stack_full (func
, start_ctx
, mono_domain_get (), thread
->jit_data
, mono_get_lmf (), unwind_options
, user_data
, FALSE
);
1190 * mono_walk_stack_with_state:
1191 * Unwind a thread described by \p state.
1193 * State must be valid (state->valid == TRUE).
1195 * If you are using this function to unwind another thread, make sure it is suspended.
1197 * If \p state is null, we capture the current context.
1200 mono_walk_stack_with_state (MonoJitStackWalk func
, MonoThreadUnwindState
*state
, MonoUnwindOptions unwind_options
, void *user_data
)
1202 MonoThreadUnwindState extra_state
;
1204 g_assert (!mono_thread_info_is_async_context ());
1205 if (!mono_thread_state_init_from_current (&extra_state
))
1207 state
= &extra_state
;
1210 g_assert (state
->valid
);
1212 if (!state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
])
1216 mono_walk_stack_full (func
,
1218 (MonoDomain
*)state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
],
1219 (MonoJitTlsData
*)state
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
],
1220 (MonoLMF
*)state
->unwind_data
[MONO_UNWIND_DATA_LMF
],
1221 unwind_options
, user_data
, FALSE
);
1225 mono_walk_stack (MonoJitStackWalk func
, MonoUnwindOptions options
, void *user_data
)
1227 MonoThreadUnwindState state
;
1228 if (!mono_thread_state_init_from_current (&state
))
1230 mono_walk_stack_with_state (func
, &state
, options
, user_data
);
1234 * mono_walk_stack_full:
1235 * \param func callback to call for each stack frame
1236 * \param domain starting appdomain, can be NULL to use the current domain
1237 * \param unwind_options what extra information the unwinder should gather
1238 * \param start_ctx starting state of the stack walk, can be NULL.
1239 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1240 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1241 * \param user_data data passed to the callback
1242 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1243 * This function walks the stack of a thread, starting from the state
1244 * represented by \p start_ctx. For each frame the callback
1245 * function is called with the relevant info. The walk ends when no more
1246 * managed stack frames are found or when the callback returns a TRUE value.
1249 mono_walk_stack_full (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoLMF
*lmf
, MonoUnwindOptions unwind_options
, gpointer user_data
, gboolean crash_context
)
1252 MonoContext ctx
, new_ctx
;
1253 StackFrameInfo frame
;
1255 host_mgreg_t
*reg_locations
[MONO_MAX_IREGS
];
1256 host_mgreg_t
*new_reg_locations
[MONO_MAX_IREGS
];
1257 gboolean get_reg_locations
= unwind_options
& MONO_UNWIND_REG_LOCATIONS
;
1258 gboolean async
= mono_thread_info_is_async_context ();
1261 memset (&frame
, 0, sizeof (StackFrameInfo
));
1264 if (mono_llvm_only
) {
1270 ips
= get_unwind_backtrace ();
1271 for (l
= ips
; l
; l
= l
->next
) {
1272 guint8
*ip
= (guint8
*)l
->data
;
1273 memset (&frame
, 0, sizeof (StackFrameInfo
));
1274 frame
.ji
= mini_jit_info_table_find (domain
, ip
, &frame
.domain
);
1275 if (!frame
.ji
|| frame
.ji
->is_trampoline
)
1277 frame
.type
= FRAME_TYPE_MANAGED
;
1278 frame
.method
= jinfo_get_method (frame
.ji
);
1279 // FIXME: Cannot lookup the actual method
1280 frame
.actual_method
= frame
.method
;
1281 if (frame
.type
== FRAME_TYPE_MANAGED
) {
1282 if (!frame
.method
->wrapper_type
|| frame
.method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1283 frame
.managed
= TRUE
;
1285 frame
.native_offset
= ip
- (guint8
*)frame
.ji
->code_start
;
1286 frame
.il_offset
= -1;
1288 if (func (&frame
, NULL
, user_data
))
1297 g_warning ("start_ctx required for stack walk");
1302 g_warning ("domain required for stack walk");
1307 g_warning ("jit_tls required for stack walk");
1311 /*The LMF will be null if the target have no managed frames.*/
1312 /* g_assert (lmf); */
1313 if (async
&& (unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
)) {
1314 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1318 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
1319 memset (reg_locations
, 0, sizeof (reg_locations
));
1321 unwinder_init (&unwinder
);
1323 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
1325 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, get_reg_locations
? new_reg_locations
: NULL
, &frame
);
1329 if (frame
.type
== FRAME_TYPE_TRAMPOLINE
)
1332 if ((unwind_options
& MONO_UNWIND_LOOKUP_IL_OFFSET
) && frame
.ji
) {
1333 MonoDebugSourceLocation
*source
= NULL
;
1335 // Don't do this when we can be in a signal handler
1337 source
= mono_debug_lookup_source_location (jinfo_get_method (frame
.ji
), frame
.native_offset
, domain
);
1339 il_offset
= source
->il_offset
;
1341 MonoSeqPointInfo
*seq_points
= NULL
;
1343 // It's more reliable to look into the global cache if possible
1345 seq_points
= (MonoSeqPointInfo
*) frame
.ji
->seq_points
;
1347 seq_points
= mono_get_seq_points (domain
, jinfo_get_method (frame
.ji
));
1350 if (seq_points
&& mono_seq_point_find_prev_by_native_offset (seq_points
, frame
.native_offset
, &sp
))
1351 il_offset
= sp
.il_offset
;
1355 mono_debug_free_source_location (source
);
1359 frame
.il_offset
= il_offset
;
1361 if ((unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
) && frame
.ji
) {
1362 frame
.actual_method
= get_method_from_stack_frame (frame
.ji
, get_generic_info_from_stack_frame (frame
.ji
, &ctx
));
1364 frame
.actual_method
= frame
.method
;
1367 if (get_reg_locations
)
1368 frame
.reg_locations
= reg_locations
;
1370 if (func (&frame
, &ctx
, user_data
))
1374 if (get_reg_locations
) {
1375 for (int i
= 0; i
< MONO_MAX_IREGS
; ++i
)
1376 if (new_reg_locations
[i
])
1377 reg_locations
[i
] = new_reg_locations
[i
];
1384 #ifdef DISABLE_CRASH_REPORTING
1387 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1393 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1399 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1405 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1411 mono_crash_reporting_allow_all_native_libraries ()
1420 MonoFrameSummary
*frames
;
1423 MonoStackHash
*hashes
;
1425 } MonoSummarizeUserData
;
1428 copy_summary_string_safe (char *dest
, const char *src
)
1430 g_strlcpy (dest
, src
, MONO_MAX_SUMMARY_NAME_LEN
);
1434 fill_frame_managed_info (MonoFrameSummary
*frame
, MonoMethod
* method
)
1436 MonoImage
*image
= mono_class_get_image (method
->klass
);
1437 // Used for hashing, more stable across rebuilds than using GUID
1438 copy_summary_string_safe (frame
->str_descr
, image
->assembly_name
);
1440 frame
->managed_data
.guid
= image
->guid
;
1441 frame
->managed_data
.token
= method
->token
;
1442 frame
->managed_data
.filename
= image
->module_name
;
1444 MonoDotNetHeader
*header
= &image
->image_info
->cli_header
;
1445 frame
->managed_data
.image_size
= header
->nt
.pe_image_size
;
1446 frame
->managed_data
.time_date_stamp
= image
->time_date_stamp
;
1451 char *exported_name
;
1452 } MonoLibWhitelistEntry
;
1454 static GList
*native_library_whitelist
;
1455 static gboolean allow_all_native_libraries
= FALSE
;
1458 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1460 // Examples: libsystem_pthread.dylib -> "pthread"
1461 // Examples: libsystem_platform.dylib -> "platform"
1462 // Examples: mono-sgen -> "mono" from above line
1463 MonoLibWhitelistEntry
*entry
= g_new0 (MonoLibWhitelistEntry
, 1);
1464 entry
->suffix
= g_strdup (module_path
);
1465 entry
->exported_name
= g_strdup (module_name
);
1466 native_library_whitelist
= g_list_append (native_library_whitelist
, entry
);
1470 mono_crash_reporting_allow_all_native_libraries ()
1472 allow_all_native_libraries
= TRUE
;
1476 check_whitelisted_module (const char *in_name
, const char **out_module
)
1478 #ifndef MONO_PRIVATE_CRASHES
1481 if (g_str_has_suffix (in_name
, "mono-sgen")) {
1483 copy_summary_string_safe ((char *) *out_module
, "mono");
1486 if (allow_all_native_libraries
) {
1488 /* for a module name, use the basename of the full path in in_name */
1489 char *basename
= (char *) in_name
, *p
= (char *) in_name
;
1490 while (*p
!= '\0') {
1496 copy_summary_string_safe ((char *) *out_module
, basename
);
1498 copy_summary_string_safe ((char *) *out_module
, "unknown");
1504 for (GList
*cursor
= native_library_whitelist
; cursor
; cursor
= cursor
->next
) {
1505 MonoLibWhitelistEntry
*iter
= (MonoLibWhitelistEntry
*) cursor
->data
;
1506 if (!g_str_has_suffix (in_name
, iter
->suffix
))
1509 copy_summary_string_safe ((char *) *out_module
, iter
->exported_name
);
1518 mono_make_portable_ip (intptr_t in_ip
, intptr_t module_base
)
1520 // FIXME: Make generalize away from llvm tools?
1521 // So lldb starts the pointer base at 0x100000000
1522 // and expects to get pointers as (offset + constant)
1525 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1526 // *CoreSymbolicationDT.framework version: 63750*/
1527 intptr_t offset
= in_ip
- module_base
;
1528 intptr_t magic_value
= offset
+ 0x100000000;
1533 mono_get_portable_ip (intptr_t in_ip
, intptr_t *out_ip
, gint32
*out_offset
, const char **out_module
, char *out_name
)
1535 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1536 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1537 // non-recursive lock twice on this thread, and will deadlock.
1538 char sname
[256], fname
[256];
1539 void *saddr
= NULL
, *fbase
= NULL
;
1540 gboolean success
= g_module_address ((void*)in_ip
, fname
, 256, &fbase
, sname
, 256, &saddr
);
1544 if (!check_whitelisted_module (fname
, out_module
))
1547 *out_ip
= mono_make_portable_ip ((intptr_t) saddr
, (intptr_t) fbase
);
1548 *out_offset
= in_ip
- (intptr_t) saddr
;
1550 if (saddr
&& out_name
)
1551 copy_summary_string_safe (out_name
, sname
);
1556 summarize_offset_free_hash (guint64 accum
, MonoFrameSummary
*frame
)
1558 if (!frame
->is_managed
)
1561 // See: mono_ptrarray_hash
1562 guint64 hash_accum
= accum
;
1564 // The assembly and the method token, no offsets
1565 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1566 hash_accum
+= frame
->managed_data
.token
;
1572 summarize_offset_rich_hash (guint64 accum
, MonoFrameSummary
*frame
)
1574 // See: mono_ptrarray_hash
1575 guint64 hash_accum
= accum
;
1577 if (!frame
->is_managed
) {
1578 hash_accum
+= frame
->unmanaged_data
.ip
;
1580 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1581 hash_accum
+= frame
->managed_data
.token
;
1582 hash_accum
+= frame
->managed_data
.il_offset
;
1589 summarize_frame_internal (MonoMethod
*method
, gpointer ip
, size_t native_offset
, int il_offset
, gboolean managed
, gpointer user_data
)
1591 MonoSummarizeUserData
*ud
= (MonoSummarizeUserData
*) user_data
;
1593 gboolean valid_state
= ud
->num_frames
+ 1 < ud
->max_frames
;
1595 ud
->error
= "Exceeded the maximum number of frames";
1599 MonoFrameSummary
*dest
= &ud
->frames
[ud
->num_frames
];
1601 dest
->unmanaged_data
.ip
= (intptr_t) ip
;
1602 dest
->is_managed
= managed
;
1603 dest
->unmanaged_data
.module
[0] = '\0';
1605 if (!managed
&& method
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
&& method
->wrapper_type
< MONO_WRAPPER_NUM
) {
1606 dest
->is_managed
= FALSE
;
1607 dest
->unmanaged_data
.has_name
= TRUE
;
1608 copy_summary_string_safe (dest
->str_descr
, mono_wrapper_type_to_str (method
->wrapper_type
));
1611 #ifndef MONO_PRIVATE_CRASHES
1613 dest
->managed_data
.name
= (char *) method
->name
;
1618 ud
->error
= "Managed method frame, but no provided managed method";
1621 fill_frame_managed_info (dest
, method
);
1622 dest
->managed_data
.native_offset
= native_offset
;
1623 dest
->managed_data
.il_offset
= il_offset
;
1625 dest
->managed_data
.token
= -1;
1629 ud
->hashes
->offset_free_hash
= summarize_offset_free_hash (ud
->hashes
->offset_free_hash
, dest
);
1630 ud
->hashes
->offset_rich_hash
= summarize_offset_rich_hash (ud
->hashes
->offset_rich_hash
, dest
);
1632 // We return FALSE, so we're continuing walking
1633 // And we increment the pointer because we're done with this cell in the array
1639 summarize_frame_managed_walk (MonoMethod
*method
, gpointer ip
, size_t frame_native_offset
, gboolean managed
, gpointer user_data
)
1643 if (managed
&& method
) {
1644 MonoDebugSourceLocation
*location
= mono_debug_lookup_source_location (method
, frame_native_offset
, mono_domain_get ());
1646 il_offset
= location
->il_offset
;
1647 mono_debug_free_source_location (location
);
1651 intptr_t portable_ip
= 0;
1653 mono_get_portable_ip ((intptr_t) ip
, &portable_ip
, &offset
, NULL
, NULL
);
1655 return summarize_frame_internal (method
, (gpointer
) portable_ip
, frame_native_offset
, il_offset
, managed
, user_data
);
1660 summarize_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
1662 // Don't record trampolines between managed frames
1663 if (frame
->ji
&& frame
->ji
->is_trampoline
)
1666 if (frame
->ji
&& (frame
->ji
->is_trampoline
|| frame
->ji
->async
))
1667 return FALSE
; // Keep unwinding
1671 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx
), &ip
, &offset
, NULL
, NULL
);
1672 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1674 gboolean is_managed
= (frame
->type
== FRAME_TYPE_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP
);
1675 MonoMethod
*method
= NULL
;
1676 if (frame
&& frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
1677 method
= jinfo_get_method (frame
->ji
);
1680 method
= jinfo_get_method (frame
->ji
);
1682 return summarize_frame_internal (method
, (gpointer
) ip
, offset
, frame
->il_offset
, is_managed
, data
);
1686 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1688 memset (out
, 0, sizeof (MonoThreadSummary
));
1690 MonoException
*inner_exc
= exc
;
1693 for (exc_index
= 0; exc_index
< MONO_MAX_SUMMARY_EXCEPTIONS
; exc_index
++) {
1694 if (inner_exc
== NULL
)
1697 // Set up state to walk this MonoException's stack
1698 MonoSummarizeUserData data
;
1699 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1700 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1701 data
.num_frames
= 0;
1702 data
.frames
= out
->exceptions
[exc_index
].managed_frames
;
1704 // Accumulate all hashes from all exceptions in traveral order
1705 data
.hashes
= &out
->hashes
;
1707 mono_exception_walk_trace (inner_exc
, summarize_frame_managed_walk
, &data
);
1709 // Save per-MonoException info
1710 out
->exceptions
[exc_index
].managed_exc_type
= inner_exc
->object
.vtable
->klass
;
1711 out
->exceptions
[exc_index
].num_managed_frames
= data
.num_frames
;
1713 // Continue to traverse nesting of exceptions
1714 inner_exc
= (MonoException
*) inner_exc
->inner_ex
;
1717 out
->num_exceptions
= exc_index
;
1722 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1724 MonoSummarizeUserData data
;
1725 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1726 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1727 data
.num_frames
= 0;
1728 data
.frames
= out
->managed_frames
;
1729 data
.hashes
= &out
->hashes
;
1731 // FIXME: collect stack pointer for both and sort frames by SP
1732 // so people can see relative ordering of both managed and unmanaged frames.
1735 // Summarize managed stack
1737 mono_walk_stack_full (summarize_frame
, out
->ctx
, out
->domain
, out
->jit_tls
, out
->lmf
, MONO_UNWIND_LOOKUP_IL_OFFSET
, &data
, TRUE
);
1738 out
->num_managed_frames
= data
.num_frames
;
1740 if (data
.error
!= NULL
)
1741 out
->error_msg
= data
.error
;
1742 out
->is_managed
= (out
->num_managed_frames
!= 0);
1745 // Always runs on the dumped thread
1747 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1749 MONO_ARCH_CONTEXT_DEF
1751 // Summarize unmanaged stack
1753 #ifdef HAVE_BACKTRACE_SYMBOLS
1754 intptr_t frame_ips
[MONO_MAX_SUMMARY_FRAMES
];
1756 out
->num_unmanaged_frames
= backtrace ((void **)frame_ips
, MONO_MAX_SUMMARY_FRAMES
);
1758 for (int i
=0; i
< out
->num_unmanaged_frames
; ++i
) {
1759 intptr_t ip
= frame_ips
[i
];
1760 MonoFrameSummary
*frame
= &out
->unmanaged_frames
[i
];
1761 const char* module_buf
= frame
->unmanaged_data
.module
;
1762 int success
= mono_get_portable_ip (ip
, &frame
->unmanaged_data
.ip
, &frame
->unmanaged_data
.offset
, &module_buf
, (char *) frame
->str_descr
);
1764 /* attempt to look up any managed method at that ip */
1765 /* TODO: Trampolines - follow examples from mono_print_method_from_ip() */
1768 MonoDomain
*domain
= mono_domain_get ();
1769 MonoDomain
*target_domain
;
1770 ji
= mini_jit_info_table_find_ext (domain
, (char *)ip
, TRUE
, &target_domain
);
1772 frame
->is_managed
= TRUE
;
1773 if (!ji
->async
&& !ji
->is_trampoline
) {
1774 MonoMethod
*method
= jinfo_get_method (ji
);
1775 fill_frame_managed_info (frame
, method
);
1776 #ifndef MONO_PRIVATE_CRASHES
1777 frame
->managed_data
.name
= method
->name
;
1782 if (!success
&& !ji
) {
1783 frame
->unmanaged_data
.ip
= ip
;
1787 if (out
->unmanaged_frames
[i
].str_descr
[0] != '\0')
1788 out
->unmanaged_frames
[i
].unmanaged_data
.has_name
= TRUE
;
1792 out
->lmf
= mono_get_lmf ();
1794 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1795 out
->info_addr
= (intptr_t) thread
;
1796 out
->jit_tls
= thread
->jit_data
;
1797 out
->domain
= mono_domain_get ();
1800 out
->ctx
= &out
->ctx_mem
;
1801 mono_arch_flush_register_windows ();
1802 MONO_INIT_CONTEXT_FROM_FUNC (out
->ctx
, mono_summarize_unmanaged_stack
);
1811 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
1812 MonoReflectionMethod
**method
,
1813 gint32
*iloffset
, gint32
*native_offset
,
1814 MonoString
**file
, gint32
*line
, gint32
*column
)
1817 MonoDomain
*domain
= mono_domain_get ();
1818 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1819 MonoLMF
*lmf
= mono_get_lmf ();
1820 MonoJitInfo
*ji
= NULL
;
1821 MonoContext ctx
, new_ctx
;
1822 MonoDebugSourceLocation
*location
;
1823 MonoMethod
*jmethod
= NULL
, *actual_method
;
1824 StackFrameInfo frame
;
1829 MONO_ARCH_CONTEXT_DEF
;
1831 g_assert (skip
>= 0);
1833 if (mono_llvm_only
) {
1835 MonoDomain
*frame_domain
;
1836 guint8
*frame_ip
= NULL
;
1838 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1840 ips
= get_unwind_backtrace ();
1841 for (l
= ips
; l
&& skip
>= 0; l
= l
->next
) {
1842 guint8
*ip
= (guint8
*)l
->data
;
1846 ji
= mini_jit_info_table_find (mono_domain_get (), ip
, &frame_domain
);
1847 if (!ji
|| ji
->is_trampoline
)
1850 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1851 jmethod
= jinfo_get_method (ji
);
1852 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1859 /* No way to resolve generic instances */
1860 actual_method
= jmethod
;
1861 *native_offset
= frame_ip
- (guint8
*)ji
->code_start
;
1863 mono_arch_flush_register_windows ();
1864 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
1866 unwinder_init (&unwinder
);
1871 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
1874 switch (frame
.type
) {
1875 case FRAME_TYPE_MANAGED_TO_NATIVE
:
1876 case FRAME_TYPE_DEBUGGER_INVOKE
:
1877 case FRAME_TYPE_TRAMPOLINE
:
1878 case FRAME_TYPE_INTERP_TO_MANAGED
:
1879 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
1881 case FRAME_TYPE_INTERP
:
1882 case FRAME_TYPE_MANAGED
:
1884 *native_offset
= frame
.native_offset
;
1886 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1887 jmethod
= jinfo_get_method (ji
);
1888 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1893 g_assert_not_reached ();
1895 } while (skip
>= 0);
1897 if (frame
.type
== FRAME_TYPE_INTERP
) {
1898 jmethod
= frame
.method
;
1899 actual_method
= frame
.actual_method
;
1901 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &ctx
));
1905 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, actual_method
, NULL
, error
);
1906 if (!is_ok (error
)) {
1907 mono_error_set_pending_exception (error
);
1910 mono_gc_wbarrier_generic_store_internal (method
, (MonoObject
*) rm
);
1912 if (il_offset
!= -1) {
1913 location
= mono_debug_lookup_source_location_by_il (jmethod
, il_offset
, domain
);
1915 location
= mono_debug_lookup_source_location (jmethod
, *native_offset
, domain
);
1918 *iloffset
= location
->il_offset
;
1922 if (need_file_info
) {
1924 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1925 if (!is_ok (error
)) {
1926 mono_error_set_pending_exception (error
);
1929 mono_gc_wbarrier_generic_store_internal (file
, (MonoObject
*)filename
);
1930 *line
= location
->row
;
1931 *column
= location
->column
;
1934 *line
= *column
= 0;
1938 mono_debug_free_source_location (location
);
1944 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
1947 MonoClass
*catch_class
= ei
->data
.catch_class
;
1948 MonoType
*inflated_type
;
1949 MonoGenericContext context
;
1951 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1952 if (!catch_class
|| ei
->flags
!= MONO_EXCEPTION_CLAUSE_NONE
)
1955 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
1957 context
= mono_get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
1959 /* FIXME: we shouldn't inflate but instead put the
1960 type in the rgctx and fetch it from there. It
1961 might be a good idea to do this lazily, i.e. only
1962 when the exception is actually thrown, so as not to
1963 waste space for exception clauses which might never
1965 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
1966 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1968 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
1969 mono_metadata_free_type (inflated_type
);
1975 * mini_jit_info_table_find_ext:
1977 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1978 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1979 * OUT_DOMAIN if it is not NULL.
1982 mini_jit_info_table_find_ext (MonoDomain
*domain
, gpointer addr
, gboolean allow_trampolines
, MonoDomain
**out_domain
)
1985 MonoInternalThread
*t
= mono_thread_internal_current ();
1991 ji
= mono_jit_info_table_find_internal (domain
, addr
, TRUE
, allow_trampolines
);
1994 *out_domain
= domain
;
1998 /* maybe it is shared code, so we also search in the root domain */
1999 if (domain
!= mono_get_root_domain ()) {
2000 ji
= mono_jit_info_table_find_internal (mono_get_root_domain (), addr
, TRUE
, allow_trampolines
);
2003 *out_domain
= mono_get_root_domain ();
2011 refs
= (gpointer
*)((t
->appdomain_refs
) ? *(gpointer
*) t
->appdomain_refs
: NULL
);
2012 for (; refs
&& *refs
; refs
++) {
2013 if (*refs
!= domain
&& *refs
!= mono_get_root_domain ()) {
2014 ji
= mono_jit_info_table_find_internal ((MonoDomain
*) *refs
, addr
, TRUE
, allow_trampolines
);
2017 *out_domain
= (MonoDomain
*) *refs
;
2027 mini_jit_info_table_find (MonoDomain
*domain
, gpointer addr
, MonoDomain
**out_domain
)
2029 return mini_jit_info_table_find_ext (domain
, addr
, FALSE
, out_domain
);
2032 /* Class lazy loading functions */
2033 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr
, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
2036 * wrap_non_exception_throws:
2038 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
2039 * WrapNonExceptionThrows flag set.
2042 wrap_non_exception_throws (MonoMethod
*m
)
2045 MonoAssembly
*ass
= m_class_get_image (m
->klass
)->assembly
;
2046 MonoCustomAttrInfo
* attrs
;
2049 gboolean val
= FALSE
;
2051 if (m
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
2052 MonoDynamicMethod
*dm
= (MonoDynamicMethod
*)m
;
2057 if (ass
->wrap_non_exception_throws_inited
)
2058 return ass
->wrap_non_exception_throws
;
2060 klass
= mono_class_get_runtime_compat_attr_class ();
2062 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
2063 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2065 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
2066 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
2068 int num_named
, named_type
, name_len
;
2071 if (!attr
->ctor
|| attr
->ctor
->klass
!= klass
)
2073 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2074 p
= (const char*)attr
->data
;
2075 g_assert (read16 (p
) == 0x0001);
2077 num_named
= read16 (p
);
2083 /* data_type = *p; */
2086 if (named_type
!= 0x54)
2088 name_len
= mono_metadata_decode_blob_size (p
, &p
);
2089 name
= (char *)g_malloc (name_len
+ 1);
2090 memcpy (name
, p
, name_len
);
2091 name
[name_len
] = 0;
2093 g_assert (!strcmp (name
, "WrapNonExceptionThrows"));
2095 /* The value is a BOOLEAN */
2098 mono_custom_attrs_free (attrs
);
2101 ass
->wrap_non_exception_throws
= val
;
2102 mono_memory_barrier ();
2103 ass
->wrap_non_exception_throws_inited
= TRUE
;
2108 #define MAX_UNMANAGED_BACKTRACE 128
2110 build_native_trace (MonoError
*error
)
2113 /* This puppy only makes sense on mobile, IOW, ARM. */
2114 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2116 void *native_trace
[MAX_UNMANAGED_BACKTRACE
];
2119 size
= backtrace (native_trace
, MAX_UNMANAGED_BACKTRACE
);
2125 res
= mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, size
, error
);
2126 return_val_if_nok (error
, NULL
);
2128 for (i
= 0; i
< size
; i
++)
2129 mono_array_set_internal (res
, gpointer
, i
, native_trace
[i
]);
2137 remove_wrappers_from_trace (GList
**trace_ips_p
)
2139 GList
*trace_ips
= *trace_ips_p
;
2140 GList
*p
= trace_ips
;
2142 /* jit info, generic info, ip */
2144 MonoJitInfo
*jinfo
= (MonoJitInfo
*) p
->data
;
2145 GList
*next_p
= p
->next
->next
->next
;
2146 /* FIXME Maybe remove more wrapper types */
2147 if (jinfo
->d
.method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2148 trace_ips
= g_list_delete_link (trace_ips
, p
->next
->next
);
2149 trace_ips
= g_list_delete_link (trace_ips
, p
->next
);
2150 trace_ips
= g_list_delete_link (trace_ips
, p
);
2155 *trace_ips_p
= trace_ips
;
2158 /* This can be called more than once on a MonoException. */
2160 setup_stack_trace (MonoException
*mono_ex
, GSList
**dynamic_methods
, GList
*trace_ips
, gboolean remove_wrappers
)
2163 GList
*trace_ips_copy
= g_list_copy (trace_ips
);
2164 if (remove_wrappers
)
2165 remove_wrappers_from_trace (&trace_ips_copy
);
2166 trace_ips_copy
= g_list_reverse (trace_ips_copy
);
2168 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips_copy
, mono_defaults
.int_class
, error
);
2169 mono_error_assert_ok (error
);
2170 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
2171 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, native_trace_ips
, build_native_trace (error
));
2172 mono_error_assert_ok (error
);
2173 if (*dynamic_methods
) {
2174 /* These methods could go away anytime, so save a reference to them in the exception object */
2176 MonoMList
*list
= (MonoMList
*)mono_ex
->dynamic_methods
;
2178 for (l
= *dynamic_methods
; l
; l
= l
->next
) {
2180 MonoDomain
*domain
= mono_domain_get ();
2182 if (domain
->method_to_dyn_method
) {
2183 mono_domain_lock (domain
);
2184 dis_link
= (guint32
)(size_t)g_hash_table_lookup (domain
->method_to_dyn_method
, l
->data
);
2185 mono_domain_unlock (domain
);
2187 MonoObject
*o
= mono_gchandle_get_target_internal (dis_link
);
2189 list
= mono_mlist_prepend_checked (list
, o
, error
);
2190 mono_error_assert_ok (error
);
2196 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, dynamic_methods
, list
);
2198 g_slist_free (*dynamic_methods
);
2199 *dynamic_methods
= NULL
;
2202 g_list_free (trace_ips_copy
);
2207 MONO_FIRST_PASS_UNHANDLED
,
2208 MONO_FIRST_PASS_CALLBACK_TO_NATIVE
,
2209 MONO_FIRST_PASS_HANDLED
,
2210 } MonoFirstPassResult
;
2213 * handle_exception_first_pass:
2215 * The first pass of exception handling. Unwind the stack until a catch
2216 * clause which can catch OBJ is found. Store the index of the filter clause
2217 * which caught the exception into OUT_FILTER_IDX. Return
2218 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2219 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2220 * wrapper and an exception handling callback is installed (in which case
2221 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2223 static MonoFirstPassResult
2224 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
)
2227 MonoDomain
*domain
= mono_domain_get ();
2228 MonoJitInfo
*ji
= NULL
;
2229 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2230 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2231 MonoLMF
*lmf
= mono_get_lmf ();
2232 GList
*trace_ips
= NULL
;
2233 GSList
*dynamic_methods
= NULL
;
2234 MonoException
*mono_ex
;
2235 gboolean stack_overflow
= FALSE
;
2236 MonoContext initial_ctx
;
2238 int frame_count
= 0;
2245 MonoFirstPassResult result
= MONO_FIRST_PASS_UNHANDLED
;
2247 g_assert (ctx
!= NULL
);
2248 *last_mono_wrapper_runtime_invoke
= TRUE
;
2249 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2250 stack_overflow
= TRUE
;
2252 mono_ex
= (MonoException
*)obj
;
2253 MonoArray
*initial_trace_ips
= mono_ex
->trace_ips
;
2254 if (initial_trace_ips
) {
2255 int len
= mono_array_length_internal (initial_trace_ips
) / TRACE_IP_ENTRY_SIZE
;
2257 // If we catch in managed/non-wrapper, we don't save the catching frame
2258 if (!mono_ex
->caught_in_unmanaged
)
2261 for (i
= 0; i
< len
; i
++) {
2262 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
2263 gpointer p
= mono_array_get_internal (initial_trace_ips
, gpointer
, (i
* TRACE_IP_ENTRY_SIZE
) + j
);
2264 trace_ips
= g_list_prepend (trace_ips
, p
);
2269 // Reset the state because we're making it be caught somewhere
2270 if (mono_ex
->caught_in_unmanaged
)
2271 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, caught_in_unmanaged
, 0);
2273 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2274 mono_error_assert_ok (error
);
2279 call_filter
= (int (*) (MonoContext
*, void *))mono_get_call_filter ();
2281 g_assert (jit_tls
->end_of_stack
);
2282 g_assert (jit_tls
->abort_func
);
2285 *out_filter_idx
= -1;
2289 *out_prev_ji
= NULL
;
2293 unwinder_init (&unwinder
);
2296 MonoContext new_ctx
;
2298 int clause_index_start
= 0;
2299 gboolean unwind_res
= TRUE
;
2301 StackFrameInfo frame
;
2306 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2308 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2309 g_list_free (trace_ips
);
2313 switch (frame
.type
) {
2314 case FRAME_TYPE_DEBUGGER_INVOKE
:
2315 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2316 case FRAME_TYPE_TRAMPOLINE
:
2317 case FRAME_TYPE_INTERP_TO_MANAGED
:
2318 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2321 case FRAME_TYPE_INTERP
:
2322 case FRAME_TYPE_MANAGED
:
2325 g_assert_not_reached ();
2329 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2334 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2336 ip
= MONO_CONTEXT_GET_IP (ctx
);
2339 method
= jinfo_get_method (ji
);
2340 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2342 if (mini_debug_options
.reverse_pinvoke_exceptions
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2343 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2344 "The native frame called the managed method:\n%s\n",
2345 mono_method_full_name (method
, TRUE
));
2348 if (method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
2349 // avoid giant stack traces during a stack overflow
2350 if (frame_count
< 1000) {
2351 trace_ips
= g_list_prepend (trace_ips
, ip
);
2352 trace_ips
= g_list_prepend (trace_ips
, get_generic_info_from_stack_frame (ji
, ctx
));
2353 trace_ips
= g_list_prepend (trace_ips
, ji
);
2357 if (method
->dynamic
)
2358 dynamic_methods
= g_slist_prepend (dynamic_methods
, method
);
2360 if (stack_overflow
) {
2361 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2363 free_stack
= 0xffffff;
2366 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2367 result
= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
;
2371 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2372 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2373 gboolean filtered
= FALSE
;
2376 * During stack overflow, wait till the unwinding frees some stack
2377 * space before running handlers/finalizers.
2379 if (free_stack
<= (64 * 1024))
2382 if (is_address_protected (ji
, ei
, ip
)) {
2384 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2387 * Have to unwrap RuntimeWrappedExceptions if the
2388 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2390 if (non_exception
&& !wrap_non_exception_throws (method
))
2391 ex_obj
= non_exception
;
2395 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2396 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2398 #ifndef DISABLE_PERFCOUNTERS
2399 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_filters
);
2402 if (!ji
->is_interp
) {
2403 #ifndef MONO_CROSS_COMPILE
2404 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2406 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2408 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2409 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2411 g_assert (!ji
->from_llvm
);
2412 /* store the exception object in bp + ei->exvar_offset */
2413 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2417 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2419 * Pass the original il clause index to the landing pad so it can
2420 * branch to the landing pad associated with the il clause.
2421 * This is needed because llvm compiled code assumes that the EH
2422 * code always branches to the innermost landing pad.
2425 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2429 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2431 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2432 jit_tls
->orig_ex_ctx_set
= TRUE
;
2433 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2434 jit_tls
->orig_ex_ctx_set
= FALSE
;
2437 if (ji
->is_interp
) {
2438 /* The filter ends where the exception handler starts */
2439 filtered
= mini_get_interp_callbacks ()->run_filter (&frame
, (MonoException
*)ex_obj
, i
, ei
->data
.filter
, ei
->handler_start
);
2441 filtered
= call_filter (ctx
, ei
->data
.filter
);
2443 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2444 if (filtered
&& out_filter_idx
)
2445 *out_filter_idx
= filter_idx
;
2451 g_list_free (trace_ips
);
2452 /* mono_debugger_agent_handle_exception () needs this */
2453 mini_set_abort_threshold (&frame
);
2454 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2455 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2456 *catch_frame
= frame
;
2457 result
= MONO_FIRST_PASS_HANDLED
;
2462 ERROR_DECL (isinst_error
); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2463 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (ex_obj
, catch_class
, error
)) {
2464 /* runtime invokes catch even unhandled exceptions */
2465 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
);
2466 g_list_free (trace_ips
);
2471 /* mono_debugger_agent_handle_exception () needs this */
2473 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2474 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2475 *catch_frame
= frame
;
2476 result
= MONO_FIRST_PASS_HANDLED
;
2477 if (method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2478 //try to find threadpool_perform_wait_callback_method
2479 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &new_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2480 while (unwind_res
) {
2481 if (frame
.ji
&& !frame
.ji
->is_trampoline
&& jinfo_get_method (frame
.ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2482 *last_mono_wrapper_runtime_invoke
= FALSE
;
2485 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &new_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2490 mono_error_cleanup (isinst_error
);
2497 g_assert_not_reached ();
2501 * We implement delaying of aborts when in finally blocks by reusing the
2502 * abort protected block mechanism. The problem is that when throwing an
2503 * exception in a finally block we don't get to exit the protected block.
2504 * We exit it here when unwinding. Given that the order of the clauses
2505 * in the jit info is from inner clauses to the outer clauses, when we
2506 * want to exit the finally blocks inner to the clause that handles the
2507 * exception, we need to search up to its index.
2509 * FIXME We should do this inside interp, but with mixed mode we can
2510 * resume directly, without giving control back to the interp.
2513 interp_exit_finally_abort_blocks (MonoJitInfo
*ji
, int start_clause
, int end_clause
, gpointer ip
)
2516 for (i
= start_clause
; i
< end_clause
; i
++) {
2517 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2518 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
&&
2519 ip
>= ei
->handler_start
&&
2520 ip
< ei
->data
.handler_end
) {
2521 mono_threads_end_abort_protected_block ();
2526 static MonoException
*
2527 mono_get_exception_runtime_wrapped_checked (MonoObject
*wrapped_exception_raw
, MonoError
*error
)
2529 HANDLE_FUNCTION_ENTER ();
2530 MONO_HANDLE_DCL (MonoObject
, wrapped_exception
);
2531 MonoExceptionHandle ret
= mono_get_exception_runtime_wrapped_handle (wrapped_exception
, error
);
2532 HANDLE_FUNCTION_RETURN_OBJ (ret
);
2536 * mono_handle_exception_internal:
2537 * \param ctx saved processor state
2538 * \param obj the exception object
2539 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2542 mono_handle_exception_internal (MonoContext
*ctx
, MonoObject
*obj
, gboolean resume
, MonoJitInfo
**out_ji
)
2545 MonoDomain
*domain
= mono_domain_get ();
2546 MonoJitInfo
*ji
, *prev_ji
;
2547 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2548 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2549 MonoLMF
*lmf
= mono_get_lmf ();
2550 MonoException
*mono_ex
;
2551 gboolean stack_overflow
= FALSE
;
2552 MonoContext initial_ctx
;
2554 int frame_count
= 0;
2555 gint32 filter_idx
, first_filter_idx
= 0;
2557 MonoObject
*ex_obj
= NULL
;
2558 MonoObject
*non_exception
= NULL
;
2561 gboolean is_caught_unmanaged
= FALSE
;
2562 gboolean last_mono_wrapper_runtime_invoke
= TRUE
;
2564 g_assert (ctx
!= NULL
);
2566 MonoException
*ex
= mono_get_exception_null_reference ();
2567 MonoString
*msg
= mono_string_new_checked (domain
, "Object reference not set to an instance of an object", error
);
2568 mono_error_assert_ok (error
);
2569 MONO_OBJECT_SETREF_INTERNAL (ex
, message
, msg
);
2570 obj
= (MonoObject
*)ex
;
2574 * Allocate a new exception object instead of the preconstructed ones.
2576 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
) {
2578 * It is not a good idea to try and put even more pressure on the little stack available.
2579 * obj = mono_get_exception_stack_overflow ();
2581 stack_overflow
= TRUE
;
2583 else if (obj
== (MonoObject
*)domain
->null_reference_ex
) {
2584 obj
= (MonoObject
*)mono_get_exception_null_reference ();
2587 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2588 mono_error_assert_ok (error
);
2589 non_exception
= obj
;
2590 obj
= (MonoObject
*)mono_get_exception_runtime_wrapped_checked (obj
, error
);
2591 mono_error_assert_ok (error
);
2594 mono_ex
= (MonoException
*)obj
;
2596 if (mini_debug_options
.suspend_on_exception
) {
2597 mono_runtime_printf_err ("Exception thrown, suspending...");
2602 if (mono_ex
->caught_in_unmanaged
)
2603 is_caught_unmanaged
= TRUE
;
2606 if (mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2607 mono_ex
= (MonoException
*)obj
;
2609 mono_error_assert_ok (error
);
2613 if (mono_ex
&& jit_tls
->class_cast_from
) {
2614 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "InvalidCastException")) {
2615 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2616 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2617 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
2618 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2621 if (!is_ok (error
)) {
2622 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg
);
2623 mono_error_assert_ok (error
);
2627 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "ArrayTypeMismatchException")) {
2628 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2629 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2630 char *msg
= g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name
, to_name
);
2631 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2634 if (!is_ok (error
)) {
2635 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg
);
2636 mono_error_assert_ok (error
);
2643 call_filter
= (int (*)(MonoContext
*, void*))mono_get_call_filter ();
2645 g_assert (jit_tls
->end_of_stack
);
2646 g_assert (jit_tls
->abort_func
);
2649 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2650 * end up being TRUE on any code path.
2652 memcpy (&jit_tls
->orig_ex_ctx
, ctx
, sizeof (MonoContext
));
2655 MonoContext ctx_cp
= *ctx
;
2656 if (mono_trace_is_enabled ()) {
2658 MonoMethod
*system_exception_get_message
= mono_class_get_method_from_name_checked (mono_defaults
.exception_class
, "get_Message", 0, 0, error
);
2659 mono_error_cleanup (error
);
2661 MonoMethod
*get_message
= system_exception_get_message
== NULL
? NULL
: mono_object_get_virtual_method_internal (obj
, system_exception_get_message
);
2662 MonoObject
*message
;
2663 const char *type_name
= m_class_get_name (mono_object_class (mono_ex
));
2665 if (get_message
== NULL
) {
2667 } else if (!strcmp (type_name
, "OutOfMemoryException") || !strcmp (type_name
, "StackOverflowException")) {
2669 msg
= g_strdup_printf ("(No exception message for: %s)\n", type_name
);
2671 MonoObject
*exc
= NULL
;
2672 message
= mono_runtime_try_invoke (get_message
, obj
, NULL
, &exc
, error
);
2673 g_assert (exc
== NULL
);
2674 mono_error_assert_ok (error
);
2678 msg
= mono_string_to_utf8_checked_internal ((MonoString
*) message
, error
);
2679 if (!is_ok (error
)) {
2680 mono_error_cleanup (error
);
2681 msg
= g_strdup ("(error while display System.Exception.Message property)");
2684 msg
= g_strdup ("(System.Exception.Message property not available)");
2687 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)mono_native_thread_id_get (), m_class_get_name_space (mono_object_class (obj
)), m_class_get_name (mono_object_class (obj
)), msg
);
2689 if (mono_ex
&& mono_trace_eval_exception (mono_object_class (mono_ex
)))
2690 mono_print_thread_dump_from_ctx (ctx
);
2692 jit_tls
->orig_ex_ctx_set
= TRUE
;
2693 MONO_PROFILER_RAISE (exception_throw
, (obj
));
2694 jit_tls
->orig_ex_ctx_set
= FALSE
;
2696 StackFrameInfo catch_frame
;
2697 MonoFirstPassResult res
;
2698 res
= handle_exception_first_pass (&ctx_cp
, obj
, &first_filter_idx
, &ji
, &prev_ji
, non_exception
, &catch_frame
, &last_mono_wrapper_runtime_invoke
);
2700 if (res
== MONO_FIRST_PASS_UNHANDLED
) {
2701 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2702 /* Reached the top interpreted frames, but there might be native frames above us */
2703 throw_exception (obj
, TRUE
);
2704 g_assert_not_reached ();
2706 if (mini_debug_options
.break_on_exc
)
2708 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2710 // FIXME: This runs managed code so it might cause another stack overflow when
2711 // we are handling a stack overflow
2712 mini_set_abort_threshold (&catch_frame
);
2713 mono_unhandled_exception_internal (obj
);
2715 gboolean unhandled
= FALSE
;
2718 * The exceptions caught by the mono_runtime_invoke_checked () calls
2719 * in the threadpool needs to be treated as unhandled (#669836).
2721 * FIXME: The check below is hackish, but its hard to distinguish
2722 * these runtime invoke calls from others in the runtime.
2724 #ifndef ENABLE_NETCORE
2725 if (ji
&& jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2726 if (prev_ji
&& jinfo_get_method (prev_ji
) == mono_defaults
.threadpool_perform_wait_callback_method
)
2732 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2733 else if (!ji
|| (jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
)) {
2734 if (last_mono_wrapper_runtime_invoke
&& !mono_thread_internal_current ()->threadpool_thread
)
2735 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2737 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2739 else if (res
!= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
)
2740 if (!is_caught_unmanaged
)
2741 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2750 unwinder_init (&unwinder
);
2753 MonoContext new_ctx
;
2755 int clause_index_start
= 0;
2756 gboolean unwind_res
= TRUE
;
2757 StackFrameInfo frame
;
2762 ji
= jit_tls
->resume_state
.ji
;
2763 new_ctx
= jit_tls
->resume_state
.new_ctx
;
2764 clause_index_start
= jit_tls
->resume_state
.clause_index
;
2765 lmf
= jit_tls
->resume_state
.lmf
;
2766 first_filter_idx
= jit_tls
->resume_state
.first_filter_idx
;
2767 filter_idx
= jit_tls
->resume_state
.filter_idx
;
2770 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2772 *(mono_get_lmf_addr ()) = lmf
;
2774 jit_tls
->abort_func (obj
);
2775 g_assert_not_reached ();
2777 switch (frame
.type
) {
2778 case FRAME_TYPE_DEBUGGER_INVOKE
:
2779 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2780 case FRAME_TYPE_TRAMPOLINE
:
2781 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2784 case FRAME_TYPE_INTERP_TO_MANAGED
:
2786 case FRAME_TYPE_INTERP
:
2787 case FRAME_TYPE_MANAGED
:
2790 g_assert_not_reached ();
2793 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2798 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2800 ip
= MONO_CONTEXT_GET_IP (ctx
);
2802 method
= jinfo_get_method (ji
);
2804 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2806 if (stack_overflow
) {
2807 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2809 free_stack
= 0xffffff;
2812 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2813 guint32 handle
= mono_gchandle_new_internal (obj
, FALSE
);
2814 MONO_STACKDATA (stackptr
);
2816 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr
);
2818 ftnptr_eh_callback (handle
);
2819 g_error ("Did not expect ftnptr_eh_callback to return.");
2822 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2823 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2824 gboolean filtered
= FALSE
;
2827 * During stack overflow, wait till the unwinding frees some stack
2828 * space before running handlers/finalizers.
2830 if (free_stack
<= (64 * 1024))
2833 if (is_address_protected (ji
, ei
, ip
)) {
2835 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2838 * Have to unwrap RuntimeWrappedExceptions if the
2839 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2841 if (non_exception
&& !wrap_non_exception_throws (method
))
2842 ex_obj
= non_exception
;
2846 if (((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
))) {
2847 #ifndef MONO_CROSS_COMPILE
2848 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2849 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2851 g_assert (!ji
->from_llvm
);
2852 /* store the exception object in bp + ei->exvar_offset */
2853 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2858 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2860 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2863 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2865 * Filter clauses should only be run in the
2866 * first pass of exception handling.
2868 filtered
= (filter_idx
== first_filter_idx
);
2873 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
2874 mono_object_isinst_checked (ex_obj
, catch_class
, error
)) || filtered
) {
2876 * This guards against the situation that we abort a thread that is executing a finally clause
2877 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2878 * check for this situation here and resume interruption if we are below the guarded block.
2880 if (G_UNLIKELY (jit_tls
->handler_block
)) {
2881 gboolean is_outside
= FALSE
;
2882 gpointer prot_bp
= MONO_CONTEXT_GET_BP (&jit_tls
->handler_block_context
);
2883 gpointer catch_bp
= MONO_CONTEXT_GET_BP (ctx
);
2884 //FIXME make this stack direction aware
2886 if (catch_bp
> prot_bp
) {
2888 } else if (catch_bp
== prot_bp
) {
2889 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2890 * So we check if the catch handler_start is protected by the guarded handler protected region
2893 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2894 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2895 * There aren't any further finally/fault handler blocks down the stack over this exception.
2896 * This must be ensured by the code that installs the guard trampoline.
2898 g_assert (ji
== mini_jit_info_table_find (domain
, (char *)MONO_CONTEXT_GET_IP (&jit_tls
->handler_block_context
), NULL
));
2900 if (!is_address_protected (ji
, jit_tls
->handler_block
, ei
->handler_start
)) {
2905 jit_tls
->handler_block
= NULL
;
2906 mono_thread_resume_interruption (TRUE
); /*We ignore the exception here, it will be raised later*/
2910 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2911 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2914 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2915 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2916 * clause. Since we specifically want to indicate that we're executing the
2917 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2918 * instead of ei->flags.
2920 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2921 jit_tls
->orig_ex_ctx_set
= TRUE
;
2922 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, MONO_EXCEPTION_CLAUSE_NONE
, ex_obj
));
2923 jit_tls
->orig_ex_ctx_set
= FALSE
;
2926 mini_set_abort_threshold (&frame
);
2929 interp_exit_finally_abort_blocks (ji
, clause_index_start
, i
, ip
);
2931 * ctx->pc points into the interpreter, after the call which transitioned to
2932 * JITted code. Store the unwind state into the
2933 * interpeter state, then resume, the interpreter will unwind itself until
2934 * it reaches the target frame and will continue execution from there.
2935 * The resuming is kinda hackish, from the native code standpoint, it looks
2936 * like the call which transitioned to JITted code has succeeded, but the
2937 * return value register etc. is not set, so we have to be careful.
2939 mini_get_interp_callbacks ()->set_resume_state (jit_tls
, mono_ex
, ei
, frame
.interp_frame
, ei
->handler_start
);
2940 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2941 /* ip == 0 means an interpreter frame */
2942 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
2943 mono_arch_undo_ip_adjustment (ctx
);
2945 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2948 #ifndef DISABLE_PERFCOUNTERS
2949 mono_atomic_fetch_add_i32 (&mono_perfcounters
->exceptions_depth
, frame_count
);
2951 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2952 jit_tls
->handling_stack_ovf
= FALSE
;
2956 mono_error_cleanup (error
);
2957 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) {
2958 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2959 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2961 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2962 jit_tls
->orig_ex_ctx_set
= TRUE
;
2963 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2964 jit_tls
->orig_ex_ctx_set
= FALSE
;
2967 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2968 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2969 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2971 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2972 jit_tls
->orig_ex_ctx_set
= TRUE
;
2973 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2974 jit_tls
->orig_ex_ctx_set
= FALSE
;
2977 #ifndef DISABLE_PERFCOUNTERS
2978 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_finallys
);
2981 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
|| ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2983 if (ji
->from_llvm
) {
2985 * LLVM compiled finally handlers follow the design
2986 * of the c++ ehabi, i.e. they call a resume function
2987 * at the end instead of returning to the caller.
2988 * So save the exception handling state,
2989 * mono_resume_unwind () will call us again to continue
2992 jit_tls
->resume_state
.ex_obj
= obj
;
2993 jit_tls
->resume_state
.ji
= ji
;
2994 jit_tls
->resume_state
.clause_index
= i
+ 1;
2995 jit_tls
->resume_state
.ctx
= *ctx
;
2996 jit_tls
->resume_state
.new_ctx
= new_ctx
;
2997 jit_tls
->resume_state
.lmf
= lmf
;
2998 jit_tls
->resume_state
.first_filter_idx
= first_filter_idx
;
2999 jit_tls
->resume_state
.filter_idx
= filter_idx
;
3000 mini_set_abort_threshold (&frame
);
3001 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
3004 mini_set_abort_threshold (&frame
);
3006 gboolean has_ex
= mini_get_interp_callbacks ()->run_finally (&frame
, i
, ei
->handler_start
, ei
->data
.handler_end
);
3009 * If run_finally didn't resume to a context, it means that the handler frame
3010 * is linked to the frame calling finally through interpreter frames. This
3011 * means that we will reach the handler frame by resuming the current context.
3013 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
3014 mono_arch_undo_ip_adjustment (ctx
);
3018 call_filter (ctx
, ei
->handler_start
);
3026 interp_exit_finally_abort_blocks (ji
, clause_index_start
, ji
->num_clauses
, ip
);
3028 if (MONO_PROFILER_ENABLED (method_exception_leave
) &&
3029 mono_profiler_get_call_instrumentation_flags (method
) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
) {
3030 jit_tls
->orig_ex_ctx_set
= TRUE
;
3031 MONO_PROFILER_RAISE (method_exception_leave
, (method
, ex_obj
));
3032 jit_tls
->orig_ex_ctx_set
= FALSE
;
3038 g_assert_not_reached ();
3042 * mono_debugger_run_finally:
3043 * \param start_ctx saved processor state
3044 * This method is called by the Mono Debugger to call all \c finally clauses of the
3045 * current stack frame. It's used when the user issues a \c return command to make
3046 * the current stack frame return. After returning from this method, the debugger
3047 * unwinds the stack one frame and gives control back to the user.
3048 * NOTE: This method is only used when running inside the Mono Debugger.
3051 mono_debugger_run_finally (MonoContext
*start_ctx
)
3053 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
3054 MonoDomain
*domain
= mono_domain_get ();
3055 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3056 MonoLMF
*lmf
= mono_get_lmf ();
3057 MonoContext ctx
, new_ctx
;
3058 MonoJitInfo
*ji
, rji
;
3063 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
3064 if (!ji
|| ji
== (gpointer
)-1)
3068 call_filter
= (int (*)(MonoContext
*, void *))mono_get_call_filter ();
3070 for (i
= 0; i
< ji
->num_clauses
; i
++) {
3071 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
3073 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (&ctx
)) &&
3074 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
3075 call_filter (&ctx
, ei
->handler_start
);
3081 * mono_handle_exception:
3082 * \param ctx saved processor state
3083 * \param obj the exception object
3085 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3089 mono_handle_exception (MonoContext
*ctx
, gpointer void_obj
)
3091 MonoObject
*obj
= (MonoObject
*)void_obj
;
3093 MONO_REQ_GC_UNSAFE_MODE
;
3095 #ifndef DISABLE_PERFCOUNTERS
3096 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_thrown
);
3099 return mono_handle_exception_internal (ctx
, obj
, FALSE
, NULL
);
3102 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3104 #ifndef MONO_ARCH_USE_SIGACTION
3105 #error "Can't use sigaltstack without sigaction"
3109 mono_setup_altstack (MonoJitTlsData
*tls
)
3113 guint8
*staddr
= NULL
;
3114 #if defined(TARGET_OSX) || defined(_AIX)
3116 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3117 * stack pages. Stack overflow on main thread will kill the app.
3119 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3120 * do this for thread 1 with its stack at the top of memory. Other threads seem
3121 * fine for the altstack guard page, though.
3123 gboolean disable_stack_guard
= mono_threads_platform_is_main_thread ();
3125 gboolean disable_stack_guard
= FALSE
;
3128 if (mono_running_on_valgrind ())
3131 mono_thread_info_get_stack_bounds (&staddr
, &stsize
);
3135 tls
->end_of_stack
= staddr
+ stsize
;
3136 tls
->stack_size
= stsize
;
3138 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3140 if (!disable_stack_guard
) {
3141 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
3142 tls
->stack_ovf_guard_size
= ALIGN_TO (8 * 4096, mono_pagesize ());
3144 g_assert ((guint8
*)&sa
>= (guint8
*)tls
->stack_ovf_guard_base
+ tls
->stack_ovf_guard_size
);
3146 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
3147 /* mprotect can fail for the main thread stack */
3148 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
);
3150 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
3151 tls
->stack_ovf_valloced
= TRUE
;
3153 g_warning ("couldn't allocate guard page, continue without it");
3154 tls
->stack_ovf_guard_base
= NULL
;
3155 tls
->stack_ovf_guard_size
= 0;
3160 /* Setup an alternate signal stack */
3161 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
);
3162 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3164 g_assert (tls
->signal_stack
);
3166 sa
.ss_sp
= tls
->signal_stack
;
3167 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3169 g_assert (sigaltstack (&sa
, NULL
) == 0);
3171 if (tls
->stack_ovf_guard_base
)
3172 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
);
3174 mono_gc_register_altstack (staddr
, stsize
, tls
->signal_stack
, tls
->signal_stack_size
);
3179 mono_free_altstack (MonoJitTlsData
*tls
)
3184 sa
.ss_sp
= tls
->signal_stack
;
3185 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3186 sa
.ss_flags
= SS_DISABLE
;
3187 err
= sigaltstack (&sa
, NULL
);
3188 g_assert (err
== 0);
3190 if (tls
->signal_stack
)
3191 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3193 if (!tls
->stack_ovf_guard_base
)
3195 if (tls
->stack_ovf_valloced
)
3196 mono_vfree (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3198 mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3201 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3204 mono_setup_altstack (MonoJitTlsData
*tls
)
3209 mono_free_altstack (MonoJitTlsData
*tls
)
3213 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3216 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*siginfo
, guint8
* fault_addr
)
3224 /* we got a stack overflow in the soft-guard pages
3225 * There are two cases:
3226 * 1) managed code caused the overflow: we unprotect the soft-guard page
3227 * and let the arch-specific code trigger the exception handling mechanism
3228 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3229 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3230 * and hope we can continue with those enabled, at least until the hard-guard page
3231 * is hit. The alternative to continuing here is to just print a message and abort.
3232 * We may add in the future the code to protect the pages again in the codepath
3233 * when we return from unmanaged to managed code.
3235 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
3236 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
3237 gboolean handled
= FALSE
;
3239 mono_mprotect (jit_tls
->stack_ovf_guard_base
, jit_tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3240 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3242 mono_arch_handle_altstack_exception (ctx
, siginfo
, fault_addr
, TRUE
);
3247 /* We print a message: after this even managed stack overflows
3248 * may crash the runtime
3250 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx
), fault_addr
);
3251 if (!jit_tls
->handling_stack_ovf
) {
3252 jit_tls
->handling_stack_ovf
= 1;
3254 /*fprintf (stderr, "Already handling stack overflow\n");*/
3263 MonoMethod
*omethod
;
3265 } PrintOverflowUserData
;
3268 print_overflow_stack_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3270 MonoMethod
*method
= NULL
;
3271 PrintOverflowUserData
*user_data
= (PrintOverflowUserData
*)data
;
3274 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3275 method
= jinfo_get_method (frame
->ji
);
3278 if (user_data
->count
== 0) {
3279 /* The first frame is in its prolog, so a line number cannot be computed */
3280 user_data
->count
++;
3284 /* If this is a one method overflow, skip the other instances */
3285 if (method
== user_data
->omethod
)
3288 location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, mono_domain_get ());
3289 mono_runtime_printf_err (" %s", location
);
3292 if (user_data
->count
== 1) {
3293 mono_runtime_printf_err (" <...>");
3294 user_data
->omethod
= method
;
3296 user_data
->omethod
= NULL
;
3299 user_data
->count
++;
3301 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame
->native_offset
);
3307 mono_handle_hard_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, MonoContext
*mctx
, guint8
* fault_addr
)
3309 PrintOverflowUserData ud
;
3311 /* we don't do much now, but we can warn the user with a useful message */
3312 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx
), fault_addr
);
3314 mono_runtime_printf_err ("Stacktrace:");
3316 memset (&ud
, 0, sizeof (ud
));
3318 mono_walk_stack_with_ctx (print_overflow_stack_frame
, mctx
, MONO_UNWIND_LOOKUP_ACTUAL_METHOD
, &ud
);
3324 print_stack_frame_signal_safe (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3326 MonoMethod
*method
= NULL
;
3328 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3329 method
= jinfo_get_method (frame
->ji
);
3332 const char *name_space
= m_class_get_name_space (method
->klass
);
3333 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
);
3335 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame
->native_offset
);
3341 static G_GNUC_UNUSED gboolean
3342 print_stack_frame_to_string (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3344 GString
*p
= (GString
*)data
;
3345 MonoMethod
*method
= NULL
;
3347 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3348 method
= jinfo_get_method (frame
->ji
);
3350 if (method
&& frame
->domain
) {
3351 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
3352 g_string_append_printf (p
, " %s\n", location
);
3355 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
3360 #ifndef MONO_CROSS_COMPILE
3361 static gboolean handle_crash_loop
= FALSE
;
3364 * mono_handle_native_crash:
3366 * Handle a native crash (e.g. SIGSEGV) while in native code by
3367 * printing diagnostic information and aborting.
3370 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3372 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3374 if (handle_crash_loop
)
3377 #ifdef MONO_ARCH_USE_SIGACTION
3378 struct sigaction sa
;
3379 sa
.sa_handler
= SIG_DFL
;
3380 sigemptyset (&sa
.sa_mask
);
3383 /* Remove our SIGABRT handler */
3384 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
3386 /* On some systems we get a SIGILL when calling abort (), because it might
3387 * fail to raise SIGABRT */
3388 g_assert (sigaction (SIGILL
, &sa
, NULL
) != -1);
3390 /* Remove SIGCHLD, it uses the finalizer thread */
3391 g_assert (sigaction (SIGCHLD
, &sa
, NULL
) != -1);
3393 /* Remove SIGQUIT, we are already dumping threads */
3394 g_assert (sigaction (SIGQUIT
, &sa
, NULL
) != -1);
3398 if (mini_debug_options
.suspend_on_native_crash
) {
3399 g_async_safe_printf ("Received %s, suspending...\n", signal
);
3401 // Sleep for 1 second.
3402 g_usleep (1000 * 1000);
3406 /* prevent infinite loops in crash handling */
3407 handle_crash_loop
= TRUE
;
3410 * A SIGSEGV indicates something went very wrong so we can no longer depend
3411 * on anything working. So try to print out lots of diagnostics, starting
3412 * with ones which have a greater chance of working.
3415 g_async_safe_printf("\n=================================================================\n");
3416 g_async_safe_printf("\tNative Crash Reporting\n");
3417 g_async_safe_printf("=================================================================\n");
3418 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal
);
3419 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3420 g_async_safe_printf("used by your application.\n");
3421 g_async_safe_printf("=================================================================\n");
3422 mono_dump_native_crash_info (signal
, mctx
, info
);
3424 /* !jit_tls means the thread was not registered with the runtime */
3425 // This must be below the native crash dump, because we can't safely
3426 // do runtime state probing after we have walked the managed stack here.
3427 if (jit_tls
&& mono_thread_internal_current () && mctx
) {
3428 g_async_safe_printf ("\n=================================================================\n");
3429 g_async_safe_printf ("\tManaged Stacktrace:\n");
3430 g_async_safe_printf ("=================================================================\n");
3432 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
);
3433 g_async_safe_printf ("=================================================================\n");
3436 mono_post_native_crash_handler (signal
, mctx
, info
, mono_do_crash_chaining
);
3442 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3444 g_assert_not_reached ();
3447 #endif /* !MONO_CROSS_COMPILE */
3450 mono_print_thread_dump_internal (void *sigctx
, MonoContext
*start_ctx
)
3452 MonoInternalThread
*thread
= mono_thread_internal_current ();
3459 text
= g_string_new (0);
3461 mono_gstring_append_thread_name (text
, thread
);
3463 g_string_append_printf (text
, " tid=%p this=%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
3464 mono_thread_internal_describe (thread
, text
);
3465 g_string_append (text
, "\n");
3468 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
3470 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
3472 mono_sigctx_to_monoctx (sigctx
, &ctx
);
3474 mono_walk_stack_with_ctx (print_stack_frame_to_string
, &ctx
, MONO_UNWIND_LOOKUP_ALL
, text
);
3476 mono_runtime_printf ("%s", text
->str
);
3478 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3479 OutputDebugStringA(text
->str
);
3482 g_string_free (text
, TRUE
);
3483 mono_runtime_stdout_fflush ();
3487 * mono_print_thread_dump:
3489 * Print information about the current thread to stdout.
3490 * \p sigctx can be NULL, allowing this to be called from gdb.
3493 mono_print_thread_dump (void *sigctx
)
3495 mono_print_thread_dump_internal (sigctx
, NULL
);
3499 mono_print_thread_dump_from_ctx (MonoContext
*ctx
)
3501 mono_print_thread_dump_internal (NULL
, ctx
);
3505 * mono_resume_unwind:
3507 * This is called by a trampoline from LLVM compiled finally clauses to continue
3511 mono_resume_unwind (MonoContext
*ctx
)
3513 MONO_REQ_GC_UNSAFE_MODE
;
3515 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3516 MonoContext new_ctx
;
3518 MONO_CONTEXT_SET_IP (ctx
, MONO_CONTEXT_GET_IP (&jit_tls
->resume_state
.ctx
));
3519 MONO_CONTEXT_SET_SP (ctx
, MONO_CONTEXT_GET_SP (&jit_tls
->resume_state
.ctx
));
3522 mono_handle_exception_internal (&new_ctx
, (MonoObject
*)jit_tls
->resume_state
.ex_obj
, TRUE
, NULL
);
3524 mono_restore_context (&new_ctx
);
3530 MonoJitExceptionInfo
*ei
;
3531 } FindHandlerBlockData
;
3534 find_last_handler_block (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3538 FindHandlerBlockData
*pdata
= (FindHandlerBlockData
*)data
;
3539 MonoJitInfo
*ji
= frame
->ji
;
3544 ip
= MONO_CONTEXT_GET_IP (ctx
);
3546 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
3547 MonoJitExceptionInfo
*ei
= ji
->clauses
+ i
;
3548 if (ei
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
3550 /*If ip points to the first instruction it means the handler block didn't start
3551 so we can leave its execution to the EH machinery*/
3552 if (ei
->handler_start
<= ip
&& ip
< ei
->data
.handler_end
) {
3564 install_handler_block_guard (MonoJitInfo
*ji
, MonoContext
*ctx
)
3567 MonoJitExceptionInfo
*clause
= NULL
;
3571 ip
= MONO_CONTEXT_GET_IP (ctx
);
3573 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
3574 clause
= &ji
->clauses
[i
];
3575 if (clause
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
3577 if (clause
->handler_start
<= ip
&& clause
->data
.handler_end
> ip
)
3581 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3582 g_assert (i
< ji
->num_clauses
);
3585 bp
= (guint8
*)MONO_CONTEXT_GET_BP (ctx
);
3586 *(bp
+ clause
->exvar_offset
) = 1;
3590 * Finds the bottom handler block running and install a block guard if needed.
3593 mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
)
3595 FindHandlerBlockData data
= { 0 };
3596 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
];
3598 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3599 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3601 if (!jit_tls
|| jit_tls
->handler_block
)
3604 /* Do an async safe stack walk */
3605 mono_thread_info_set_is_async_context (TRUE
);
3606 mono_walk_stack_with_state (find_last_handler_block
, ctx
, MONO_UNWIND_NONE
, &data
);
3607 mono_thread_info_set_is_async_context (FALSE
);
3612 memcpy (&jit_tls
->handler_block_context
, &data
.ctx
, sizeof (MonoContext
));
3614 install_handler_block_guard (data
.ji
, &data
.ctx
);
3616 jit_tls
->handler_block
= data
.ei
;
3622 mono_uninstall_current_handler_block_guard (void)
3624 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3626 jit_tls
->handler_block
= NULL
;
3631 mono_current_thread_has_handle_block_guard (void)
3633 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3634 return jit_tls
&& jit_tls
->handler_block
!= NULL
;
3638 mono_set_cast_details (MonoClass
*from
, MonoClass
*to
)
3640 MonoJitTlsData
*jit_tls
= NULL
;
3642 if (mini_debug_options
.better_cast_details
) {
3643 jit_tls
= mono_tls_get_jit_tls ();
3644 jit_tls
->class_cast_from
= from
;
3645 jit_tls
->class_cast_to
= to
;
3650 /*returns false if the thread is not attached*/
3652 mono_thread_state_init_from_sigctx (MonoThreadUnwindState
*ctx
, void *sigctx
)
3654 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3661 mono_sigctx_to_monoctx (sigctx
, &ctx
->ctx
);
3663 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3664 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3665 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3668 mono_thread_state_init (ctx
);
3671 if (!ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] || !ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
])
3679 mono_thread_state_init (MonoThreadUnwindState
*ctx
)
3681 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3683 #if defined(MONO_CROSS_COMPILE)
3684 ctx
->valid
= FALSE
; //A cross compiler doesn't need to suspend.
3685 #elif MONO_ARCH_HAS_MONO_CONTEXT
3686 MONO_CONTEXT_GET_CURRENT (ctx
->ctx
);
3688 g_error ("Use a null sigctx requires a working mono-context");
3691 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3692 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3693 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
? thread
->jit_data
: NULL
;
3699 mono_thread_state_init_from_monoctx (MonoThreadUnwindState
*ctx
, MonoContext
*mctx
)
3701 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3708 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3709 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3710 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3715 /*returns false if the thread is not attached*/
3717 mono_thread_state_init_from_current (MonoThreadUnwindState
*ctx
)
3719 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3720 MONO_ARCH_CONTEXT_DEF
3722 mono_arch_flush_register_windows ();
3724 if (!thread
|| !thread
->jit_data
) {
3728 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
->ctx
, mono_thread_state_init_from_current
);
3730 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3731 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3732 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3738 mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
)
3740 mono_handle_exception (ctx
, (MonoObject
*)exc
);
3741 mono_restore_context (ctx
);
3744 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3746 mono_setup_async_callback (MonoContext
*ctx
, void (*async_cb
)(void *fun
), gpointer user_data
)
3748 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3749 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3750 jit_tls
->ex_ctx
= *ctx
;
3752 mono_arch_setup_async_callback (ctx
, async_cb
, user_data
);
3754 g_error ("This target doesn't support mono_arch_setup_async_callback");
3759 * mono_restore_context:
3761 * Call the architecture specific restore context function.
3764 mono_restore_context (MonoContext
*ctx
)
3766 static void (*restore_context
) (MonoContext
*);
3768 if (!restore_context
)
3769 restore_context
= (void (*)(MonoContext
*))mono_get_restore_context ();
3770 restore_context (ctx
);
3771 g_assert_not_reached ();
3775 * mono_jinfo_get_unwind_info:
3777 * Return the unwind info for JI.
3780 mono_jinfo_get_unwind_info (MonoJitInfo
*ji
, guint32
*unwind_info_len
)
3782 if (ji
->has_unwind_info
) {
3783 /* The address/length in the MonoJitInfo structure itself */
3784 MonoUnwindJitInfo
*info
= mono_jit_info_get_unwind_info (ji
);
3785 *unwind_info_len
= info
->unw_info_len
;
3786 return info
->unw_info
;
3787 } else if (ji
->from_aot
)
3788 return mono_aot_get_unwind_info (ji
, unwind_info_len
);
3790 return mono_get_cached_unwind_info (ji
->unwind_info
, unwind_info_len
);
3794 mono_jinfo_get_epilog_size (MonoJitInfo
*ji
)
3796 MonoArchEHJitInfo
*info
;
3798 info
= mono_jit_info_get_arch_eh_info (ji
);
3801 return info
->epilog_size
;
3805 * mono_install_ftnptr_eh_callback:
3807 * Install a callback that should be called when there is a managed exception
3808 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3809 * managed exception to a native exception, to properly unwind the native
3810 * stack; this native exception will then be converted back to a managed
3811 * exception in their managed-to-native wrapper.
3814 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback
)
3816 ftnptr_eh_callback
= callback
;
3820 * LLVM/Bitcode exception handling.
3824 throw_exception (MonoObject
*ex
, gboolean rethrow
)
3826 MONO_REQ_GC_UNSAFE_MODE
;
3829 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3830 MonoException
*mono_ex
;
3832 if (!mono_object_isinst_checked (ex
, mono_defaults
.exception_class
, error
)) {
3833 mono_error_assert_ok (error
);
3834 mono_ex
= mono_get_exception_runtime_wrapped_checked (ex
, error
);
3835 mono_error_assert_ok (error
);
3836 jit_tls
->thrown_non_exc
= mono_gchandle_new_internal (ex
, FALSE
);
3839 mono_ex
= (MonoException
*)ex
;
3842 jit_tls
->thrown_exc
= mono_gchandle_new_internal ((MonoObject
*)mono_ex
, FALSE
);
3845 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3846 GList
*l
, *ips
= NULL
;
3849 _Unwind_Backtrace (build_stack_trace
, &ips
);
3850 /* The list contains ip-gshared info pairs */
3852 ips
= g_list_reverse (ips
);
3853 for (l
= ips
; l
; l
= l
->next
) {
3854 trace
= g_list_append (trace
, l
->data
);
3855 trace
= g_list_append (trace
, NULL
);
3856 trace
= g_list_append (trace
, NULL
);
3858 MonoArray
*ips_arr
= mono_glist_to_array (trace
, mono_defaults
.int_class
, error
);
3859 mono_error_assert_ok (error
);
3860 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
3862 g_list_free (trace
);
3866 mono_llvm_cpp_throw_exception ();
3870 mono_llvm_throw_exception (MonoObject
*ex
)
3872 throw_exception (ex
, FALSE
);
3876 mono_llvm_rethrow_exception (MonoObject
*ex
)
3878 throw_exception (ex
, TRUE
);
3882 mono_llvm_raise_exception (MonoException
*e
)
3884 mono_llvm_throw_exception ((MonoObject
*)e
);
3888 mono_llvm_reraise_exception (MonoException
*e
)
3890 mono_llvm_rethrow_exception ((MonoObject
*)e
);
3894 mono_llvm_throw_corlib_exception (guint32 ex_token_index
)
3896 guint32 ex_token
= MONO_TOKEN_TYPE_DEF
| ex_token_index
;
3899 ex
= mono_exception_from_token (m_class_get_image (mono_defaults
.exception_class
), ex_token
);
3901 mono_llvm_throw_exception ((MonoObject
*)ex
);
3905 * mono_llvm_resume_exception:
3907 * Resume exception propagation.
3910 mono_llvm_resume_exception (void)
3912 mono_llvm_cpp_throw_exception ();
3916 * mono_llvm_load_exception:
3918 * Return the currently thrown exception.
3921 mono_llvm_load_exception (void)
3924 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3926 MonoException
*mono_ex
= (MonoException
*)mono_gchandle_get_target_internal (jit_tls
->thrown_exc
);
3928 MonoArray
*ta
= mono_ex
->trace_ips
;
3931 GList
*trace_ips
= NULL
;
3932 gpointer ip
= MONO_RETURN_ADDRESS ();
3934 size_t upper
= mono_array_length_internal (ta
);
3936 for (int i
= 0; i
< upper
; i
+= TRACE_IP_ENTRY_SIZE
) {
3937 gpointer curr_ip
= mono_array_get_internal (ta
, gpointer
, i
);
3938 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
3939 gpointer p
= mono_array_get_internal (ta
, gpointer
, i
+ j
);
3940 trace_ips
= g_list_append (trace_ips
, p
);
3946 // FIXME: Does this work correctly for rethrows?
3947 // We may be discarding useful information
3948 // when this gets GC'ed
3949 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips
, mono_defaults
.int_class
, error
);
3950 mono_error_assert_ok (error
);
3951 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
3952 g_list_free (trace_ips
);
3955 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3957 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, 0, error
));
3958 mono_error_assert_ok (error
);
3959 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, stack_trace
, mono_array_new_checked (mono_domain_get (), mono_defaults
.stack_frame_class
, 0, error
));
3960 mono_error_assert_ok (error
);
3963 return &mono_ex
->object
;
3967 * mono_llvm_clear_exception:
3969 * Mark the currently thrown exception as handled.
3972 mono_llvm_clear_exception (void)
3974 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3975 mono_gchandle_free_internal (jit_tls
->thrown_exc
);
3976 jit_tls
->thrown_exc
= 0;
3977 if (jit_tls
->thrown_non_exc
)
3978 mono_gchandle_free_internal (jit_tls
->thrown_non_exc
);
3979 jit_tls
->thrown_non_exc
= 0;
3981 mono_memory_barrier ();
3985 * mono_llvm_match_exception:
3987 * Return the innermost clause containing REGION_START-REGION_END which can handle
3988 * the current exception.
3991 mono_llvm_match_exception (MonoJitInfo
*jinfo
, guint32 region_start
, guint32 region_end
, gpointer rgctx
, MonoObject
*this_obj
)
3994 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3998 g_assert (jit_tls
->thrown_exc
);
3999 exc
= mono_gchandle_get_target_internal (jit_tls
->thrown_exc
);
4000 if (jit_tls
->thrown_non_exc
) {
4002 * Have to unwrap RuntimeWrappedExceptions if the
4003 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
4005 if (!wrap_non_exception_throws (jinfo_get_method (jinfo
)))
4006 exc
= mono_gchandle_get_target_internal (jit_tls
->thrown_non_exc
);
4009 for (int i
= 0; i
< jinfo
->num_clauses
; i
++) {
4010 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
4011 MonoClass
*catch_class
;
4013 if (! (ei
->try_offset
== region_start
&& ei
->try_offset
+ ei
->try_len
== region_end
) )
4016 catch_class
= ei
->data
.catch_class
;
4017 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class
))) {
4018 MonoGenericContext context
;
4019 MonoType
*inflated_type
;
4021 g_assert (rgctx
|| this_obj
);
4022 context
= mono_get_generic_context_from_stack_frame (jinfo
, rgctx
? rgctx
: this_obj
->vtable
);
4023 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
4024 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
4026 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
4027 mono_metadata_free_type (inflated_type
);
4030 // FIXME: Handle edge cases handled in get_exception_catch_class
4031 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (exc
, catch_class
, error
)) {
4032 index
= ei
->clause_index
;
4035 mono_error_assert_ok (error
);
4037 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
4038 g_assert_not_reached ();
4045 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4046 G_EXTERN_C _Unwind_Reason_Code
mono_debug_personality (int a
, _Unwind_Action b
,
4047 uint64_t c
, struct _Unwind_Exception
*d
, struct _Unwind_Context
*e
)
4049 g_assert_not_reached ();
4052 G_EXTERN_C
void mono_debug_personality (void);
4055 mono_debug_personality (void)
4057 g_assert_not_reached ();