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.
23 #ifdef HAVE_EXECINFO_H
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
31 #ifdef HAVE_SYS_WAIT_H
39 #ifdef HAVE_SYS_SYSCALL_H
40 #include <sys/syscall.h>
43 #ifdef HAVE_SYS_PRCTL_H
44 #include <sys/prctl.h>
51 #include <mono/metadata/appdomain.h>
52 #include <mono/metadata/tabledefs.h>
53 #include <mono/metadata/threads.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/exception.h>
57 #include <mono/metadata/exception-internals.h>
58 #include <mono/metadata/object-internals.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/metadata/debug-internals.h>
62 #include <mono/metadata/mono-debug.h>
63 #include <mono/metadata/profiler-private.h>
64 #include <mono/metadata/mono-endian.h>
65 #include <mono/metadata/environment.h>
66 #include <mono/metadata/mono-mlist.h>
67 #include <mono/utils/mono-merp.h>
68 #include <mono/utils/mono-mmap.h>
69 #include <mono/utils/mono-logger-internals.h>
70 #include <mono/utils/mono-error.h>
71 #include <mono/utils/mono-error-internals.h>
72 #include <mono/utils/mono-state.h>
73 #include <mono/utils/mono-threads-debug.h>
77 #include "debugger-agent.h"
78 #include "seq-points.h"
79 #include "llvm-runtime.h"
80 #include "mini-llvm.h"
81 #include "aot-runtime.h"
82 #include "mini-runtime.h"
83 #include "interp/interp.h"
86 #include "mini-llvm-cpp.h"
93 #ifndef MONO_ARCH_CONTEXT_DEF
94 #define MONO_ARCH_CONTEXT_DEF
102 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
103 * This structure represents one entry.
104 * This should consists of pointers only.
109 gpointer generic_info
;
110 /* Only for interpreter frames */
114 /* Number of words in trace_ips belonging to one entry */
115 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
117 static gpointer restore_context_func
, call_filter_func
;
118 static gpointer throw_exception_func
, rethrow_exception_func
, rethrow_preserve_exception_func
;
119 static gpointer throw_corlib_exception_func
;
121 static MonoFtnPtrEHCallback ftnptr_eh_callback
;
123 static void mono_walk_stack_full (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoLMF
*lmf
, MonoUnwindOptions unwind_options
, gpointer user_data
, gboolean crash_context
);
124 static void mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
);
125 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
);
126 static gboolean
mono_current_thread_has_handle_block_guard (void);
127 static gboolean
mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
);
128 static void mono_uninstall_current_handler_block_guard (void);
129 static gboolean
mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
);
130 static void throw_exception (MonoObject
*ex
, gboolean rethrow
);
132 static void mono_summarize_managed_stack (MonoThreadSummary
*out
);
133 static void mono_summarize_unmanaged_stack (MonoThreadSummary
*out
);
134 static void mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
);
135 static void mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
);
136 static void mono_crash_reporting_allow_all_native_libraries (void);
139 first_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer addr
)
141 gpointer
*data
= (gpointer
*)addr
;
147 // FIXME: Happens with llvm_only
152 *data
= frame
->frame_addr
;
158 mono_thread_get_managed_sp (void)
160 gpointer addr
= NULL
;
161 mono_walk_stack (first_managed
, MONO_UNWIND_SIGNAL_SAFE
, &addr
);
166 mini_clear_abort_threshold (void)
168 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
169 jit_tls
->abort_exc_stack_threshold
= NULL
;
173 mini_set_abort_threshold (StackFrameInfo
*frame
)
175 gpointer sp
= frame
->frame_addr
;
176 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
177 // Only move it up, to avoid thrown/caught
178 // exceptions lower in the stack from triggering
180 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
181 if (!jit_tls
->abort_exc_stack_threshold
|| above_threshold
) {
182 jit_tls
->abort_exc_stack_threshold
= sp
;
186 // Note: In the case that the frame is above where the thread abort
187 // was set we bump the threshold so that functions called from the new,
188 // higher threshold don't trigger the thread abort exception
190 mini_above_abort_threshold (void)
192 gpointer sp
= mono_thread_get_managed_sp ();
193 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
198 gboolean above_threshold
= (gsize
) sp
>= (gsize
) jit_tls
->abort_exc_stack_threshold
;
201 jit_tls
->abort_exc_stack_threshold
= sp
;
203 return above_threshold
;
207 mono_get_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
210 if (mono_find_prev_seq_point_for_native_offset (domain
, method
, native_offset
, NULL
, &sp
))
216 mono_exceptions_init (void)
218 MonoRuntimeExceptionHandlingCallbacks cbs
;
219 if (mono_ee_features
.use_aot_trampolines
) {
220 restore_context_func
= mono_aot_get_trampoline ("restore_context");
221 call_filter_func
= mono_aot_get_trampoline ("call_filter");
222 throw_exception_func
= mono_aot_get_trampoline ("throw_exception");
223 rethrow_exception_func
= mono_aot_get_trampoline ("rethrow_exception");
224 rethrow_preserve_exception_func
= mono_aot_get_trampoline ("rethrow_preserve_exception");
225 } else if (!mono_llvm_only
) {
228 restore_context_func
= mono_arch_get_restore_context (&info
, FALSE
);
229 mono_tramp_info_register (info
, NULL
);
230 call_filter_func
= mono_arch_get_call_filter (&info
, FALSE
);
231 mono_tramp_info_register (info
, NULL
);
232 throw_exception_func
= mono_arch_get_throw_exception (&info
, FALSE
);
233 mono_tramp_info_register (info
, NULL
);
234 rethrow_exception_func
= mono_arch_get_rethrow_exception (&info
, FALSE
);
235 mono_tramp_info_register (info
, NULL
);
236 rethrow_preserve_exception_func
= mono_arch_get_rethrow_preserve_exception (&info
, FALSE
);
237 mono_tramp_info_register (info
, NULL
);
240 mono_arch_exceptions_init ();
242 cbs
.mono_walk_stack_with_ctx
= mono_runtime_walk_stack_with_ctx
;
243 cbs
.mono_walk_stack_with_state
= mono_walk_stack_with_state
;
244 cbs
.mono_summarize_managed_stack
= mono_summarize_managed_stack
;
245 cbs
.mono_summarize_unmanaged_stack
= mono_summarize_unmanaged_stack
;
246 cbs
.mono_summarize_exception
= mono_summarize_exception
;
247 cbs
.mono_register_native_library
= mono_crash_reporting_register_native_library
;
248 cbs
.mono_allow_all_native_libraries
= mono_crash_reporting_allow_all_native_libraries
;
250 if (mono_llvm_only
) {
251 cbs
.mono_raise_exception
= mono_llvm_raise_exception
;
252 cbs
.mono_reraise_exception
= mono_llvm_reraise_exception
;
254 cbs
.mono_raise_exception
= (void (*)(MonoException
*))mono_get_throw_exception ();
255 cbs
.mono_reraise_exception
= (void (*)(MonoException
*))mono_get_rethrow_exception ();
257 cbs
.mono_raise_exception_with_ctx
= mono_raise_exception_with_ctx
;
258 cbs
.mono_exception_walk_trace
= mono_exception_walk_trace
;
259 cbs
.mono_install_handler_block_guard
= mono_install_handler_block_guard
;
260 cbs
.mono_uninstall_current_handler_block_guard
= mono_uninstall_current_handler_block_guard
;
261 cbs
.mono_current_thread_has_handle_block_guard
= mono_current_thread_has_handle_block_guard
;
262 cbs
.mono_clear_abort_threshold
= mini_clear_abort_threshold
;
263 cbs
.mono_above_abort_threshold
= mini_above_abort_threshold
;
264 mono_install_eh_callbacks (&cbs
);
265 mono_install_get_seq_point (mono_get_seq_point_for_native_offset
);
269 mono_get_throw_exception (void)
271 g_assert (throw_exception_func
);
272 return throw_exception_func
;
276 mono_get_rethrow_exception (void)
278 g_assert (rethrow_exception_func
);
279 return rethrow_exception_func
;
283 mono_get_rethrow_preserve_exception (void)
285 g_assert (rethrow_preserve_exception_func
);
286 return rethrow_preserve_exception_func
;
290 no_call_filter (void)
292 g_assert_not_reached ();
296 mono_get_call_filter (void)
298 /* This is called even in llvmonly mode etc. */
299 if (!call_filter_func
)
300 return (gpointer
)no_call_filter
;
301 return call_filter_func
;
305 mono_get_restore_context (void)
307 g_assert (restore_context_func
);
308 return restore_context_func
;
312 mono_get_throw_corlib_exception (void)
314 gpointer code
= NULL
;
317 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
318 if (throw_corlib_exception_func
)
319 return throw_corlib_exception_func
;
321 if (mono_ee_features
.use_aot_trampolines
)
322 code
= mono_aot_get_trampoline ("throw_corlib_exception");
324 code
= mono_arch_get_throw_corlib_exception (&info
, FALSE
);
325 mono_tramp_info_register (info
, NULL
);
328 mono_memory_barrier ();
330 throw_corlib_exception_func
= code
;
332 return throw_corlib_exception_func
;
336 * mono_get_throw_exception_addr:
338 * Return an address which stores the result of
339 * mono_get_throw_exception.
342 mono_get_throw_exception_addr (void)
344 return &throw_exception_func
;
348 mono_get_rethrow_preserve_exception_addr (void)
350 return &rethrow_preserve_exception_func
;
354 is_address_protected (MonoJitInfo
*ji
, MonoJitExceptionInfo
*ei
, gpointer ip
)
356 MonoTryBlockHoleTableJitInfo
*table
;
361 if (ei
->try_start
> ip
|| ip
>= ei
->try_end
)
364 if (!ji
->has_try_block_holes
)
367 table
= mono_jit_info_get_try_block_hole_table_info (ji
);
368 offset
= (guint32
)((char*)ip
- (char*)ji
->code_start
);
369 clause
= (guint16
)(ei
- ji
->clauses
);
370 g_assert (clause
< ji
->num_clauses
);
372 for (i
= 0; i
< table
->num_holes
; ++i
) {
373 MonoTryBlockHoleJitInfo
*hole
= &table
->holes
[i
];
374 if (hole
->clause
== clause
&& hole
->offset
<= offset
&& hole
->offset
+ hole
->length
> offset
)
380 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
383 static gboolean show_native_addresses
= TRUE
;
385 static gboolean show_native_addresses
= FALSE
;
388 static _Unwind_Reason_Code
389 build_stack_trace (struct _Unwind_Context
*frame_ctx
, void *state
)
391 MonoDomain
*domain
= mono_domain_get ();
392 uintptr_t ip
= _Unwind_GetIP (frame_ctx
);
394 if (show_native_addresses
|| mono_jit_info_table_find (domain
, (char*)ip
)) {
395 GList
**trace_ips
= (GList
**)state
;
396 *trace_ips
= g_list_prepend (*trace_ips
, (gpointer
)ip
);
399 return _URC_NO_REASON
;
403 get_unwind_backtrace (void)
407 _Unwind_Backtrace (build_stack_trace
, &ips
);
409 return g_slist_reverse (ips
);
415 get_unwind_backtrace (void)
423 arch_unwind_frame (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
424 MonoJitInfo
*ji
, MonoContext
*ctx
,
425 MonoContext
*new_ctx
, MonoLMF
**lmf
,
426 host_mgreg_t
**save_locations
,
427 StackFrameInfo
*frame
)
430 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
431 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
433 memset (frame
, 0, sizeof (StackFrameInfo
));
438 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
440 * This LMF entry is created by the soft debug code to mark transitions to
441 * managed code done during invokes.
443 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
444 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
445 } else if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT
|| ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
446 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED
;
447 frame
->interp_exit_data
= ext
->interp_exit_data
;
448 if (ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
) {
449 frame
->type
= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
450 memcpy (new_ctx
, &ext
->ctx
, sizeof (MonoContext
));
453 g_assert_not_reached ();
456 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~3);
462 return mono_arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
468 * Translate between the mono_arch_unwind_frame function and the old API.
471 find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
472 MonoContext
*new_ctx
, MonoLMF
**lmf
, gboolean
*managed
)
474 StackFrameInfo frame
;
477 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
479 /* Avoid costly table lookup during stack overflow */
480 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
483 ji
= mini_jit_info_table_find (domain
, ip
, NULL
);
488 err
= arch_unwind_frame (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, NULL
, &frame
);
490 return (MonoJitInfo
*)-1;
492 if (*lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
494 * Remove any unused lmf.
495 * Mask out the lower bits which might be used to hold additional information.
497 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
500 /* Convert between the new and the old APIs */
501 switch (frame
.type
) {
502 case FRAME_TYPE_MANAGED
:
506 case FRAME_TYPE_TRAMPOLINE
:
508 case FRAME_TYPE_MANAGED_TO_NATIVE
:
512 memset (res
, 0, sizeof (MonoJitInfo
));
513 res
->d
.method
= frame
.method
;
516 case FRAME_TYPE_DEBUGGER_INVOKE
: {
520 * The normal exception handling code can't handle this frame, so just
523 ji
= find_jit_info (domain
, jit_tls
, res
, NULL
, new_ctx
, &tmp_ctx
, lmf
, managed
);
524 memcpy (new_ctx
, &tmp_ctx
, sizeof (MonoContext
));
528 g_assert_not_reached ();
533 /* mono_find_jit_info:
535 * This function is used to gather information from @ctx. It return the
536 * MonoJitInfo of the corresponding function, unwinds one stack frame and
537 * stores the resulting context into @new_ctx. It also stores a string
538 * describing the stack location into @trace (if not NULL), and modifies
539 * the @lmf if necessary. @native_offset return the IP offset from the
540 * start of the function or -1 if that info is not available.
543 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
544 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
548 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
550 MonoMethod
*method
= NULL
;
561 ji
= find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
563 if (ji
== (gpointer
)-1)
566 if (ji
&& !ji
->is_trampoline
)
567 method
= jinfo_get_method (ji
);
569 if (managed2
|| (method
&& method
->wrapper_type
)) {
570 const char *real_ip
, *start
;
573 start
= (const char *)ji
->code_start
;
575 /* ctx->ip points into native code */
576 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
578 real_ip
= (const char*)ip
;
580 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
581 offset
= real_ip
- start
;
586 *native_offset
= offset
;
589 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
593 *trace
= mono_debug_print_stack_frame (method
, offset
, domain
);
596 char *fname
= mono_method_full_name (jinfo_get_method (res
), TRUE
);
597 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
606 * mono_find_jit_info_ext:
608 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
610 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
611 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
612 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
613 * to obtain the last managed frame.
614 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
615 * On return, it will be filled with the locations where callee saved registers are saved
616 * by the current frame. This is returned outside of StackFrameInfo because it can be
617 * quite large on some platforms.
618 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
622 mono_find_jit_info_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
623 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
624 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
625 host_mgreg_t
**save_locations
,
626 StackFrameInfo
*frame
)
629 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
631 MonoDomain
*target_domain
= domain
;
632 MonoMethod
*method
= NULL
;
633 gboolean async
= mono_thread_info_is_async_context ();
638 /* Avoid costly table lookup during stack overflow */
639 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
642 ji
= mini_jit_info_table_find_ext (domain
, ip
, TRUE
, &target_domain
);
645 target_domain
= domain
;
648 memset (save_locations
, 0, MONO_MAX_IREGS
* sizeof (host_mgreg_t
*));
650 err
= arch_unwind_frame (target_domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, save_locations
, frame
);
654 gboolean not_i2m
= frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED
&& frame
->type
!= FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
;
656 if (not_i2m
&& *lmf
&& ((*lmf
) != jit_tls
->first_lmf
) && ((gpointer
)MONO_CONTEXT_GET_SP (new_ctx
) >= (gpointer
)(*lmf
))) {
658 * Remove any unused lmf.
659 * Mask out the lower bits which might be used to hold additional information.
661 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~(TARGET_SIZEOF_VOID_P
-1));
664 if (frame
->ji
&& !frame
->ji
->is_trampoline
&& !frame
->ji
->async
)
665 method
= jinfo_get_method (frame
->ji
);
667 if (frame
->type
== FRAME_TYPE_MANAGED
&& method
) {
668 if (!method
->wrapper_type
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
669 frame
->managed
= TRUE
;
672 if (frame
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
) {
674 * This type of frame is just a marker, the caller should unwind once more to get the
675 * last managed frame.
678 frame
->method
= NULL
;
681 frame
->native_offset
= -1;
682 frame
->domain
= target_domain
;
683 frame
->async_context
= async
;
684 frame
->frame_addr
= MONO_CONTEXT_GET_SP (ctx
);
688 if (frame
->type
== FRAME_TYPE_MANAGED
)
689 frame
->method
= method
;
691 if (ji
&& (frame
->managed
|| (method
&& method
->wrapper_type
))) {
692 const char *real_ip
, *start
;
694 start
= (const char *)ji
->code_start
;
695 if (frame
->type
== FRAME_TYPE_MANAGED
)
696 real_ip
= (const char*)ip
;
698 /* ctx->ip points into native code */
699 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
701 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
702 frame
->native_offset
= real_ip
- start
;
704 frame
->native_offset
= -1;
708 *trace
= mono_debug_print_stack_frame (method
, frame
->native_offset
, domain
);
710 if (trace
&& frame
->method
) {
711 char *fname
= mono_method_full_name (frame
->method
, TRUE
);
712 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
722 MonoInterpStackIter interp_iter
;
723 gpointer last_frame_addr
;
727 unwinder_init (Unwinder
*unwinder
)
729 memset (unwinder
, 0, sizeof (Unwinder
));
732 #if defined(__GNUC__) && defined(TARGET_ARM64)
733 /* gcc 4.9.2 seems to miscompile this on arm64 */
734 static __attribute__((optimize("O0"))) gboolean
738 unwinder_unwind_frame (Unwinder
*unwinder
,
739 MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
740 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
741 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
742 host_mgreg_t
**save_locations
,
743 StackFrameInfo
*frame
)
746 if (unwinder
->in_interp
) {
747 memcpy (new_ctx
, ctx
, sizeof (MonoContext
));
749 /* Process debugger invokes */
750 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
751 if (unwinder
->last_frame_addr
< (gpointer
)(*lmf
)) {
752 if (((gsize
)(*lmf
)->previous_lmf
) & 2) {
753 MonoLMFExt
*ext
= (MonoLMFExt
*)(*lmf
);
754 if (ext
->kind
== MONO_LMFEXT_DEBUGGER_INVOKE
) {
755 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~7);
756 frame
->type
= FRAME_TYPE_DEBUGGER_INVOKE
;
762 unwinder
->in_interp
= mini_get_interp_callbacks ()->frame_iter_next (&unwinder
->interp_iter
, frame
);
763 if (frame
->type
== FRAME_TYPE_INTERP
) {
764 parent
= mini_get_interp_callbacks ()->frame_get_parent (frame
->interp_frame
);
765 unwinder
->last_frame_addr
= parent
;
767 if (!unwinder
->in_interp
)
768 return unwinder_unwind_frame (unwinder
, domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
, save_locations
, frame
);
771 gboolean res
= mono_find_jit_info_ext (domain
, jit_tls
, prev_ji
, ctx
, new_ctx
, trace
, lmf
,
772 save_locations
, frame
);
775 if (frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
) {
776 unwinder
->in_interp
= TRUE
;
777 mini_get_interp_callbacks ()->frame_iter_init (&unwinder
->interp_iter
, frame
->interp_exit_data
);
779 unwinder
->last_frame_addr
= frame
->frame_addr
;
785 * This function is async-safe.
788 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
790 MonoGenericJitInfo
*gi
;
794 if (!ji
->has_generic_jit_info
)
796 gi
= mono_jit_info_get_generic_jit_info (ji
);
802 * Search location list if available, it contains the precise location of the
803 * argument for every pc offset, even if the method was interrupted while it was in
807 int offset
= (gsize
)MONO_CONTEXT_GET_IP (ctx
) - (gsize
)ji
->code_start
;
810 for (i
= 0; i
< gi
->nlocs
; ++i
) {
811 MonoDwarfLocListEntry
*entry
= &gi
->locations
[i
];
813 if (offset
>= entry
->from
&& (offset
< entry
->to
|| entry
->to
== 0)) {
815 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, entry
->reg
);
817 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, entry
->reg
) + entry
->offset
);
821 g_assert (i
< gi
->nlocs
);
824 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
826 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
830 method
= jinfo_get_method (ji
);
831 if (mono_method_get_context (method
)->method_inst
) {
832 /* A MonoMethodRuntimeGenericContext* */
834 } else if ((method
->flags
& METHOD_ATTRIBUTE_STATIC
) || m_class_is_valuetype (method
->klass
)) {
838 /* Avoid returning a managed object */
839 MonoObject
*this_obj
= (MonoObject
*)info
;
841 return this_obj
->vtable
;
846 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
848 static MonoGenericContext
849 get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
851 MonoGenericContext context
= { NULL
, NULL
};
852 MonoClass
*klass
, *method_container_class
;
855 g_assert (generic_info
);
857 method
= jinfo_get_method (ji
);
858 g_assert (method
->is_inflated
);
859 if (mono_method_get_context (method
)->method_inst
) {
860 MonoMethodRuntimeGenericContext
*mrgctx
= (MonoMethodRuntimeGenericContext
*)generic_info
;
862 klass
= mrgctx
->class_vtable
->klass
;
863 context
.method_inst
= mrgctx
->method_inst
;
864 g_assert (context
.method_inst
);
866 MonoVTable
*vtable
= (MonoVTable
*)generic_info
;
868 klass
= vtable
->klass
;
871 //g_assert (!mono_class_is_gtd (method->klass));
872 if (mono_class_is_ginst (method
->klass
))
873 method_container_class
= mono_class_get_generic_class (method
->klass
)->container_class
;
875 method_container_class
= method
->klass
;
877 /* class might refer to a subclass of method's class */
878 while (!(klass
== method
->klass
|| (mono_class_is_ginst (klass
) && mono_class_get_generic_class (klass
)->container_class
== method_container_class
))) {
879 klass
= m_class_get_parent (klass
);
883 if (mono_class_is_ginst (klass
) || mono_class_is_gtd (klass
))
884 context
.class_inst
= mini_class_get_context (klass
)->class_inst
;
886 if (mono_class_is_ginst (klass
))
887 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass
)->container_class
, method_container_class
));
889 g_assert (mono_class_has_parent_and_ignore_generics (klass
, method_container_class
));
895 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
898 MonoGenericContext context
;
901 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
902 return jinfo_get_method (ji
);
903 context
= get_generic_context_from_stack_frame (ji
, generic_info
);
905 method
= jinfo_get_method (ji
);
906 method
= mono_method_get_declaring_generic_method (method
);
907 method
= mono_class_inflate_generic_method_checked (method
, &context
, error
);
908 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
914 * mono_exception_walk_native_trace:
915 * \param ex The exception object whose frames should be walked
916 * \param func callback to call for each stack frame
917 * \param user_data data passed to the callback
918 * This function walks the stacktrace of an exception. For
919 * each frame the callback function is called with the relevant info.
920 * The walk ends when no more stack frames are found or when the callback
921 * returns a TRUE value.
925 mono_exception_walk_trace (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
929 MONO_ENTER_GC_UNSAFE
;
930 res
= mono_exception_walk_trace_internal (ex
, func
, user_data
);
936 mono_exception_stackframe_obj_walk (MonoStackFrame
*captured_frame
, MonoExceptionFrameWalk func
, gpointer user_data
)
941 gpointer ip
= (gpointer
) (captured_frame
->method_address
+ captured_frame
->native_offset
);
942 MonoJitInfo
*ji
= mono_jit_info_table_find_internal (mono_domain_get (), ip
, TRUE
, TRUE
);
944 // Other domain maybe?
947 MonoMethod
*method
= jinfo_get_method (ji
);
949 gboolean r
= func (method
, (gpointer
) captured_frame
->method_address
, captured_frame
->native_offset
, TRUE
, user_data
);
957 mono_exception_stacktrace_obj_walk (MonoStackTrace
*st
, MonoExceptionFrameWalk func
, gpointer user_data
)
959 int num_captured
= st
->captured_traces
? mono_array_length_internal (st
->captured_traces
) : 0;
960 for (int i
=0; i
< num_captured
; i
++) {
961 MonoStackTrace
*curr_trace
= mono_array_get_fast (st
->captured_traces
, MonoStackTrace
*, i
);
962 mono_exception_stacktrace_obj_walk (curr_trace
, func
, user_data
);
965 int num_frames
= st
->frames
? mono_array_length_internal (st
->frames
) : 0;
966 for (int frame
= 0; frame
< num_frames
; frame
++) {
967 gboolean r
= mono_exception_stackframe_obj_walk (mono_array_get_fast (st
->frames
, MonoStackFrame
*, frame
), func
, user_data
);
976 mono_exception_walk_trace_internal (MonoException
*ex
, MonoExceptionFrameWalk func
, gpointer user_data
)
978 MONO_REQ_GC_UNSAFE_MODE
;
980 MonoDomain
*domain
= mono_domain_get ();
981 MonoArray
*ta
= ex
->trace_ips
;
983 /* Exception is not thrown yet */
987 int len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
988 gboolean otherwise_has_traces
= len
> 0;
990 for (int i
= 0; i
< len
; i
++) {
991 ExceptionTraceIp trace_ip
;
993 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
994 gpointer ip
= trace_ip
.ip
;
995 gpointer generic_info
= trace_ip
.generic_info
;
997 MonoJitInfo
*ji
= NULL
;
1001 ji
= mono_jit_info_table_find (domain
, ip
);
1007 r
= func (NULL
, ip
, 0, FALSE
, user_data
);
1012 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
1013 if (func (method
, ji
->code_start
, (char *) ip
- (char *) ji
->code_start
, TRUE
, user_data
))
1018 ta
= (MonoArray
*) ex
->captured_traces
;
1019 len
= ta
? mono_array_length_internal (ta
) : 0;
1020 gboolean captured_has_traces
= len
> 0;
1022 for (int i
= 0; i
< len
; i
++) {
1023 MonoStackTrace
*captured_trace
= mono_array_get_fast (ta
, MonoStackTrace
*, i
);
1024 if (!captured_trace
)
1027 mono_exception_stacktrace_obj_walk (captured_trace
, func
, user_data
);
1030 return captured_has_traces
|| otherwise_has_traces
;
1034 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
1037 MonoDomain
*domain
= mono_domain_get ();
1039 MonoArray
*ta
= exc
->trace_ips
;
1040 MonoDebugSourceLocation
*location
;
1044 /* Exception is not thrown yet */
1045 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, 0, error
);
1046 mono_error_set_pending_exception (error
);
1050 len
= mono_array_length_internal (ta
) / TRACE_IP_ENTRY_SIZE
;
1052 res
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0, error
);
1053 if (mono_error_set_pending_exception (error
))
1056 for (i
= skip
; i
< len
; i
++) {
1058 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
1059 if (!is_ok (error
)) {
1060 mono_error_set_pending_exception (error
);
1063 ExceptionTraceIp trace_ip
;
1064 memcpy (&trace_ip
, mono_array_addr_fast (ta
, ExceptionTraceIp
, i
), sizeof (ExceptionTraceIp
));
1065 gpointer ip
= trace_ip
.ip
;
1066 gpointer generic_info
= trace_ip
.generic_info
;
1072 ji
= mono_jit_info_table_find (domain
, ip
);
1074 /* Unmanaged frame */
1075 mono_array_setref_internal (res
, i
, sf
);
1080 g_assert (ji
!= NULL
);
1082 if (mono_llvm_only
|| !generic_info
)
1083 /* Can't resolve actual method */
1084 method
= jinfo_get_method (ji
);
1086 method
= get_method_from_stack_frame (ji
, generic_info
);
1087 if (jinfo_get_method (ji
)->wrapper_type
) {
1091 s
= mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_REFLECTION
);
1092 MonoString
*name
= mono_string_new_checked (domain
, s
, error
);
1094 if (!is_ok (error
)) {
1095 mono_error_set_pending_exception (error
);
1098 MONO_OBJECT_SETREF_INTERNAL (sf
, internal_method_name
, name
);
1101 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
1102 if (!is_ok (error
)) {
1103 mono_error_set_pending_exception (error
);
1106 MONO_OBJECT_SETREF_INTERNAL (sf
, method
, rm
);
1109 sf
->method_index
= ji
->from_aot
? mono_aot_find_method_index (method
) : 0xffffff;
1110 sf
->method_address
= (gsize
) ji
->code_start
;
1111 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
1114 * mono_debug_lookup_source_location() returns both the file / line number information
1115 * and the IL offset. Note that computing the IL offset is already an expensive
1116 * operation, so we shouldn't call this method twice.
1118 location
= mono_debug_lookup_source_location (jinfo_get_method (ji
), sf
->native_offset
, domain
);
1120 sf
->il_offset
= location
->il_offset
;
1123 if (mono_find_prev_seq_point_for_native_offset (domain
, jinfo_get_method (ji
), sf
->native_offset
, NULL
, &sp
))
1124 sf
->il_offset
= sp
.il_offset
;
1129 if (need_file_info
) {
1130 if (location
&& location
->source_file
) {
1131 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1132 if (!is_ok (error
)) {
1133 mono_error_set_pending_exception (error
);
1136 MONO_OBJECT_SETREF_INTERNAL (sf
, filename
, filename
);
1137 sf
->line
= location
->row
;
1138 sf
->column
= location
->column
;
1140 sf
->line
= sf
->column
= 0;
1141 sf
->filename
= NULL
;
1145 mono_debug_free_source_location (location
);
1146 mono_array_setref_internal (res
, i
- skip
, sf
);
1153 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1156 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1157 if (jit_tls
&& jit_tls
->orig_ex_ctx_set
)
1158 start_ctx
= &jit_tls
->orig_ex_ctx
;
1160 mono_walk_stack_with_ctx (func
, start_ctx
, unwind_options
, user_data
);
1163 * mono_walk_stack_with_ctx:
1164 * Unwind the current thread starting at \p start_ctx.
1165 * If \p start_ctx is null, we capture the current context.
1168 mono_walk_stack_with_ctx (MonoJitStackWalk func
, MonoContext
*start_ctx
, MonoUnwindOptions unwind_options
, void *user_data
)
1170 MonoContext extra_ctx
;
1171 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1172 MONO_ARCH_CONTEXT_DEF
1174 if (!thread
|| !thread
->jit_data
)
1178 mono_arch_flush_register_windows ();
1179 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx
, mono_walk_stack_with_ctx
);
1180 start_ctx
= &extra_ctx
;
1183 mono_walk_stack_full (func
, start_ctx
, mono_domain_get (), thread
->jit_data
, mono_get_lmf (), unwind_options
, user_data
, FALSE
);
1187 * mono_walk_stack_with_state:
1188 * Unwind a thread described by \p state.
1190 * State must be valid (state->valid == TRUE).
1192 * If you are using this function to unwind another thread, make sure it is suspended.
1194 * If \p state is null, we capture the current context.
1197 mono_walk_stack_with_state (MonoJitStackWalk func
, MonoThreadUnwindState
*state
, MonoUnwindOptions unwind_options
, void *user_data
)
1199 MonoThreadUnwindState extra_state
;
1201 g_assert (!mono_thread_info_is_async_context ());
1202 if (!mono_thread_state_init_from_current (&extra_state
))
1204 state
= &extra_state
;
1207 g_assert (state
->valid
);
1209 if (!state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
])
1213 mono_walk_stack_full (func
,
1215 (MonoDomain
*)state
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
],
1216 (MonoJitTlsData
*)state
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
],
1217 (MonoLMF
*)state
->unwind_data
[MONO_UNWIND_DATA_LMF
],
1218 unwind_options
, user_data
, FALSE
);
1222 mono_walk_stack (MonoJitStackWalk func
, MonoUnwindOptions options
, void *user_data
)
1224 MonoThreadUnwindState state
;
1225 if (!mono_thread_state_init_from_current (&state
))
1227 mono_walk_stack_with_state (func
, &state
, options
, user_data
);
1231 * mono_walk_stack_full:
1232 * \param func callback to call for each stack frame
1233 * \param domain starting appdomain, can be NULL to use the current domain
1234 * \param unwind_options what extra information the unwinder should gather
1235 * \param start_ctx starting state of the stack walk, can be NULL.
1236 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1237 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1238 * \param user_data data passed to the callback
1239 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1240 * This function walks the stack of a thread, starting from the state
1241 * represented by \p start_ctx. For each frame the callback
1242 * function is called with the relevant info. The walk ends when no more
1243 * managed stack frames are found or when the callback returns a TRUE value.
1246 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
)
1249 MonoContext ctx
, new_ctx
;
1250 StackFrameInfo frame
;
1252 host_mgreg_t
*reg_locations
[MONO_MAX_IREGS
];
1253 host_mgreg_t
*new_reg_locations
[MONO_MAX_IREGS
];
1254 gboolean get_reg_locations
= unwind_options
& MONO_UNWIND_REG_LOCATIONS
;
1255 gboolean async
= mono_thread_info_is_async_context ();
1258 memset (&frame
, 0, sizeof (StackFrameInfo
));
1261 if (mono_llvm_only
) {
1267 ips
= get_unwind_backtrace ();
1268 for (l
= ips
; l
; l
= l
->next
) {
1269 guint8
*ip
= (guint8
*)l
->data
;
1270 memset (&frame
, 0, sizeof (StackFrameInfo
));
1271 frame
.ji
= mini_jit_info_table_find (domain
, ip
, &frame
.domain
);
1272 if (!frame
.ji
|| frame
.ji
->is_trampoline
)
1274 frame
.type
= FRAME_TYPE_MANAGED
;
1275 frame
.method
= jinfo_get_method (frame
.ji
);
1276 // FIXME: Cannot lookup the actual method
1277 frame
.actual_method
= frame
.method
;
1278 if (frame
.type
== FRAME_TYPE_MANAGED
) {
1279 if (!frame
.method
->wrapper_type
|| frame
.method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1280 frame
.managed
= TRUE
;
1282 frame
.native_offset
= ip
- (guint8
*)frame
.ji
->code_start
;
1283 frame
.il_offset
= -1;
1285 if (func (&frame
, NULL
, user_data
))
1294 g_warning ("start_ctx required for stack walk");
1299 g_warning ("domain required for stack walk");
1304 g_warning ("jit_tls required for stack walk");
1308 /*The LMF will be null if the target have no managed frames.*/
1309 /* g_assert (lmf); */
1310 if (async
&& (unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
)) {
1311 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1315 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
1316 memset (reg_locations
, 0, sizeof (reg_locations
));
1318 unwinder_init (&unwinder
);
1320 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
1322 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, get_reg_locations
? new_reg_locations
: NULL
, &frame
);
1326 if (frame
.type
== FRAME_TYPE_TRAMPOLINE
)
1329 if ((unwind_options
& MONO_UNWIND_LOOKUP_IL_OFFSET
) && frame
.ji
) {
1330 MonoDebugSourceLocation
*source
= NULL
;
1332 // Don't do this when we can be in a signal handler
1334 source
= mono_debug_lookup_source_location (jinfo_get_method (frame
.ji
), frame
.native_offset
, domain
);
1336 il_offset
= source
->il_offset
;
1338 MonoSeqPointInfo
*seq_points
= NULL
;
1340 // It's more reliable to look into the global cache if possible
1342 seq_points
= (MonoSeqPointInfo
*) frame
.ji
->seq_points
;
1344 seq_points
= mono_get_seq_points (domain
, jinfo_get_method (frame
.ji
));
1347 if (seq_points
&& mono_seq_point_find_prev_by_native_offset (seq_points
, frame
.native_offset
, &sp
))
1348 il_offset
= sp
.il_offset
;
1352 mono_debug_free_source_location (source
);
1356 frame
.il_offset
= il_offset
;
1358 if ((unwind_options
& MONO_UNWIND_LOOKUP_ACTUAL_METHOD
) && frame
.ji
) {
1359 frame
.actual_method
= get_method_from_stack_frame (frame
.ji
, get_generic_info_from_stack_frame (frame
.ji
, &ctx
));
1361 frame
.actual_method
= frame
.method
;
1364 if (get_reg_locations
)
1365 frame
.reg_locations
= reg_locations
;
1367 if (func (&frame
, &ctx
, user_data
))
1371 if (get_reg_locations
) {
1372 for (int i
= 0; i
< MONO_MAX_IREGS
; ++i
)
1373 if (new_reg_locations
[i
])
1374 reg_locations
[i
] = new_reg_locations
[i
];
1381 #ifdef DISABLE_CRASH_REPORTING
1384 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1390 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1396 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1402 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1408 mono_crash_reporting_allow_all_native_libraries ()
1417 MonoFrameSummary
*frames
;
1420 MonoStackHash
*hashes
;
1422 } MonoSummarizeUserData
;
1425 copy_summary_string_safe (char *in
, const char *out
)
1427 for (int i
=0; i
< MONO_MAX_SUMMARY_NAME_LEN
; i
++) {
1429 if (out
[i
] == '\0')
1434 in
[MONO_MAX_SUMMARY_NAME_LEN
] = '\0';
1440 char *exported_name
;
1441 } MonoLibWhitelistEntry
;
1443 static GList
*native_library_whitelist
;
1444 static gboolean allow_all_native_libraries
= FALSE
;
1447 mono_crash_reporting_register_native_library (const char *module_path
, const char *module_name
)
1449 // Examples: libsystem_pthread.dylib -> "pthread"
1450 // Examples: libsystem_platform.dylib -> "platform"
1451 // Examples: mono-sgen -> "mono" from above line
1452 MonoLibWhitelistEntry
*entry
= g_new0 (MonoLibWhitelistEntry
, 1);
1453 entry
->suffix
= g_strdup (module_path
);
1454 entry
->exported_name
= g_strdup (module_name
);
1455 native_library_whitelist
= g_list_append (native_library_whitelist
, entry
);
1459 mono_crash_reporting_allow_all_native_libraries ()
1461 allow_all_native_libraries
= TRUE
;
1465 check_whitelisted_module (const char *in_name
, const char **out_module
)
1467 #ifndef MONO_PRIVATE_CRASHES
1470 if (allow_all_native_libraries
) {
1472 *out_module
= "<external module>";
1475 if (g_str_has_suffix (in_name
, "mono-sgen")) {
1477 *out_module
= "mono";
1481 for (GList
*cursor
= native_library_whitelist
; cursor
; cursor
= cursor
->next
) {
1482 MonoLibWhitelistEntry
*iter
= (MonoLibWhitelistEntry
*) cursor
->data
;
1483 if (!g_str_has_suffix (in_name
, iter
->suffix
))
1486 *out_module
= iter
->exported_name
;
1495 mono_make_portable_ip (intptr_t in_ip
, intptr_t module_base
)
1497 // FIXME: Make generalize away from llvm tools?
1498 // So lldb starts the pointer base at 0x100000000
1499 // and expects to get pointers as (offset + constant)
1502 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1503 // *CoreSymbolicationDT.framework version: 63750*/
1504 intptr_t offset
= in_ip
- module_base
;
1505 intptr_t magic_value
= offset
+ 0x100000000;
1510 mono_get_portable_ip (intptr_t in_ip
, intptr_t *out_ip
, gint32
*out_offset
, const char **out_module
, char *out_name
)
1512 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1513 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1514 // non-recursive lock twice on this thread, and will deadlock.
1516 gboolean success
= dladdr ((void*)in_ip
, &info
);
1520 if (!check_whitelisted_module (info
.dli_fname
, out_module
))
1523 *out_ip
= mono_make_portable_ip ((intptr_t) info
.dli_saddr
, (intptr_t) info
.dli_fbase
);
1524 *out_offset
= in_ip
- (intptr_t) info
.dli_saddr
;
1526 #ifndef MONO_PRIVATE_CRASHES
1527 if (info
.dli_saddr
&& out_name
)
1528 copy_summary_string_safe (out_name
, info
.dli_sname
);
1534 summarize_offset_free_hash (guint64 accum
, MonoFrameSummary
*frame
)
1536 if (!frame
->is_managed
)
1539 // See: mono_ptrarray_hash
1540 guint64 hash_accum
= accum
;
1542 // The assembly and the method token, no offsets
1543 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1544 hash_accum
+= frame
->managed_data
.token
;
1550 summarize_offset_rich_hash (guint64 accum
, MonoFrameSummary
*frame
)
1552 // See: mono_ptrarray_hash
1553 guint64 hash_accum
= accum
;
1555 if (!frame
->is_managed
) {
1556 hash_accum
+= frame
->unmanaged_data
.ip
;
1558 hash_accum
+= mono_metadata_str_hash (frame
->str_descr
);
1559 hash_accum
+= frame
->managed_data
.token
;
1560 hash_accum
+= frame
->managed_data
.il_offset
;
1567 summarize_frame_internal (MonoMethod
*method
, gpointer ip
, size_t native_offset
, int il_offset
, gboolean managed
, gpointer user_data
)
1569 MonoSummarizeUserData
*ud
= (MonoSummarizeUserData
*) user_data
;
1571 gboolean valid_state
= ud
->num_frames
+ 1 < ud
->max_frames
;
1573 ud
->error
= "Exceeded the maximum number of frames";
1577 MonoFrameSummary
*dest
= &ud
->frames
[ud
->num_frames
];
1579 dest
->unmanaged_data
.ip
= (intptr_t) ip
;
1580 dest
->is_managed
= managed
;
1582 if (!managed
&& method
&& method
->wrapper_type
!= MONO_WRAPPER_NONE
&& method
->wrapper_type
< MONO_WRAPPER_NUM
) {
1583 dest
->is_managed
= FALSE
;
1584 dest
->unmanaged_data
.has_name
= TRUE
;
1585 copy_summary_string_safe (dest
->str_descr
, mono_wrapper_type_to_str (method
->wrapper_type
));
1588 #ifndef MONO_PRIVATE_CRASHES
1590 dest
->managed_data
.name
= (char *) method
->name
;
1595 ud
->error
= "Managed method frame, but no provided managed method";
1599 MonoImage
*image
= mono_class_get_image (method
->klass
);
1600 // Used for hashing, more stable across rebuilds than using GUID
1601 copy_summary_string_safe (dest
->str_descr
, image
->assembly_name
);
1603 dest
->managed_data
.guid
= image
->guid
;
1605 dest
->managed_data
.native_offset
= native_offset
;
1606 dest
->managed_data
.token
= method
->token
;
1607 dest
->managed_data
.il_offset
= il_offset
;
1609 dest
->managed_data
.filename
= image
->module_name
;
1611 MonoDotNetHeader
*header
= &image
->image_info
->cli_header
;
1612 dest
->managed_data
.image_size
= header
->nt
.pe_image_size
;
1614 dest
->managed_data
.time_date_stamp
= image
->time_date_stamp
;
1617 dest
->managed_data
.token
= -1;
1621 ud
->hashes
->offset_free_hash
= summarize_offset_free_hash (ud
->hashes
->offset_free_hash
, dest
);
1622 ud
->hashes
->offset_rich_hash
= summarize_offset_rich_hash (ud
->hashes
->offset_rich_hash
, dest
);
1624 // We return FALSE, so we're continuing walking
1625 // And we increment the pointer because we're done with this cell in the array
1631 summarize_frame_managed_walk (MonoMethod
*method
, gpointer ip
, size_t frame_native_offset
, gboolean managed
, gpointer user_data
)
1635 if (managed
&& method
) {
1636 MonoDebugSourceLocation
*location
= mono_debug_lookup_source_location (method
, frame_native_offset
, mono_domain_get ());
1638 il_offset
= location
->il_offset
;
1639 mono_debug_free_source_location (location
);
1643 intptr_t portable_ip
= 0;
1645 mono_get_portable_ip ((intptr_t) ip
, &portable_ip
, &offset
, NULL
, NULL
);
1647 return summarize_frame_internal (method
, (gpointer
) portable_ip
, frame_native_offset
, il_offset
, managed
, user_data
);
1652 summarize_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
1654 // Don't record trampolines between managed frames
1655 if (frame
->ji
&& frame
->ji
->is_trampoline
)
1658 if (frame
->ji
&& (frame
->ji
->is_trampoline
|| frame
->ji
->async
))
1659 return FALSE
; // Keep unwinding
1663 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx
), &ip
, &offset
, NULL
, NULL
);
1664 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1666 gboolean is_managed
= (frame
->type
== FRAME_TYPE_MANAGED
|| frame
->type
== FRAME_TYPE_INTERP
);
1667 MonoMethod
*method
= NULL
;
1668 if (frame
&& frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
1669 method
= jinfo_get_method (frame
->ji
);
1672 method
= jinfo_get_method (frame
->ji
);
1674 return summarize_frame_internal (method
, (gpointer
) ip
, offset
, frame
->il_offset
, is_managed
, data
);
1678 mono_summarize_exception (MonoException
*exc
, MonoThreadSummary
*out
)
1680 memset (out
, 0, sizeof (MonoThreadSummary
));
1682 MonoException
*inner_exc
= exc
;
1685 for (exc_index
= 0; exc_index
< MONO_MAX_SUMMARY_EXCEPTIONS
; exc_index
++) {
1686 if (inner_exc
== NULL
)
1689 // Set up state to walk this MonoException's stack
1690 MonoSummarizeUserData data
;
1691 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1692 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1693 data
.num_frames
= 0;
1694 data
.frames
= out
->exceptions
[exc_index
].managed_frames
;
1696 // Accumulate all hashes from all exceptions in traveral order
1697 data
.hashes
= &out
->hashes
;
1699 mono_exception_walk_trace (inner_exc
, summarize_frame_managed_walk
, &data
);
1701 // Save per-MonoException info
1702 out
->exceptions
[exc_index
].managed_exc_type
= inner_exc
->object
.vtable
->klass
;
1703 out
->exceptions
[exc_index
].num_managed_frames
= data
.num_frames
;
1705 // Continue to traverse nesting of exceptions
1706 inner_exc
= (MonoException
*) inner_exc
->inner_ex
;
1709 out
->num_exceptions
= exc_index
;
1714 mono_summarize_managed_stack (MonoThreadSummary
*out
)
1716 MonoSummarizeUserData data
;
1717 memset (&data
, 0, sizeof (MonoSummarizeUserData
));
1718 data
.max_frames
= MONO_MAX_SUMMARY_FRAMES
;
1719 data
.num_frames
= 0;
1720 data
.frames
= out
->managed_frames
;
1721 data
.hashes
= &out
->hashes
;
1723 // FIXME: collect stack pointer for both and sort frames by SP
1724 // so people can see relative ordering of both managed and unmanaged frames.
1727 // Summarize managed stack
1729 mono_walk_stack_full (summarize_frame
, out
->ctx
, out
->domain
, out
->jit_tls
, out
->lmf
, MONO_UNWIND_LOOKUP_IL_OFFSET
, &data
, TRUE
);
1730 out
->num_managed_frames
= data
.num_frames
;
1732 if (data
.error
!= NULL
)
1733 out
->error_msg
= data
.error
;
1734 out
->is_managed
= (out
->num_managed_frames
!= 0);
1737 // Always runs on the dumped thread
1739 mono_summarize_unmanaged_stack (MonoThreadSummary
*out
)
1741 MONO_ARCH_CONTEXT_DEF
1743 // Summarize unmanaged stack
1745 #ifdef HAVE_BACKTRACE_SYMBOLS
1746 intptr_t frame_ips
[MONO_MAX_SUMMARY_FRAMES
];
1748 out
->num_unmanaged_frames
= backtrace ((void **)frame_ips
, MONO_MAX_SUMMARY_FRAMES
);
1750 for (int i
=0; i
< out
->num_unmanaged_frames
; ++i
) {
1751 intptr_t ip
= frame_ips
[i
];
1752 MonoFrameSummary
*frame
= &out
->unmanaged_frames
[i
];
1754 int success
= mono_get_portable_ip (ip
, &frame
->unmanaged_data
.ip
, &frame
->unmanaged_data
.offset
, &frame
->unmanaged_data
.module
, (char *) frame
->str_descr
);
1758 if (out
->unmanaged_frames
[i
].str_descr
[0] != '\0')
1759 out
->unmanaged_frames
[i
].unmanaged_data
.has_name
= TRUE
;
1763 out
->lmf
= mono_get_lmf ();
1765 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
1766 out
->info_addr
= (intptr_t) thread
;
1767 out
->jit_tls
= thread
->jit_data
;
1768 out
->domain
= mono_domain_get ();
1771 out
->ctx
= &out
->ctx_mem
;
1772 mono_arch_flush_register_windows ();
1773 MONO_INIT_CONTEXT_FROM_FUNC (out
->ctx
, mono_summarize_unmanaged_stack
);
1782 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
1783 MonoReflectionMethod
**method
,
1784 gint32
*iloffset
, gint32
*native_offset
,
1785 MonoString
**file
, gint32
*line
, gint32
*column
)
1788 MonoDomain
*domain
= mono_domain_get ();
1789 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
1790 MonoLMF
*lmf
= mono_get_lmf ();
1791 MonoJitInfo
*ji
= NULL
;
1792 MonoContext ctx
, new_ctx
;
1793 MonoDebugSourceLocation
*location
;
1794 MonoMethod
*jmethod
= NULL
, *actual_method
;
1795 StackFrameInfo frame
;
1800 MONO_ARCH_CONTEXT_DEF
;
1802 g_assert (skip
>= 0);
1804 if (mono_llvm_only
) {
1806 MonoDomain
*frame_domain
;
1807 guint8
*frame_ip
= NULL
;
1809 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1811 ips
= get_unwind_backtrace ();
1812 for (l
= ips
; l
&& skip
>= 0; l
= l
->next
) {
1813 guint8
*ip
= (guint8
*)l
->data
;
1817 ji
= mini_jit_info_table_find (mono_domain_get (), ip
, &frame_domain
);
1818 if (!ji
|| ji
->is_trampoline
)
1821 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1822 jmethod
= jinfo_get_method (ji
);
1823 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1830 /* No way to resolve generic instances */
1831 actual_method
= jmethod
;
1832 *native_offset
= frame_ip
- (guint8
*)ji
->code_start
;
1834 mono_arch_flush_register_windows ();
1835 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
1837 unwinder_init (&unwinder
);
1842 res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
1845 switch (frame
.type
) {
1846 case FRAME_TYPE_MANAGED_TO_NATIVE
:
1847 case FRAME_TYPE_DEBUGGER_INVOKE
:
1848 case FRAME_TYPE_TRAMPOLINE
:
1849 case FRAME_TYPE_INTERP_TO_MANAGED
:
1850 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
1852 case FRAME_TYPE_INTERP
:
1853 case FRAME_TYPE_MANAGED
:
1855 *native_offset
= frame
.native_offset
;
1857 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1858 jmethod
= jinfo_get_method (ji
);
1859 if (jmethod
->wrapper_type
!= MONO_WRAPPER_NONE
&& jmethod
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& jmethod
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
)
1864 g_assert_not_reached ();
1866 } while (skip
>= 0);
1868 if (frame
.type
== FRAME_TYPE_INTERP
) {
1869 jmethod
= frame
.method
;
1870 actual_method
= frame
.actual_method
;
1872 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &ctx
));
1876 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, actual_method
, NULL
, error
);
1877 if (!is_ok (error
)) {
1878 mono_error_set_pending_exception (error
);
1881 mono_gc_wbarrier_generic_store_internal (method
, (MonoObject
*) rm
);
1883 if (il_offset
!= -1) {
1884 location
= mono_debug_lookup_source_location_by_il (jmethod
, il_offset
, domain
);
1886 location
= mono_debug_lookup_source_location (jmethod
, *native_offset
, domain
);
1889 *iloffset
= location
->il_offset
;
1893 if (need_file_info
) {
1895 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
1896 if (!is_ok (error
)) {
1897 mono_error_set_pending_exception (error
);
1900 mono_gc_wbarrier_generic_store_internal (file
, (MonoObject
*)filename
);
1901 *line
= location
->row
;
1902 *column
= location
->column
;
1905 *line
= *column
= 0;
1909 mono_debug_free_source_location (location
);
1915 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
1918 MonoClass
*catch_class
= ei
->data
.catch_class
;
1919 MonoType
*inflated_type
;
1920 MonoGenericContext context
;
1922 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1923 if (!catch_class
|| ei
->flags
!= MONO_EXCEPTION_CLAUSE_NONE
)
1926 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
1928 context
= get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
1930 /* FIXME: we shouldn't inflate but instead put the
1931 type in the rgctx and fetch it from there. It
1932 might be a good idea to do this lazily, i.e. only
1933 when the exception is actually thrown, so as not to
1934 waste space for exception clauses which might never
1936 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
1937 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
1939 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
1940 mono_metadata_free_type (inflated_type
);
1946 * mini_jit_info_table_find_ext:
1948 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1949 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1950 * OUT_DOMAIN if it is not NULL.
1953 mini_jit_info_table_find_ext (MonoDomain
*domain
, gpointer addr
, gboolean allow_trampolines
, MonoDomain
**out_domain
)
1956 MonoInternalThread
*t
= mono_thread_internal_current ();
1962 ji
= mono_jit_info_table_find_internal (domain
, addr
, TRUE
, allow_trampolines
);
1965 *out_domain
= domain
;
1969 /* maybe it is shared code, so we also search in the root domain */
1970 if (domain
!= mono_get_root_domain ()) {
1971 ji
= mono_jit_info_table_find_internal (mono_get_root_domain (), addr
, TRUE
, allow_trampolines
);
1974 *out_domain
= mono_get_root_domain ();
1982 refs
= (gpointer
*)((t
->appdomain_refs
) ? *(gpointer
*) t
->appdomain_refs
: NULL
);
1983 for (; refs
&& *refs
; refs
++) {
1984 if (*refs
!= domain
&& *refs
!= mono_get_root_domain ()) {
1985 ji
= mono_jit_info_table_find_internal ((MonoDomain
*) *refs
, addr
, TRUE
, allow_trampolines
);
1988 *out_domain
= (MonoDomain
*) *refs
;
1998 mini_jit_info_table_find (MonoDomain
*domain
, gpointer addr
, MonoDomain
**out_domain
)
2000 return mini_jit_info_table_find_ext (domain
, addr
, FALSE
, out_domain
);
2003 /* Class lazy loading functions */
2004 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr
, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
2007 * wrap_non_exception_throws:
2009 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
2010 * WrapNonExceptionThrows flag set.
2013 wrap_non_exception_throws (MonoMethod
*m
)
2016 MonoAssembly
*ass
= m_class_get_image (m
->klass
)->assembly
;
2017 MonoCustomAttrInfo
* attrs
;
2020 gboolean val
= FALSE
;
2022 if (m
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
2023 MonoDynamicMethod
*dm
= (MonoDynamicMethod
*)m
;
2028 if (ass
->wrap_non_exception_throws_inited
)
2029 return ass
->wrap_non_exception_throws
;
2031 klass
= mono_class_get_runtime_compat_attr_class ();
2033 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
2034 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2036 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
2037 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
2039 int num_named
, named_type
, name_len
;
2042 if (!attr
->ctor
|| attr
->ctor
->klass
!= klass
)
2044 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2045 p
= (const char*)attr
->data
;
2046 g_assert (read16 (p
) == 0x0001);
2048 num_named
= read16 (p
);
2054 /* data_type = *p; */
2057 if (named_type
!= 0x54)
2059 name_len
= mono_metadata_decode_blob_size (p
, &p
);
2060 name
= (char *)g_malloc (name_len
+ 1);
2061 memcpy (name
, p
, name_len
);
2062 name
[name_len
] = 0;
2064 g_assert (!strcmp (name
, "WrapNonExceptionThrows"));
2066 /* The value is a BOOLEAN */
2069 mono_custom_attrs_free (attrs
);
2072 ass
->wrap_non_exception_throws
= val
;
2073 mono_memory_barrier ();
2074 ass
->wrap_non_exception_throws_inited
= TRUE
;
2079 #define MAX_UNMANAGED_BACKTRACE 128
2081 build_native_trace (MonoError
*error
)
2084 /* This puppy only makes sense on mobile, IOW, ARM. */
2085 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2087 void *native_trace
[MAX_UNMANAGED_BACKTRACE
];
2090 size
= backtrace (native_trace
, MAX_UNMANAGED_BACKTRACE
);
2096 res
= mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, size
, error
);
2097 return_val_if_nok (error
, NULL
);
2099 for (i
= 0; i
< size
; i
++)
2100 mono_array_set_internal (res
, gpointer
, i
, native_trace
[i
]);
2108 remove_wrappers_from_trace (GList
**trace_ips_p
)
2110 GList
*trace_ips
= *trace_ips_p
;
2111 GList
*p
= trace_ips
;
2113 /* jit info, generic info, ip */
2115 MonoJitInfo
*jinfo
= (MonoJitInfo
*) p
->data
;
2116 GList
*next_p
= p
->next
->next
->next
;
2117 /* FIXME Maybe remove more wrapper types */
2118 if (jinfo
->d
.method
->wrapper_type
== MONO_WRAPPER_OTHER
) {
2119 trace_ips
= g_list_delete_link (trace_ips
, p
->next
->next
);
2120 trace_ips
= g_list_delete_link (trace_ips
, p
->next
);
2121 trace_ips
= g_list_delete_link (trace_ips
, p
);
2126 *trace_ips_p
= trace_ips
;
2129 /* This can be called more than once on a MonoException. */
2131 setup_stack_trace (MonoException
*mono_ex
, GSList
**dynamic_methods
, GList
*trace_ips
, gboolean remove_wrappers
)
2134 GList
*trace_ips_copy
= g_list_copy (trace_ips
);
2135 if (remove_wrappers
)
2136 remove_wrappers_from_trace (&trace_ips_copy
);
2137 trace_ips_copy
= g_list_reverse (trace_ips_copy
);
2139 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips_copy
, mono_defaults
.int_class
, error
);
2140 mono_error_assert_ok (error
);
2141 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
2142 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, native_trace_ips
, build_native_trace (error
));
2143 mono_error_assert_ok (error
);
2144 if (*dynamic_methods
) {
2145 /* These methods could go away anytime, so save a reference to them in the exception object */
2147 MonoMList
*list
= (MonoMList
*)mono_ex
->dynamic_methods
;
2149 for (l
= *dynamic_methods
; l
; l
= l
->next
) {
2151 MonoDomain
*domain
= mono_domain_get ();
2153 if (domain
->method_to_dyn_method
) {
2154 mono_domain_lock (domain
);
2155 dis_link
= (guint32
)(size_t)g_hash_table_lookup (domain
->method_to_dyn_method
, l
->data
);
2156 mono_domain_unlock (domain
);
2158 MonoObject
*o
= mono_gchandle_get_target_internal (dis_link
);
2160 list
= mono_mlist_prepend_checked (list
, o
, error
);
2161 mono_error_assert_ok (error
);
2167 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, dynamic_methods
, list
);
2169 g_slist_free (*dynamic_methods
);
2170 *dynamic_methods
= NULL
;
2173 g_list_free (trace_ips_copy
);
2178 MONO_FIRST_PASS_UNHANDLED
,
2179 MONO_FIRST_PASS_CALLBACK_TO_NATIVE
,
2180 MONO_FIRST_PASS_HANDLED
,
2181 } MonoFirstPassResult
;
2184 * handle_exception_first_pass:
2186 * The first pass of exception handling. Unwind the stack until a catch
2187 * clause which can catch OBJ is found. Store the index of the filter clause
2188 * which caught the exception into OUT_FILTER_IDX. Return
2189 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2190 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2191 * wrapper and an exception handling callback is installed (in which case
2192 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2194 static MonoFirstPassResult
2195 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
)
2198 MonoDomain
*domain
= mono_domain_get ();
2199 MonoJitInfo
*ji
= NULL
;
2200 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2201 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2202 MonoLMF
*lmf
= mono_get_lmf ();
2203 GList
*trace_ips
= NULL
;
2204 GSList
*dynamic_methods
= NULL
;
2205 MonoException
*mono_ex
;
2206 gboolean stack_overflow
= FALSE
;
2207 MonoContext initial_ctx
;
2209 int frame_count
= 0;
2216 MonoFirstPassResult result
= MONO_FIRST_PASS_UNHANDLED
;
2218 g_assert (ctx
!= NULL
);
2220 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2221 stack_overflow
= TRUE
;
2223 mono_ex
= (MonoException
*)obj
;
2224 MonoArray
*initial_trace_ips
= mono_ex
->trace_ips
;
2225 if (initial_trace_ips
) {
2226 int len
= mono_array_length_internal (initial_trace_ips
) / TRACE_IP_ENTRY_SIZE
;
2228 // If we catch in managed/non-wrapper, we don't save the catching frame
2229 if (!mono_ex
->caught_in_unmanaged
)
2232 for (i
= 0; i
< len
; i
++) {
2233 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
2234 gpointer p
= mono_array_get_internal (initial_trace_ips
, gpointer
, (i
* TRACE_IP_ENTRY_SIZE
) + j
);
2235 trace_ips
= g_list_prepend (trace_ips
, p
);
2240 // Reset the state because we're making it be caught somewhere
2241 if (mono_ex
->caught_in_unmanaged
)
2242 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, caught_in_unmanaged
, 0);
2244 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2245 mono_error_assert_ok (error
);
2250 call_filter
= (int (*) (MonoContext
*, void *))mono_get_call_filter ();
2252 g_assert (jit_tls
->end_of_stack
);
2253 g_assert (jit_tls
->abort_func
);
2256 *out_filter_idx
= -1;
2260 *out_prev_ji
= NULL
;
2264 unwinder_init (&unwinder
);
2267 MonoContext new_ctx
;
2269 int clause_index_start
= 0;
2270 gboolean unwind_res
= TRUE
;
2272 StackFrameInfo frame
;
2277 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2279 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2280 g_list_free (trace_ips
);
2284 switch (frame
.type
) {
2285 case FRAME_TYPE_DEBUGGER_INVOKE
:
2286 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2287 case FRAME_TYPE_TRAMPOLINE
:
2288 case FRAME_TYPE_INTERP_TO_MANAGED
:
2289 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2292 case FRAME_TYPE_INTERP
:
2293 case FRAME_TYPE_MANAGED
:
2296 g_assert_not_reached ();
2300 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2305 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2307 ip
= MONO_CONTEXT_GET_IP (ctx
);
2310 method
= jinfo_get_method (ji
);
2311 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2313 if (mini_debug_options
.reverse_pinvoke_exceptions
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
2314 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2315 "The native frame called the managed method:\n%s\n",
2316 mono_method_full_name (method
, TRUE
));
2319 if (method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
2320 // avoid giant stack traces during a stack overflow
2321 if (frame_count
< 1000) {
2322 trace_ips
= g_list_prepend (trace_ips
, ip
);
2323 trace_ips
= g_list_prepend (trace_ips
, get_generic_info_from_stack_frame (ji
, ctx
));
2324 trace_ips
= g_list_prepend (trace_ips
, ji
);
2328 if (method
->dynamic
)
2329 dynamic_methods
= g_slist_prepend (dynamic_methods
, method
);
2331 if (stack_overflow
) {
2332 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2334 free_stack
= 0xffffff;
2337 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2338 result
= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
;
2342 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2343 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2344 gboolean filtered
= FALSE
;
2347 * During stack overflow, wait till the unwinding frees some stack
2348 * space before running handlers/finalizers.
2350 if (free_stack
<= (64 * 1024))
2353 if (is_address_protected (ji
, ei
, ip
)) {
2355 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2358 * Have to unwrap RuntimeWrappedExceptions if the
2359 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2361 if (non_exception
&& !wrap_non_exception_throws (method
))
2362 ex_obj
= non_exception
;
2366 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2367 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, FALSE
);
2369 #ifndef DISABLE_PERFCOUNTERS
2370 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_filters
);
2373 if (!ji
->is_interp
) {
2374 #ifndef MONO_CROSS_COMPILE
2375 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2377 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2379 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2380 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2382 g_assert (!ji
->from_llvm
);
2383 /* store the exception object in bp + ei->exvar_offset */
2384 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2388 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2390 * Pass the original il clause index to the landing pad so it can
2391 * branch to the landing pad associated with the il clause.
2392 * This is needed because llvm compiled code assumes that the EH
2393 * code always branches to the innermost landing pad.
2396 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2400 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2402 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2403 jit_tls
->orig_ex_ctx_set
= TRUE
;
2404 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2405 jit_tls
->orig_ex_ctx_set
= FALSE
;
2408 if (ji
->is_interp
) {
2409 /* The filter ends where the exception handler starts */
2410 filtered
= mini_get_interp_callbacks ()->run_filter (&frame
, (MonoException
*)ex_obj
, i
, ei
->data
.filter
, ei
->handler_start
);
2412 filtered
= call_filter (ctx
, ei
->data
.filter
);
2414 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex
, ctx
, &initial_ctx
);
2415 if (filtered
&& out_filter_idx
)
2416 *out_filter_idx
= filter_idx
;
2422 g_list_free (trace_ips
);
2423 /* mono_debugger_agent_handle_exception () needs this */
2424 mini_set_abort_threshold (&frame
);
2425 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2426 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2427 *catch_frame
= frame
;
2428 result
= MONO_FIRST_PASS_HANDLED
;
2433 ERROR_DECL (isinst_error
); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2434 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (ex_obj
, catch_class
, error
)) {
2435 /* runtime invokes catch even unhandled exceptions */
2436 setup_stack_trace (mono_ex
, &dynamic_methods
, trace_ips
, method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
);
2437 g_list_free (trace_ips
);
2442 /* mono_debugger_agent_handle_exception () needs this */
2444 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2445 frame
.native_offset
= (char*)ei
->handler_start
- (char*)ji
->code_start
;
2446 *catch_frame
= frame
;
2447 result
= MONO_FIRST_PASS_HANDLED
;
2450 mono_error_cleanup (isinst_error
);
2457 g_assert_not_reached ();
2461 * We implement delaying of aborts when in finally blocks by reusing the
2462 * abort protected block mechanism. The problem is that when throwing an
2463 * exception in a finally block we don't get to exit the protected block.
2464 * We exit it here when unwinding. Given that the order of the clauses
2465 * in the jit info is from inner clauses to the outer clauses, when we
2466 * want to exit the finally blocks inner to the clause that handles the
2467 * exception, we need to search up to its index.
2469 * FIXME We should do this inside interp, but with mixed mode we can
2470 * resume directly, without giving control back to the interp.
2473 interp_exit_finally_abort_blocks (MonoJitInfo
*ji
, int start_clause
, int end_clause
, gpointer ip
)
2476 for (i
= start_clause
; i
< end_clause
; i
++) {
2477 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2478 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
&&
2479 ip
>= ei
->handler_start
&&
2480 ip
< ei
->data
.handler_end
) {
2481 mono_threads_end_abort_protected_block ();
2486 static MonoException
*
2487 mono_get_exception_runtime_wrapped_checked (MonoObject
*wrapped_exception_raw
, MonoError
*error
)
2489 HANDLE_FUNCTION_ENTER ();
2490 MONO_HANDLE_DCL (MonoObject
, wrapped_exception
);
2491 MonoExceptionHandle ret
= mono_get_exception_runtime_wrapped_handle (wrapped_exception
, error
);
2492 HANDLE_FUNCTION_RETURN_OBJ (ret
);
2496 * mono_handle_exception_internal:
2497 * \param ctx saved processor state
2498 * \param obj the exception object
2499 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2502 mono_handle_exception_internal (MonoContext
*ctx
, MonoObject
*obj
, gboolean resume
, MonoJitInfo
**out_ji
)
2505 MonoDomain
*domain
= mono_domain_get ();
2506 MonoJitInfo
*ji
, *prev_ji
;
2507 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
2508 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
2509 MonoLMF
*lmf
= mono_get_lmf ();
2510 MonoException
*mono_ex
;
2511 gboolean stack_overflow
= FALSE
;
2512 MonoContext initial_ctx
;
2514 int frame_count
= 0;
2515 gint32 filter_idx
, first_filter_idx
= 0;
2517 MonoObject
*ex_obj
= NULL
;
2518 MonoObject
*non_exception
= NULL
;
2522 g_assert (ctx
!= NULL
);
2524 MonoException
*ex
= mono_get_exception_null_reference ();
2525 MonoString
*msg
= mono_string_new_checked (domain
, "Object reference not set to an instance of an object", error
);
2526 mono_error_assert_ok (error
);
2527 MONO_OBJECT_SETREF_INTERNAL (ex
, message
, msg
);
2528 obj
= (MonoObject
*)ex
;
2532 * Allocate a new exception object instead of the preconstructed ones.
2534 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
) {
2536 * It is not a good idea to try and put even more pressure on the little stack available.
2537 * obj = mono_get_exception_stack_overflow ();
2539 stack_overflow
= TRUE
;
2541 else if (obj
== (MonoObject
*)domain
->null_reference_ex
) {
2542 obj
= (MonoObject
*)mono_get_exception_null_reference ();
2545 if (!mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2546 mono_error_assert_ok (error
);
2547 non_exception
= obj
;
2548 obj
= (MonoObject
*)mono_get_exception_runtime_wrapped_checked (obj
, error
);
2549 mono_error_assert_ok (error
);
2552 mono_ex
= (MonoException
*)obj
;
2554 if (mini_debug_options
.suspend_on_exception
) {
2555 mono_runtime_printf_err ("Exception thrown, suspending...");
2560 if (mono_object_isinst_checked (obj
, mono_defaults
.exception_class
, error
)) {
2561 mono_ex
= (MonoException
*)obj
;
2563 mono_error_assert_ok (error
);
2567 if (mono_ex
&& jit_tls
->class_cast_from
) {
2568 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "InvalidCastException")) {
2569 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2570 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2571 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
2572 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2575 if (!is_ok (error
)) {
2576 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg
);
2577 mono_error_assert_ok (error
);
2581 if (!strcmp (m_class_get_name (mono_ex
->object
.vtable
->klass
), "ArrayTypeMismatchException")) {
2582 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
2583 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
2584 char *msg
= g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name
, to_name
);
2585 mono_ex
->message
= mono_string_new_checked (domain
, msg
, error
);
2588 if (!is_ok (error
)) {
2589 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg
);
2590 mono_error_assert_ok (error
);
2597 call_filter
= (int (*)(MonoContext
*, void*))mono_get_call_filter ();
2599 g_assert (jit_tls
->end_of_stack
);
2600 g_assert (jit_tls
->abort_func
);
2603 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2604 * end up being TRUE on any code path.
2606 memcpy (&jit_tls
->orig_ex_ctx
, ctx
, sizeof (MonoContext
));
2609 MonoContext ctx_cp
= *ctx
;
2610 if (mono_trace_is_enabled ()) {
2612 MonoMethod
*system_exception_get_message
= mono_class_get_method_from_name_checked (mono_defaults
.exception_class
, "get_Message", 0, 0, error
);
2613 mono_error_cleanup (error
);
2615 MonoMethod
*get_message
= system_exception_get_message
== NULL
? NULL
: mono_object_get_virtual_method_internal (obj
, system_exception_get_message
);
2616 MonoObject
*message
;
2617 const char *type_name
= m_class_get_name (mono_object_class (mono_ex
));
2619 if (get_message
== NULL
) {
2621 } else if (!strcmp (type_name
, "OutOfMemoryException") || !strcmp (type_name
, "StackOverflowException")) {
2623 msg
= g_strdup_printf ("(No exception message for: %s)\n", type_name
);
2625 MonoObject
*exc
= NULL
;
2626 message
= mono_runtime_try_invoke (get_message
, obj
, NULL
, &exc
, error
);
2627 g_assert (exc
== NULL
);
2628 mono_error_assert_ok (error
);
2632 msg
= mono_string_to_utf8_checked_internal ((MonoString
*) message
, error
);
2633 if (!is_ok (error
)) {
2634 mono_error_cleanup (error
);
2635 msg
= g_strdup ("(error while display System.Exception.Message property)");
2638 msg
= g_strdup ("(System.Exception.Message property not available)");
2641 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
);
2643 if (mono_ex
&& mono_trace_eval_exception (mono_object_class (mono_ex
)))
2644 mono_print_thread_dump_from_ctx (ctx
);
2646 jit_tls
->orig_ex_ctx_set
= TRUE
;
2647 MONO_PROFILER_RAISE (exception_throw
, (obj
));
2648 jit_tls
->orig_ex_ctx_set
= FALSE
;
2650 StackFrameInfo catch_frame
;
2651 MonoFirstPassResult res
;
2652 res
= handle_exception_first_pass (&ctx_cp
, obj
, &first_filter_idx
, &ji
, &prev_ji
, non_exception
, &catch_frame
);
2654 if (res
== MONO_FIRST_PASS_UNHANDLED
) {
2655 if (mono_aot_mode
== MONO_AOT_MODE_LLVMONLY_INTERP
) {
2656 /* Reached the top interpreted frames, but there might be native frames above us */
2657 throw_exception (obj
, TRUE
);
2658 g_assert_not_reached ();
2660 if (mini_debug_options
.break_on_exc
)
2662 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2664 if (mini_debug_options
.suspend_on_unhandled
&& mono_object_class (obj
) != mono_defaults
.threadabortexception_class
) {
2665 mono_runtime_printf_err ("Unhandled exception, suspending...");
2670 // FIXME: This runs managed code so it might cause another stack overflow when
2671 // we are handling a stack overflow
2672 mini_set_abort_threshold (&catch_frame
);
2673 mono_unhandled_exception_internal (obj
);
2675 gboolean unhandled
= FALSE
;
2678 * The exceptions caught by the mono_runtime_invoke_checked () calls
2679 * in the threadpool needs to be treated as unhandled (#669836).
2681 * FIXME: The check below is hackish, but its hard to distinguish
2682 * these runtime invoke calls from others in the runtime.
2684 if (ji
&& jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2685 if (prev_ji
&& jinfo_get_method (prev_ji
) == mono_defaults
.threadpool_perform_wait_callback_method
)
2690 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2691 else if (jinfo_get_method (ji
)->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
2692 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, NULL
, NULL
);
2693 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2695 else if (res
!= MONO_FIRST_PASS_CALLBACK_TO_NATIVE
)
2696 mini_get_dbg_callbacks ()->handle_exception ((MonoException
*)obj
, ctx
, &ctx_cp
, &catch_frame
);
2705 unwinder_init (&unwinder
);
2708 MonoContext new_ctx
;
2710 int clause_index_start
= 0;
2711 gboolean unwind_res
= TRUE
;
2712 StackFrameInfo frame
;
2717 ji
= jit_tls
->resume_state
.ji
;
2718 new_ctx
= jit_tls
->resume_state
.new_ctx
;
2719 clause_index_start
= jit_tls
->resume_state
.clause_index
;
2720 lmf
= jit_tls
->resume_state
.lmf
;
2721 first_filter_idx
= jit_tls
->resume_state
.first_filter_idx
;
2722 filter_idx
= jit_tls
->resume_state
.filter_idx
;
2725 unwind_res
= unwinder_unwind_frame (&unwinder
, domain
, jit_tls
, NULL
, ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
2727 *(mono_get_lmf_addr ()) = lmf
;
2729 jit_tls
->abort_func (obj
);
2730 g_assert_not_reached ();
2732 switch (frame
.type
) {
2733 case FRAME_TYPE_DEBUGGER_INVOKE
:
2734 case FRAME_TYPE_MANAGED_TO_NATIVE
:
2735 case FRAME_TYPE_TRAMPOLINE
:
2736 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX
:
2739 case FRAME_TYPE_INTERP_TO_MANAGED
:
2741 case FRAME_TYPE_INTERP
:
2742 case FRAME_TYPE_MANAGED
:
2745 g_assert_not_reached ();
2748 in_interp
= frame
.type
== FRAME_TYPE_INTERP
;
2753 ip
= (guint8
*)ji
->code_start
+ frame
.native_offset
;
2755 ip
= MONO_CONTEXT_GET_IP (ctx
);
2757 method
= jinfo_get_method (ji
);
2759 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2761 if (stack_overflow
) {
2762 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
2764 free_stack
= 0xffffff;
2767 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
&& ftnptr_eh_callback
) {
2768 guint32 handle
= mono_gchandle_new_internal (obj
, FALSE
);
2769 MONO_STACKDATA (stackptr
);
2771 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr
);
2773 ftnptr_eh_callback (handle
);
2774 g_error ("Did not expect ftnptr_eh_callback to return.");
2777 for (i
= clause_index_start
; i
< ji
->num_clauses
; i
++) {
2778 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
2779 gboolean filtered
= FALSE
;
2782 * During stack overflow, wait till the unwinding frees some stack
2783 * space before running handlers/finalizers.
2785 if (free_stack
<= (64 * 1024))
2788 if (is_address_protected (ji
, ei
, ip
)) {
2790 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
2793 * Have to unwrap RuntimeWrappedExceptions if the
2794 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2796 if (non_exception
&& !wrap_non_exception_throws (method
))
2797 ex_obj
= non_exception
;
2801 if (((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
))) {
2802 #ifndef MONO_CROSS_COMPILE
2803 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2804 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, ex_obj
);
2806 g_assert (!ji
->from_llvm
);
2807 /* store the exception object in bp + ei->exvar_offset */
2808 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = ex_obj
;
2813 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2815 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx
, ei
->clause_index
);
2818 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
2820 * Filter clauses should only be run in the
2821 * first pass of exception handling.
2823 filtered
= (filter_idx
== first_filter_idx
);
2828 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
2829 mono_object_isinst_checked (ex_obj
, catch_class
, error
)) || filtered
) {
2831 * This guards against the situation that we abort a thread that is executing a finally clause
2832 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2833 * check for this situation here and resume interruption if we are below the guarded block.
2835 if (G_UNLIKELY (jit_tls
->handler_block
)) {
2836 gboolean is_outside
= FALSE
;
2837 gpointer prot_bp
= MONO_CONTEXT_GET_BP (&jit_tls
->handler_block_context
);
2838 gpointer catch_bp
= MONO_CONTEXT_GET_BP (ctx
);
2839 //FIXME make this stack direction aware
2841 if (catch_bp
> prot_bp
) {
2843 } else if (catch_bp
== prot_bp
) {
2844 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2845 * So we check if the catch handler_start is protected by the guarded handler protected region
2848 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2849 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2850 * There aren't any further finally/fault handler blocks down the stack over this exception.
2851 * This must be ensured by the code that installs the guard trampoline.
2853 g_assert (ji
== mini_jit_info_table_find (domain
, (char *)MONO_CONTEXT_GET_IP (&jit_tls
->handler_block_context
), NULL
));
2855 if (!is_address_protected (ji
, jit_tls
->handler_block
, ei
->handler_start
)) {
2860 jit_tls
->handler_block
= NULL
;
2861 mono_thread_resume_interruption (TRUE
); /*We ignore the exception here, it will be raised later*/
2865 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2866 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2869 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2870 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2871 * clause. Since we specifically want to indicate that we're executing the
2872 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2873 * instead of ei->flags.
2875 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2876 jit_tls
->orig_ex_ctx_set
= TRUE
;
2877 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, MONO_EXCEPTION_CLAUSE_NONE
, ex_obj
));
2878 jit_tls
->orig_ex_ctx_set
= FALSE
;
2881 mini_set_abort_threshold (&frame
);
2884 interp_exit_finally_abort_blocks (ji
, clause_index_start
, i
, ip
);
2886 * ctx->pc points into the interpreter, after the call which transitioned to
2887 * JITted code. Store the unwind state into the
2888 * interpeter state, then resume, the interpreter will unwind itself until
2889 * it reaches the target frame and will continue execution from there.
2890 * The resuming is kinda hackish, from the native code standpoint, it looks
2891 * like the call which transitioned to JITted code has succeeded, but the
2892 * return value register etc. is not set, so we have to be careful.
2894 mini_get_interp_callbacks ()->set_resume_state (jit_tls
, mono_ex
, ei
, frame
.interp_frame
, ei
->handler_start
);
2895 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2896 /* ip == 0 means an interpreter frame */
2897 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
2898 mono_arch_undo_ip_adjustment (ctx
);
2900 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2903 #ifndef DISABLE_PERFCOUNTERS
2904 mono_atomic_fetch_add_i32 (&mono_perfcounters
->exceptions_depth
, frame_count
);
2906 if (obj
== (MonoObject
*)domain
->stack_overflow_ex
)
2907 jit_tls
->handling_stack_ovf
= FALSE
;
2911 mono_error_cleanup (error
);
2912 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
) {
2913 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2914 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2916 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2917 jit_tls
->orig_ex_ctx_set
= TRUE
;
2918 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2919 jit_tls
->orig_ex_ctx_set
= FALSE
;
2922 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2923 if (mono_trace_is_enabled () && mono_trace_eval (method
))
2924 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (method
, TRUE
));
2926 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2927 jit_tls
->orig_ex_ctx_set
= TRUE
;
2928 MONO_PROFILER_RAISE (exception_clause
, (method
, i
, (MonoExceptionEnum
)ei
->flags
, ex_obj
));
2929 jit_tls
->orig_ex_ctx_set
= FALSE
;
2932 #ifndef DISABLE_PERFCOUNTERS
2933 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_finallys
);
2936 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
|| ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
) {
2938 if (ji
->from_llvm
) {
2940 * LLVM compiled finally handlers follow the design
2941 * of the c++ ehabi, i.e. they call a resume function
2942 * at the end instead of returning to the caller.
2943 * So save the exception handling state,
2944 * mono_resume_unwind () will call us again to continue
2947 jit_tls
->resume_state
.ex_obj
= obj
;
2948 jit_tls
->resume_state
.ji
= ji
;
2949 jit_tls
->resume_state
.clause_index
= i
+ 1;
2950 jit_tls
->resume_state
.ctx
= *ctx
;
2951 jit_tls
->resume_state
.new_ctx
= new_ctx
;
2952 jit_tls
->resume_state
.lmf
= lmf
;
2953 jit_tls
->resume_state
.first_filter_idx
= first_filter_idx
;
2954 jit_tls
->resume_state
.filter_idx
= filter_idx
;
2955 mini_set_abort_threshold (&frame
);
2956 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
2959 mini_set_abort_threshold (&frame
);
2961 gboolean has_ex
= mini_get_interp_callbacks ()->run_finally (&frame
, i
, ei
->handler_start
, ei
->data
.handler_end
);
2964 * If run_finally didn't resume to a context, it means that the handler frame
2965 * is linked to the frame calling finally through interpreter frames. This
2966 * means that we will reach the handler frame by resuming the current context.
2968 if (MONO_CONTEXT_GET_IP (ctx
) != 0)
2969 mono_arch_undo_ip_adjustment (ctx
);
2973 call_filter (ctx
, ei
->handler_start
);
2981 interp_exit_finally_abort_blocks (ji
, clause_index_start
, ji
->num_clauses
, ip
);
2983 if (MONO_PROFILER_ENABLED (method_exception_leave
) &&
2984 mono_profiler_get_call_instrumentation_flags (method
) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
) {
2985 jit_tls
->orig_ex_ctx_set
= TRUE
;
2986 MONO_PROFILER_RAISE (method_exception_leave
, (method
, ex_obj
));
2987 jit_tls
->orig_ex_ctx_set
= FALSE
;
2993 g_assert_not_reached ();
2997 * mono_debugger_run_finally:
2998 * \param start_ctx saved processor state
2999 * This method is called by the Mono Debugger to call all \c finally clauses of the
3000 * current stack frame. It's used when the user issues a \c return command to make
3001 * the current stack frame return. After returning from this method, the debugger
3002 * unwinds the stack one frame and gives control back to the user.
3003 * NOTE: This method is only used when running inside the Mono Debugger.
3006 mono_debugger_run_finally (MonoContext
*start_ctx
)
3008 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
3009 MonoDomain
*domain
= mono_domain_get ();
3010 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3011 MonoLMF
*lmf
= mono_get_lmf ();
3012 MonoContext ctx
, new_ctx
;
3013 MonoJitInfo
*ji
, rji
;
3018 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
3019 if (!ji
|| ji
== (gpointer
)-1)
3023 call_filter
= (int (*)(MonoContext
*, void *))mono_get_call_filter ();
3025 for (i
= 0; i
< ji
->num_clauses
; i
++) {
3026 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
3028 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (&ctx
)) &&
3029 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
3030 call_filter (&ctx
, ei
->handler_start
);
3036 * mono_handle_exception:
3037 * \param ctx saved processor state
3038 * \param obj the exception object
3040 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3044 mono_handle_exception (MonoContext
*ctx
, gpointer void_obj
)
3046 MonoObject
*obj
= (MonoObject
*)void_obj
;
3048 MONO_REQ_GC_UNSAFE_MODE
;
3050 #ifndef DISABLE_PERFCOUNTERS
3051 mono_atomic_inc_i32 (&mono_perfcounters
->exceptions_thrown
);
3054 return mono_handle_exception_internal (ctx
, obj
, FALSE
, NULL
);
3057 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3059 #ifndef MONO_ARCH_USE_SIGACTION
3060 #error "Can't use sigaltstack without sigaction"
3064 mono_setup_altstack (MonoJitTlsData
*tls
)
3068 guint8
*staddr
= NULL
;
3069 #if defined(TARGET_OSX) || defined(_AIX)
3071 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3072 * stack pages. Stack overflow on main thread will kill the app.
3074 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3075 * do this for thread 1 with its stack at the top of memory. Other threads seem
3076 * fine for the altstack guard page, though.
3078 gboolean disable_stack_guard
= mono_threads_platform_is_main_thread ();
3080 gboolean disable_stack_guard
= FALSE
;
3083 if (mono_running_on_valgrind ())
3086 mono_thread_info_get_stack_bounds (&staddr
, &stsize
);
3090 tls
->end_of_stack
= staddr
+ stsize
;
3091 tls
->stack_size
= stsize
;
3093 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3095 if (!disable_stack_guard
) {
3096 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
3097 tls
->stack_ovf_guard_size
= ALIGN_TO (8 * 4096, mono_pagesize ());
3099 g_assert ((guint8
*)&sa
>= (guint8
*)tls
->stack_ovf_guard_base
+ tls
->stack_ovf_guard_size
);
3101 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
3102 /* mprotect can fail for the main thread stack */
3103 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
);
3105 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
3106 tls
->stack_ovf_valloced
= TRUE
;
3108 g_warning ("couldn't allocate guard page, continue without it");
3109 tls
->stack_ovf_guard_base
= NULL
;
3110 tls
->stack_ovf_guard_size
= 0;
3115 /* Setup an alternate signal stack */
3116 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
);
3117 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3119 g_assert (tls
->signal_stack
);
3121 sa
.ss_sp
= tls
->signal_stack
;
3122 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3124 g_assert (sigaltstack (&sa
, NULL
) == 0);
3126 if (tls
->stack_ovf_guard_base
)
3127 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
);
3129 mono_gc_register_altstack (staddr
, stsize
, tls
->signal_stack
, tls
->signal_stack_size
);
3134 mono_free_altstack (MonoJitTlsData
*tls
)
3139 sa
.ss_sp
= tls
->signal_stack
;
3140 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
3141 sa
.ss_flags
= SS_DISABLE
;
3142 err
= sigaltstack (&sa
, NULL
);
3143 g_assert (err
== 0);
3145 if (tls
->signal_stack
)
3146 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3148 if (!tls
->stack_ovf_guard_base
)
3150 if (tls
->stack_ovf_valloced
)
3151 mono_vfree (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MEM_ACCOUNT_EXCEPTIONS
);
3153 mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3156 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3159 mono_setup_altstack (MonoJitTlsData
*tls
)
3164 mono_free_altstack (MonoJitTlsData
*tls
)
3168 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3171 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*siginfo
, guint8
* fault_addr
)
3179 /* we got a stack overflow in the soft-guard pages
3180 * There are two cases:
3181 * 1) managed code caused the overflow: we unprotect the soft-guard page
3182 * and let the arch-specific code trigger the exception handling mechanism
3183 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3184 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3185 * and hope we can continue with those enabled, at least until the hard-guard page
3186 * is hit. The alternative to continuing here is to just print a message and abort.
3187 * We may add in the future the code to protect the pages again in the codepath
3188 * when we return from unmanaged to managed code.
3190 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
3191 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
3192 gboolean handled
= FALSE
;
3194 mono_mprotect (jit_tls
->stack_ovf_guard_base
, jit_tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
3195 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3197 mono_arch_handle_altstack_exception (ctx
, siginfo
, fault_addr
, TRUE
);
3202 /* We print a message: after this even managed stack overflows
3203 * may crash the runtime
3205 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx
), fault_addr
);
3206 if (!jit_tls
->handling_stack_ovf
) {
3207 jit_tls
->handling_stack_ovf
= 1;
3209 /*fprintf (stderr, "Already handling stack overflow\n");*/
3218 MonoMethod
*omethod
;
3220 } PrintOverflowUserData
;
3223 print_overflow_stack_frame (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3225 MonoMethod
*method
= NULL
;
3226 PrintOverflowUserData
*user_data
= (PrintOverflowUserData
*)data
;
3229 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3230 method
= jinfo_get_method (frame
->ji
);
3233 if (user_data
->count
== 0) {
3234 /* The first frame is in its prolog, so a line number cannot be computed */
3235 user_data
->count
++;
3239 /* If this is a one method overflow, skip the other instances */
3240 if (method
== user_data
->omethod
)
3243 location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, mono_domain_get ());
3244 mono_runtime_printf_err (" %s", location
);
3247 if (user_data
->count
== 1) {
3248 mono_runtime_printf_err (" <...>");
3249 user_data
->omethod
= method
;
3251 user_data
->omethod
= NULL
;
3254 user_data
->count
++;
3256 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame
->native_offset
);
3262 mono_handle_hard_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, MonoContext
*mctx
, guint8
* fault_addr
)
3264 PrintOverflowUserData ud
;
3266 /* we don't do much now, but we can warn the user with a useful message */
3267 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx
), fault_addr
);
3269 mono_runtime_printf_err ("Stacktrace:");
3271 memset (&ud
, 0, sizeof (ud
));
3273 mono_walk_stack_with_ctx (print_overflow_stack_frame
, mctx
, MONO_UNWIND_LOOKUP_ACTUAL_METHOD
, &ud
);
3279 print_stack_frame_signal_safe (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3281 MonoMethod
*method
= NULL
;
3283 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3284 method
= jinfo_get_method (frame
->ji
);
3287 const char *name_space
= m_class_get_name_space (method
->klass
);
3288 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
);
3290 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame
->native_offset
);
3296 static G_GNUC_UNUSED gboolean
3297 print_stack_frame_to_string (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3299 GString
*p
= (GString
*)data
;
3300 MonoMethod
*method
= NULL
;
3302 if (frame
->ji
&& frame
->type
!= FRAME_TYPE_TRAMPOLINE
)
3303 method
= jinfo_get_method (frame
->ji
);
3305 if (method
&& frame
->domain
) {
3306 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
3307 g_string_append_printf (p
, " %s\n", location
);
3310 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
3315 #ifndef MONO_CROSS_COMPILE
3316 static gboolean handle_crash_loop
= FALSE
;
3319 * mono_handle_native_crash:
3321 * Handle a native crash (e.g. SIGSEGV) while in native code by
3322 * printing diagnostic information and aborting.
3325 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3327 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3329 if (handle_crash_loop
)
3332 if (mini_debug_options
.suspend_on_native_crash
) {
3333 g_async_safe_printf ("Received %s, suspending...\n", signal
);
3335 // Sleep for 1 second.
3336 g_usleep (1000 * 1000);
3340 /* prevent infinite loops in crash handling */
3341 handle_crash_loop
= TRUE
;
3344 * A SIGSEGV indicates something went very wrong so we can no longer depend
3345 * on anything working. So try to print out lots of diagnostics, starting
3346 * with ones which have a greater chance of working.
3349 g_async_safe_printf("\n=================================================================\n");
3350 g_async_safe_printf("\tNative Crash Reporting\n");
3351 g_async_safe_printf("=================================================================\n");
3352 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal
);
3353 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3354 g_async_safe_printf("used by your application.\n");
3355 g_async_safe_printf("=================================================================\n");
3356 mono_dump_native_crash_info (signal
, mctx
, info
);
3358 /* !jit_tls means the thread was not registered with the runtime */
3359 // This must be below the native crash dump, because we can't safely
3360 // do runtime state probing after we have walked the managed stack here.
3361 if (jit_tls
&& mono_thread_internal_current () && mctx
) {
3362 g_async_safe_printf ("\n=================================================================\n");
3363 g_async_safe_printf ("\tManaged Stacktrace:\n");
3364 g_async_safe_printf ("=================================================================\n");
3366 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
);
3367 g_async_safe_printf ("=================================================================\n");
3370 #ifdef MONO_ARCH_USE_SIGACTION
3371 struct sigaction sa
;
3372 sa
.sa_handler
= SIG_DFL
;
3373 sigemptyset (&sa
.sa_mask
);
3376 /* Remove our SIGABRT handler */
3377 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
3379 /* On some systems we get a SIGILL when calling abort (), because it might
3380 * fail to raise SIGABRT */
3381 g_assert (sigaction (SIGILL
, &sa
, NULL
) != -1);
3384 mono_post_native_crash_handler (signal
, mctx
, info
, mono_do_crash_chaining
);
3390 mono_handle_native_crash (const char *signal
, MonoContext
*mctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
3392 g_assert_not_reached ();
3395 #endif /* !MONO_CROSS_COMPILE */
3398 mono_print_thread_dump_internal (void *sigctx
, MonoContext
*start_ctx
)
3400 MonoInternalThread
*thread
= mono_thread_internal_current ();
3407 text
= g_string_new (0);
3409 mono_gstring_append_thread_name (text
, thread
);
3411 g_string_append_printf (text
, " tid=%p this=%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
3412 mono_thread_internal_describe (thread
, text
);
3413 g_string_append (text
, "\n");
3416 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
3418 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
3420 mono_sigctx_to_monoctx (sigctx
, &ctx
);
3422 mono_walk_stack_with_ctx (print_stack_frame_to_string
, &ctx
, MONO_UNWIND_LOOKUP_ALL
, text
);
3424 mono_runtime_printf ("%s", text
->str
);
3426 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3427 OutputDebugStringA(text
->str
);
3430 g_string_free (text
, TRUE
);
3431 mono_runtime_stdout_fflush ();
3435 * mono_print_thread_dump:
3437 * Print information about the current thread to stdout.
3438 * \p sigctx can be NULL, allowing this to be called from gdb.
3441 mono_print_thread_dump (void *sigctx
)
3443 mono_print_thread_dump_internal (sigctx
, NULL
);
3447 mono_print_thread_dump_from_ctx (MonoContext
*ctx
)
3449 mono_print_thread_dump_internal (NULL
, ctx
);
3453 * mono_resume_unwind:
3455 * This is called by a trampoline from LLVM compiled finally clauses to continue
3459 mono_resume_unwind (MonoContext
*ctx
)
3461 MONO_REQ_GC_UNSAFE_MODE
;
3463 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3464 MonoContext new_ctx
;
3466 MONO_CONTEXT_SET_IP (ctx
, MONO_CONTEXT_GET_IP (&jit_tls
->resume_state
.ctx
));
3467 MONO_CONTEXT_SET_SP (ctx
, MONO_CONTEXT_GET_SP (&jit_tls
->resume_state
.ctx
));
3470 mono_handle_exception_internal (&new_ctx
, (MonoObject
*)jit_tls
->resume_state
.ex_obj
, TRUE
, NULL
);
3472 mono_restore_context (&new_ctx
);
3478 MonoJitExceptionInfo
*ei
;
3479 } FindHandlerBlockData
;
3482 find_last_handler_block (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3486 FindHandlerBlockData
*pdata
= (FindHandlerBlockData
*)data
;
3487 MonoJitInfo
*ji
= frame
->ji
;
3492 ip
= MONO_CONTEXT_GET_IP (ctx
);
3494 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
3495 MonoJitExceptionInfo
*ei
= ji
->clauses
+ i
;
3496 if (ei
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
3498 /*If ip points to the first instruction it means the handler block didn't start
3499 so we can leave its execution to the EH machinery*/
3500 if (ei
->handler_start
<= ip
&& ip
< ei
->data
.handler_end
) {
3512 install_handler_block_guard (MonoJitInfo
*ji
, MonoContext
*ctx
)
3515 MonoJitExceptionInfo
*clause
= NULL
;
3519 ip
= MONO_CONTEXT_GET_IP (ctx
);
3521 for (i
= 0; i
< ji
->num_clauses
; ++i
) {
3522 clause
= &ji
->clauses
[i
];
3523 if (clause
->flags
!= MONO_EXCEPTION_CLAUSE_FINALLY
)
3525 if (clause
->handler_start
<= ip
&& clause
->data
.handler_end
> ip
)
3529 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3530 g_assert (i
< ji
->num_clauses
);
3533 bp
= (guint8
*)MONO_CONTEXT_GET_BP (ctx
);
3534 *(bp
+ clause
->exvar_offset
) = 1;
3538 * Finds the bottom handler block running and install a block guard if needed.
3541 mono_install_handler_block_guard (MonoThreadUnwindState
*ctx
)
3543 FindHandlerBlockData data
= { 0 };
3544 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
];
3546 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3547 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3549 if (!jit_tls
|| jit_tls
->handler_block
)
3552 /* Do an async safe stack walk */
3553 mono_thread_info_set_is_async_context (TRUE
);
3554 mono_walk_stack_with_state (find_last_handler_block
, ctx
, MONO_UNWIND_NONE
, &data
);
3555 mono_thread_info_set_is_async_context (FALSE
);
3560 memcpy (&jit_tls
->handler_block_context
, &data
.ctx
, sizeof (MonoContext
));
3562 install_handler_block_guard (data
.ji
, &data
.ctx
);
3564 jit_tls
->handler_block
= data
.ei
;
3570 mono_uninstall_current_handler_block_guard (void)
3572 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3574 jit_tls
->handler_block
= NULL
;
3579 mono_current_thread_has_handle_block_guard (void)
3581 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3582 return jit_tls
&& jit_tls
->handler_block
!= NULL
;
3586 mono_set_cast_details (MonoClass
*from
, MonoClass
*to
)
3588 MonoJitTlsData
*jit_tls
= NULL
;
3590 if (mini_debug_options
.better_cast_details
) {
3591 jit_tls
= mono_tls_get_jit_tls ();
3592 jit_tls
->class_cast_from
= from
;
3593 jit_tls
->class_cast_to
= to
;
3598 /*returns false if the thread is not attached*/
3600 mono_thread_state_init_from_sigctx (MonoThreadUnwindState
*ctx
, void *sigctx
)
3602 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3609 mono_sigctx_to_monoctx (sigctx
, &ctx
->ctx
);
3611 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3612 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3613 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3616 mono_thread_state_init (ctx
);
3619 if (!ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] || !ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
])
3627 mono_thread_state_init (MonoThreadUnwindState
*ctx
)
3629 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3631 #if defined(MONO_CROSS_COMPILE)
3632 ctx
->valid
= FALSE
; //A cross compiler doesn't need to suspend.
3633 #elif MONO_ARCH_HAS_MONO_CONTEXT
3634 MONO_CONTEXT_GET_CURRENT (ctx
->ctx
);
3636 g_error ("Use a null sigctx requires a working mono-context");
3639 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3640 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3641 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
? thread
->jit_data
: NULL
;
3647 mono_thread_state_init_from_monoctx (MonoThreadUnwindState
*ctx
, MonoContext
*mctx
)
3649 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3656 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3657 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3658 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3663 /*returns false if the thread is not attached*/
3665 mono_thread_state_init_from_current (MonoThreadUnwindState
*ctx
)
3667 MonoThreadInfo
*thread
= mono_thread_info_current_unchecked ();
3668 MONO_ARCH_CONTEXT_DEF
3670 mono_arch_flush_register_windows ();
3672 if (!thread
|| !thread
->jit_data
) {
3676 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
->ctx
, mono_thread_state_init_from_current
);
3678 ctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
3679 ctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = mono_get_lmf ();
3680 ctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = thread
->jit_data
;
3686 mono_raise_exception_with_ctx (MonoException
*exc
, MonoContext
*ctx
)
3688 mono_handle_exception (ctx
, (MonoObject
*)exc
);
3689 mono_restore_context (ctx
);
3692 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3694 mono_setup_async_callback (MonoContext
*ctx
, void (*async_cb
)(void *fun
), gpointer user_data
)
3696 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3697 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
3698 jit_tls
->ex_ctx
= *ctx
;
3700 mono_arch_setup_async_callback (ctx
, async_cb
, user_data
);
3702 g_error ("This target doesn't support mono_arch_setup_async_callback");
3707 * mono_restore_context:
3709 * Call the architecture specific restore context function.
3712 mono_restore_context (MonoContext
*ctx
)
3714 static void (*restore_context
) (MonoContext
*);
3716 if (!restore_context
)
3717 restore_context
= (void (*)(MonoContext
*))mono_get_restore_context ();
3718 restore_context (ctx
);
3719 g_assert_not_reached ();
3723 * mono_jinfo_get_unwind_info:
3725 * Return the unwind info for JI.
3728 mono_jinfo_get_unwind_info (MonoJitInfo
*ji
, guint32
*unwind_info_len
)
3730 if (ji
->has_unwind_info
) {
3731 /* The address/length in the MonoJitInfo structure itself */
3732 MonoUnwindJitInfo
*info
= mono_jit_info_get_unwind_info (ji
);
3733 *unwind_info_len
= info
->unw_info_len
;
3734 return info
->unw_info
;
3735 } else if (ji
->from_aot
)
3736 return mono_aot_get_unwind_info (ji
, unwind_info_len
);
3738 return mono_get_cached_unwind_info (ji
->unwind_info
, unwind_info_len
);
3742 mono_jinfo_get_epilog_size (MonoJitInfo
*ji
)
3744 MonoArchEHJitInfo
*info
;
3746 info
= mono_jit_info_get_arch_eh_info (ji
);
3749 return info
->epilog_size
;
3753 * mono_install_ftnptr_eh_callback:
3755 * Install a callback that should be called when there is a managed exception
3756 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3757 * managed exception to a native exception, to properly unwind the native
3758 * stack; this native exception will then be converted back to a managed
3759 * exception in their managed-to-native wrapper.
3762 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback
)
3764 ftnptr_eh_callback
= callback
;
3768 * LLVM/Bitcode exception handling.
3772 throw_exception (MonoObject
*ex
, gboolean rethrow
)
3774 MONO_REQ_GC_UNSAFE_MODE
;
3777 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3778 MonoException
*mono_ex
;
3780 if (!mono_object_isinst_checked (ex
, mono_defaults
.exception_class
, error
)) {
3781 mono_error_assert_ok (error
);
3782 mono_ex
= mono_get_exception_runtime_wrapped_checked (ex
, error
);
3783 mono_error_assert_ok (error
);
3784 jit_tls
->thrown_non_exc
= mono_gchandle_new_internal (ex
, FALSE
);
3787 mono_ex
= (MonoException
*)ex
;
3790 jit_tls
->thrown_exc
= mono_gchandle_new_internal ((MonoObject
*)mono_ex
, FALSE
);
3793 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3794 GList
*l
, *ips
= NULL
;
3797 _Unwind_Backtrace (build_stack_trace
, &ips
);
3798 /* The list contains ip-gshared info pairs */
3800 ips
= g_list_reverse (ips
);
3801 for (l
= ips
; l
; l
= l
->next
) {
3802 trace
= g_list_append (trace
, l
->data
);
3803 trace
= g_list_append (trace
, NULL
);
3804 trace
= g_list_append (trace
, NULL
);
3806 MonoArray
*ips_arr
= mono_glist_to_array (trace
, mono_defaults
.int_class
, error
);
3807 mono_error_assert_ok (error
);
3808 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
3810 g_list_free (trace
);
3814 mono_llvm_cpp_throw_exception ();
3818 mono_llvm_throw_exception (MonoObject
*ex
)
3820 throw_exception (ex
, FALSE
);
3824 mono_llvm_rethrow_exception (MonoObject
*ex
)
3826 throw_exception (ex
, TRUE
);
3830 mono_llvm_raise_exception (MonoException
*e
)
3832 mono_llvm_throw_exception ((MonoObject
*)e
);
3836 mono_llvm_reraise_exception (MonoException
*e
)
3838 mono_llvm_rethrow_exception ((MonoObject
*)e
);
3842 mono_llvm_throw_corlib_exception (guint32 ex_token_index
)
3844 guint32 ex_token
= MONO_TOKEN_TYPE_DEF
| ex_token_index
;
3847 ex
= mono_exception_from_token (m_class_get_image (mono_defaults
.exception_class
), ex_token
);
3849 mono_llvm_throw_exception ((MonoObject
*)ex
);
3853 * mono_llvm_resume_exception:
3855 * Resume exception propagation.
3858 mono_llvm_resume_exception (void)
3860 mono_llvm_cpp_throw_exception ();
3864 * mono_llvm_load_exception:
3866 * Return the currently thrown exception.
3869 mono_llvm_load_exception (void)
3872 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3874 MonoException
*mono_ex
= (MonoException
*)mono_gchandle_get_target_internal (jit_tls
->thrown_exc
);
3876 MonoArray
*ta
= mono_ex
->trace_ips
;
3879 GList
*trace_ips
= NULL
;
3880 gpointer ip
= MONO_RETURN_ADDRESS ();
3882 size_t upper
= mono_array_length_internal (ta
);
3884 for (int i
= 0; i
< upper
; i
+= TRACE_IP_ENTRY_SIZE
) {
3885 gpointer curr_ip
= mono_array_get_internal (ta
, gpointer
, i
);
3886 for (int j
= 0; j
< TRACE_IP_ENTRY_SIZE
; ++j
) {
3887 gpointer p
= mono_array_get_internal (ta
, gpointer
, i
+ j
);
3888 trace_ips
= g_list_append (trace_ips
, p
);
3894 // FIXME: Does this work correctly for rethrows?
3895 // We may be discarding useful information
3896 // when this gets GC'ed
3897 MonoArray
*ips_arr
= mono_glist_to_array (trace_ips
, mono_defaults
.int_class
, error
);
3898 mono_error_assert_ok (error
);
3899 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, ips_arr
);
3900 g_list_free (trace_ips
);
3903 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3905 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, trace_ips
, mono_array_new_checked (mono_domain_get (), mono_defaults
.int_class
, 0, error
));
3906 mono_error_assert_ok (error
);
3907 MONO_OBJECT_SETREF_INTERNAL (mono_ex
, stack_trace
, mono_array_new_checked (mono_domain_get (), mono_defaults
.stack_frame_class
, 0, error
));
3908 mono_error_assert_ok (error
);
3911 return &mono_ex
->object
;
3915 * mono_llvm_clear_exception:
3917 * Mark the currently thrown exception as handled.
3920 mono_llvm_clear_exception (void)
3922 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3923 mono_gchandle_free_internal (jit_tls
->thrown_exc
);
3924 jit_tls
->thrown_exc
= 0;
3925 if (jit_tls
->thrown_non_exc
)
3926 mono_gchandle_free_internal (jit_tls
->thrown_non_exc
);
3927 jit_tls
->thrown_non_exc
= 0;
3929 mono_memory_barrier ();
3933 * mono_llvm_match_exception:
3935 * Return the innermost clause containing REGION_START-REGION_END which can handle
3936 * the current exception.
3939 mono_llvm_match_exception (MonoJitInfo
*jinfo
, guint32 region_start
, guint32 region_end
, gpointer rgctx
, MonoObject
*this_obj
)
3942 MonoJitTlsData
*jit_tls
= mono_get_jit_tls ();
3946 g_assert (jit_tls
->thrown_exc
);
3947 exc
= mono_gchandle_get_target_internal (jit_tls
->thrown_exc
);
3948 if (jit_tls
->thrown_non_exc
) {
3950 * Have to unwrap RuntimeWrappedExceptions if the
3951 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
3953 if (!wrap_non_exception_throws (jinfo_get_method (jinfo
)))
3954 exc
= mono_gchandle_get_target_internal (jit_tls
->thrown_non_exc
);
3957 for (int i
= 0; i
< jinfo
->num_clauses
; i
++) {
3958 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
3959 MonoClass
*catch_class
;
3961 if (! (ei
->try_offset
== region_start
&& ei
->try_offset
+ ei
->try_len
== region_end
) )
3964 catch_class
= ei
->data
.catch_class
;
3965 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class
))) {
3966 MonoGenericContext context
;
3967 MonoType
*inflated_type
;
3969 g_assert (rgctx
|| this_obj
);
3970 context
= get_generic_context_from_stack_frame (jinfo
, rgctx
? rgctx
: this_obj
->vtable
);
3971 inflated_type
= mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class
), &context
, error
);
3972 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
3974 catch_class
= mono_class_from_mono_type_internal (inflated_type
);
3975 mono_metadata_free_type (inflated_type
);
3978 // FIXME: Handle edge cases handled in get_exception_catch_class
3979 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&& mono_object_isinst_checked (exc
, catch_class
, error
)) {
3980 index
= ei
->clause_index
;
3983 mono_error_assert_ok (error
);
3985 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
3986 g_assert_not_reached ();
3993 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
3994 G_EXTERN_C _Unwind_Reason_Code
mono_debug_personality (int a
, _Unwind_Action b
,
3995 uint64_t c
, struct _Unwind_Exception
*d
, struct _Unwind_Context
*e
)
3997 g_assert_not_reached ();
4000 G_EXTERN_C
void mono_debug_personality (void);
4003 mono_debug_personality (void)
4005 g_assert_not_reached ();