[interp] Fix interp logging (#17636)
[mono-project.git] / mono / mini / mini-exceptions.c
blob0a466c12052461db164997c93d20afdce2be4d69
1 /**
2 * \file
3 * generic exception support
5 * Authors:
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.
15 #include <config.h>
16 #include <glib.h>
17 #include <string.h>
18 #include <signal.h>
20 #ifdef HAVE_EXECINFO_H
21 #include <execinfo.h>
22 #endif
24 #ifdef HAVE_SYS_TYPES_H
25 #include <sys/types.h>
26 #endif
28 #ifdef HAVE_SYS_WAIT_H
29 #include <sys/wait.h>
30 #endif
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
36 #ifdef HAVE_SYS_SYSCALL_H
37 #include <sys/syscall.h>
38 #endif
40 #ifdef HAVE_SYS_PRCTL_H
41 #include <sys/prctl.h>
42 #endif
44 #ifdef HAVE_UNWIND_H
45 #include <unwind.h>
46 #endif
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/tabledefs.h>
50 #include <mono/metadata/threads.h>
51 #include <mono/metadata/threads-types.h>
52 #include <mono/metadata/debug-helpers.h>
53 #include <mono/metadata/exception.h>
54 #include <mono/metadata/exception-internals.h>
55 #include <mono/metadata/object-internals.h>
56 #include <mono/metadata/reflection-internals.h>
57 #include <mono/metadata/gc-internals.h>
58 #include <mono/metadata/debug-internals.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/metadata/profiler-private.h>
61 #include <mono/metadata/mono-endian.h>
62 #include <mono/metadata/environment.h>
63 #include <mono/metadata/mono-mlist.h>
64 #include <mono/utils/mono-merp.h>
65 #include <mono/utils/mono-mmap.h>
66 #include <mono/utils/mono-logger-internals.h>
67 #include <mono/utils/mono-error.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/mono-state.h>
70 #include <mono/utils/mono-threads-debug.h>
72 #include "mini.h"
73 #include "trace.h"
74 #include "debugger-agent.h"
75 #include "seq-points.h"
76 #include "llvm-runtime.h"
77 #include "mini-llvm.h"
78 #include "aot-runtime.h"
79 #include "mini-runtime.h"
80 #include "interp/interp.h"
82 #ifdef ENABLE_LLVM
83 #include "mini-llvm-cpp.h"
84 #endif
86 #ifdef TARGET_ARM
87 #include "mini-arm.h"
88 #endif
90 #ifndef MONO_ARCH_CONTEXT_DEF
91 #define MONO_ARCH_CONTEXT_DEF
92 #endif
94 #if !defined(DISABLE_CRASH_REPORTING)
95 #include <gmodule.h>
96 #endif
97 #include "mono/utils/mono-tls-inline.h"
100 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
101 * This structure represents one entry.
102 * This should consists of pointers only.
104 typedef struct
106 gpointer ip;
107 gpointer generic_info;
108 /* Only for interpreter frames */
109 MonoJitInfo *ji;
110 } ExceptionTraceIp;
112 /* Number of words in trace_ips belonging to one entry */
113 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
115 static gpointer restore_context_func, call_filter_func;
116 static gpointer throw_exception_func, rethrow_exception_func, rethrow_preserve_exception_func;
117 static gpointer throw_corlib_exception_func;
119 static MonoFtnPtrEHCallback ftnptr_eh_callback;
121 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);
122 static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx);
123 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
124 static gboolean mono_current_thread_has_handle_block_guard (void);
125 static gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx);
126 static void mono_uninstall_current_handler_block_guard (void);
127 static gboolean mono_exception_walk_trace_internal (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data);
128 static void throw_exception (MonoObject *ex, gboolean rethrow);
130 static void mono_summarize_managed_stack (MonoThreadSummary *out);
131 static void mono_summarize_unmanaged_stack (MonoThreadSummary *out);
132 static void mono_summarize_exception (MonoException *exc, MonoThreadSummary *out);
133 static void mono_crash_reporting_register_native_library (const char *module_path, const char *module_name);
134 static void mono_crash_reporting_allow_all_native_libraries (void);
136 static gboolean
137 first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
139 gpointer *data = (gpointer *)addr;
141 if (!frame->managed)
142 return FALSE;
144 if (!ctx) {
145 // FIXME: Happens with llvm_only
146 *data = NULL;
147 return TRUE;
150 *data = frame->frame_addr;
151 g_assert (*data);
152 return TRUE;
155 static gpointer
156 mono_thread_get_managed_sp (void)
158 gpointer addr = NULL;
159 mono_walk_stack (first_managed, MONO_UNWIND_SIGNAL_SAFE, &addr);
160 return addr;
163 static void
164 mini_clear_abort_threshold (void)
166 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
167 jit_tls->abort_exc_stack_threshold = NULL;
170 static void
171 mini_set_abort_threshold (StackFrameInfo *frame)
173 gpointer sp = frame->frame_addr;
174 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
175 // Only move it up, to avoid thrown/caught
176 // exceptions lower in the stack from triggering
177 // a rethrow
178 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
179 if (!jit_tls->abort_exc_stack_threshold || above_threshold) {
180 jit_tls->abort_exc_stack_threshold = sp;
184 // Note: In the case that the frame is above where the thread abort
185 // was set we bump the threshold so that functions called from the new,
186 // higher threshold don't trigger the thread abort exception
187 static gboolean
188 mini_above_abort_threshold (void)
190 gpointer sp = mono_thread_get_managed_sp ();
191 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
193 if (!sp)
194 return TRUE;
196 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
198 if (above_threshold)
199 jit_tls->abort_exc_stack_threshold = sp;
201 return above_threshold;
204 static int
205 mono_get_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
207 SeqPoint sp;
208 if (mono_find_prev_seq_point_for_native_offset (domain, method, native_offset, NULL, &sp))
209 return sp.il_offset;
210 return -1;
213 void
214 mono_exceptions_init (void)
216 MonoRuntimeExceptionHandlingCallbacks cbs;
217 if (mono_ee_features.use_aot_trampolines) {
218 restore_context_func = mono_aot_get_trampoline ("restore_context");
219 call_filter_func = mono_aot_get_trampoline ("call_filter");
220 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
221 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
222 rethrow_preserve_exception_func = mono_aot_get_trampoline ("rethrow_preserve_exception");
223 } else if (!mono_llvm_only) {
224 MonoTrampInfo *info;
226 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
227 mono_tramp_info_register (info, NULL);
228 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
229 mono_tramp_info_register (info, NULL);
230 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
231 mono_tramp_info_register (info, NULL);
232 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
233 mono_tramp_info_register (info, NULL);
234 rethrow_preserve_exception_func = mono_arch_get_rethrow_preserve_exception (&info, FALSE);
235 mono_tramp_info_register (info, NULL);
238 mono_arch_exceptions_init ();
240 cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
241 cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
242 cbs.mono_summarize_managed_stack = mono_summarize_managed_stack;
243 cbs.mono_summarize_unmanaged_stack = mono_summarize_unmanaged_stack;
244 cbs.mono_summarize_exception = mono_summarize_exception;
245 cbs.mono_register_native_library = mono_crash_reporting_register_native_library;
246 cbs.mono_allow_all_native_libraries = mono_crash_reporting_allow_all_native_libraries;
248 if (mono_llvm_only) {
249 cbs.mono_raise_exception = mono_llvm_raise_exception;
250 cbs.mono_reraise_exception = mono_llvm_reraise_exception;
251 } else {
252 cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception ();
253 cbs.mono_reraise_exception = (void (*)(MonoException *))mono_get_rethrow_exception ();
255 cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
256 cbs.mono_exception_walk_trace = mono_exception_walk_trace;
257 cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
258 cbs.mono_uninstall_current_handler_block_guard = mono_uninstall_current_handler_block_guard;
259 cbs.mono_current_thread_has_handle_block_guard = mono_current_thread_has_handle_block_guard;
260 cbs.mono_clear_abort_threshold = mini_clear_abort_threshold;
261 cbs.mono_above_abort_threshold = mini_above_abort_threshold;
262 mono_install_eh_callbacks (&cbs);
263 mono_install_get_seq_point (mono_get_seq_point_for_native_offset);
266 gpointer
267 mono_get_throw_exception (void)
269 g_assert (throw_exception_func);
270 return throw_exception_func;
273 gpointer
274 mono_get_rethrow_exception (void)
276 g_assert (rethrow_exception_func);
277 return rethrow_exception_func;
280 gpointer
281 mono_get_rethrow_preserve_exception (void)
283 g_assert (rethrow_preserve_exception_func);
284 return rethrow_preserve_exception_func;
287 static void
288 no_call_filter (void)
290 g_assert_not_reached ();
293 gpointer
294 mono_get_call_filter (void)
296 /* This is called even in llvmonly mode etc. */
297 if (!call_filter_func)
298 return (gpointer)no_call_filter;
299 return call_filter_func;
302 gpointer
303 mono_get_restore_context (void)
305 g_assert (restore_context_func);
306 return restore_context_func;
309 gpointer
310 mono_get_throw_corlib_exception (void)
312 gpointer code = NULL;
313 MonoTrampInfo *info;
315 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
316 if (throw_corlib_exception_func)
317 return throw_corlib_exception_func;
319 if (mono_ee_features.use_aot_trampolines)
320 code = mono_aot_get_trampoline ("throw_corlib_exception");
321 else {
322 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
323 mono_tramp_info_register (info, NULL);
326 mono_memory_barrier ();
328 throw_corlib_exception_func = code;
330 return throw_corlib_exception_func;
334 * mono_get_throw_exception_addr:
336 * Return an address which stores the result of
337 * mono_get_throw_exception.
339 gpointer
340 mono_get_throw_exception_addr (void)
342 return &throw_exception_func;
345 gpointer
346 mono_get_rethrow_preserve_exception_addr (void)
348 return &rethrow_preserve_exception_func;
351 static gboolean
352 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
354 MonoTryBlockHoleTableJitInfo *table;
355 int i;
356 guint32 offset;
357 guint16 clause;
359 if (ei->try_start > ip || ip >= ei->try_end)
360 return FALSE;
362 if (!ji->has_try_block_holes)
363 return TRUE;
365 table = mono_jit_info_get_try_block_hole_table_info (ji);
366 offset = (guint32)((char*)ip - (char*)ji->code_start);
367 clause = (guint16)(ei - ji->clauses);
368 g_assert (clause < ji->num_clauses);
370 for (i = 0; i < table->num_holes; ++i) {
371 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
372 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
373 return FALSE;
375 return TRUE;
378 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
380 #if 0
381 static gboolean show_native_addresses = TRUE;
382 #else
383 static gboolean show_native_addresses = FALSE;
384 #endif
386 static _Unwind_Reason_Code
387 build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
389 MonoDomain *domain = mono_domain_get ();
390 uintptr_t ip = _Unwind_GetIP (frame_ctx);
392 if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
393 GList **trace_ips = (GList **)state;
394 *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
397 return _URC_NO_REASON;
400 static GSList*
401 get_unwind_backtrace (void)
403 GSList *ips = NULL;
405 _Unwind_Backtrace (build_stack_trace, &ips);
407 return g_slist_reverse (ips);
410 #else
412 static GSList*
413 get_unwind_backtrace (void)
415 return NULL;
418 #endif
420 static gboolean
421 arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
422 MonoJitInfo *ji, MonoContext *ctx,
423 MonoContext *new_ctx, MonoLMF **lmf,
424 host_mgreg_t **save_locations,
425 StackFrameInfo *frame)
427 if (!ji && *lmf) {
428 if (((gsize)(*lmf)->previous_lmf) & 2) {
429 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
431 memset (frame, 0, sizeof (StackFrameInfo));
432 frame->ji = ji;
434 *new_ctx = *ctx;
436 if (ext->kind == MONO_LMFEXT_DEBUGGER_INVOKE) {
438 * This LMF entry is created by the soft debug code to mark transitions to
439 * managed code done during invokes.
441 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
442 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
443 } else if (ext->kind == MONO_LMFEXT_INTERP_EXIT || ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX) {
444 frame->type = FRAME_TYPE_INTERP_TO_MANAGED;
445 frame->interp_exit_data = ext->interp_exit_data;
446 if (ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX) {
447 frame->type = FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX;
448 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
450 } else {
451 g_assert_not_reached ();
454 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~3);
456 return TRUE;
460 return mono_arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
464 * find_jit_info:
466 * Translate between the mono_arch_unwind_frame function and the old API.
468 static MonoJitInfo *
469 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
470 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
472 StackFrameInfo frame;
473 MonoJitInfo *ji;
474 gboolean err;
475 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
477 /* Avoid costly table lookup during stack overflow */
478 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
479 ji = prev_ji;
480 else
481 ji = mini_jit_info_table_find (domain, ip, NULL);
483 if (managed)
484 *managed = FALSE;
486 err = arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
487 if (!err)
488 return (MonoJitInfo *)-1;
490 if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
492 * Remove any unused lmf.
493 * Mask out the lower bits which might be used to hold additional information.
495 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P -1));
498 /* Convert between the new and the old APIs */
499 switch (frame.type) {
500 case FRAME_TYPE_MANAGED:
501 if (managed)
502 *managed = TRUE;
503 return frame.ji;
504 case FRAME_TYPE_TRAMPOLINE:
505 return frame.ji;
506 case FRAME_TYPE_MANAGED_TO_NATIVE:
507 if (frame.ji)
508 return frame.ji;
509 else {
510 memset (res, 0, sizeof (MonoJitInfo));
511 res->d.method = frame.method;
512 return res;
514 case FRAME_TYPE_DEBUGGER_INVOKE: {
515 MonoContext tmp_ctx;
518 * The normal exception handling code can't handle this frame, so just
519 * skip it.
521 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
522 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
523 return ji;
525 default:
526 g_assert_not_reached ();
527 return NULL;
531 /* mono_find_jit_info:
533 * This function is used to gather information from @ctx. It return the
534 * MonoJitInfo of the corresponding function, unwinds one stack frame and
535 * stores the resulting context into @new_ctx. It also stores a string
536 * describing the stack location into @trace (if not NULL), and modifies
537 * the @lmf if necessary. @native_offset return the IP offset from the
538 * start of the function or -1 if that info is not available.
540 MonoJitInfo *
541 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
542 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
543 gboolean *managed)
545 gboolean managed2;
546 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
547 MonoJitInfo *ji;
548 MonoMethod *method = NULL;
550 if (trace)
551 *trace = NULL;
553 if (native_offset)
554 *native_offset = -1;
556 if (managed)
557 *managed = FALSE;
559 ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
561 if (ji == (gpointer)-1)
562 return ji;
564 if (ji && !ji->is_trampoline)
565 method = jinfo_get_method (ji);
567 if (managed2 || (method && method->wrapper_type)) {
568 const char *real_ip, *start;
569 gint32 offset;
571 start = (const char *)ji->code_start;
572 if (!managed2)
573 /* ctx->ip points into native code */
574 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
575 else
576 real_ip = (const char*)ip;
578 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
579 offset = real_ip - start;
580 else
581 offset = -1;
583 if (native_offset)
584 *native_offset = offset;
586 if (managed)
587 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
588 *managed = TRUE;
590 if (trace)
591 *trace = mono_debug_print_stack_frame (method, offset, domain);
592 } else {
593 if (trace) {
594 char *fname = mono_method_full_name (jinfo_get_method (res), TRUE);
595 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
596 g_free (fname);
600 return ji;
604 * mono_find_jit_info_ext:
606 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
607 * structure.
608 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
609 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
610 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
611 * to obtain the last managed frame.
612 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
613 * On return, it will be filled with the locations where callee saved registers are saved
614 * by the current frame. This is returned outside of StackFrameInfo because it can be
615 * quite large on some platforms.
616 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
617 * not be set.
619 gboolean
620 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
621 MonoJitInfo *prev_ji, MonoContext *ctx,
622 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
623 host_mgreg_t **save_locations,
624 StackFrameInfo *frame)
626 gboolean err;
627 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
628 MonoJitInfo *ji;
629 MonoDomain *target_domain = domain;
630 MonoMethod *method = NULL;
631 gboolean async = mono_thread_info_is_async_context ();
633 if (trace)
634 *trace = NULL;
636 /* Avoid costly table lookup during stack overflow */
637 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
638 ji = prev_ji;
639 else
640 ji = mini_jit_info_table_find_ext (domain, ip, TRUE, &target_domain);
642 if (!target_domain)
643 target_domain = domain;
645 if (save_locations)
646 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (host_mgreg_t*));
648 err = arch_unwind_frame (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
649 if (!err)
650 return FALSE;
652 gboolean not_i2m = frame->type != FRAME_TYPE_INTERP_TO_MANAGED && frame->type != FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX;
654 if (not_i2m && *lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
656 * Remove any unused lmf.
657 * Mask out the lower bits which might be used to hold additional information.
659 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P -1));
662 if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async)
663 method = jinfo_get_method (frame->ji);
665 if (frame->type == FRAME_TYPE_MANAGED && method) {
666 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
667 frame->managed = TRUE;
670 if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
672 * This type of frame is just a marker, the caller should unwind once more to get the
673 * last managed frame.
675 frame->ji = NULL;
676 frame->method = NULL;
679 frame->native_offset = -1;
680 frame->domain = target_domain;
681 frame->async_context = async;
682 frame->frame_addr = MONO_CONTEXT_GET_SP (ctx);
684 ji = frame->ji;
686 if (frame->type == FRAME_TYPE_MANAGED)
687 frame->method = method;
689 if (ji && (frame->managed || (method && method->wrapper_type))) {
690 const char *real_ip, *start;
692 start = (const char *)ji->code_start;
693 if (frame->type == FRAME_TYPE_MANAGED)
694 real_ip = (const char*)ip;
695 else
696 /* ctx->ip points into native code */
697 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
699 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
700 frame->native_offset = real_ip - start;
701 else {
702 frame->native_offset = -1;
705 if (trace)
706 *trace = mono_debug_print_stack_frame (method, frame->native_offset, domain);
707 } else {
708 if (trace && frame->method) {
709 char *fname = mono_method_full_name (frame->method, TRUE);
710 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
711 g_free (fname);
715 return TRUE;
718 typedef struct {
719 gboolean in_interp;
720 MonoInterpStackIter interp_iter;
721 gpointer last_frame_addr;
722 } Unwinder;
724 static void
725 unwinder_init (Unwinder *unwinder)
727 memset (unwinder, 0, sizeof (Unwinder));
730 #if defined(__GNUC__) && defined(TARGET_ARM64)
731 /* gcc 4.9.2 seems to miscompile this on arm64 */
732 static __attribute__((optimize("O0"))) gboolean
733 #else
734 static gboolean
735 #endif
736 unwinder_unwind_frame (Unwinder *unwinder,
737 MonoDomain *domain, MonoJitTlsData *jit_tls,
738 MonoJitInfo *prev_ji, MonoContext *ctx,
739 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
740 host_mgreg_t **save_locations,
741 StackFrameInfo *frame)
743 gpointer parent;
744 if (unwinder->in_interp) {
745 memcpy (new_ctx, ctx, sizeof (MonoContext));
747 /* Process debugger invokes */
748 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
749 if (unwinder->last_frame_addr < (gpointer)(*lmf)) {
750 if (((gsize)(*lmf)->previous_lmf) & 2) {
751 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
752 if (ext->kind == MONO_LMFEXT_DEBUGGER_INVOKE) {
753 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~7);
754 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
755 return TRUE;
760 unwinder->in_interp = mini_get_interp_callbacks ()->frame_iter_next (&unwinder->interp_iter, frame);
761 if (frame->type == FRAME_TYPE_INTERP) {
762 parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame);
763 unwinder->last_frame_addr = parent;
765 if (!unwinder->in_interp)
766 return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame);
767 return TRUE;
768 } else {
769 gboolean res = mono_find_jit_info_ext (domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf,
770 save_locations, frame);
771 if (!res)
772 return FALSE;
773 if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED || frame->type == FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX) {
774 unwinder->in_interp = TRUE;
775 mini_get_interp_callbacks ()->frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data);
777 unwinder->last_frame_addr = frame->frame_addr;
778 return TRUE;
783 * This function is async-safe.
785 static gpointer
786 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
788 MonoGenericJitInfo *gi;
789 MonoMethod *method;
790 gpointer info;
792 if (!ji->has_generic_jit_info)
793 return NULL;
794 gi = mono_jit_info_get_generic_jit_info (ji);
795 if (!gi->has_this)
796 return NULL;
798 info = NULL;
800 * Search location list if available, it contains the precise location of the
801 * argument for every pc offset, even if the method was interrupted while it was in
802 * its prolog.
804 if (gi->nlocs) {
805 int offset = (gsize)MONO_CONTEXT_GET_IP (ctx) - (gsize)ji->code_start;
806 int i;
808 for (i = 0; i < gi->nlocs; ++i) {
809 MonoDwarfLocListEntry *entry = &gi->locations [i];
811 if (offset >= entry->from && (offset < entry->to || entry->to == 0)) {
812 if (entry->is_reg)
813 info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg);
814 else
815 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset);
816 break;
819 g_assert (i < gi->nlocs);
820 } else {
821 if (gi->this_in_reg)
822 info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg);
823 else
824 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
825 gi->this_offset);
828 method = jinfo_get_method (ji);
829 if (mono_method_get_context (method)->method_inst) {
830 /* A MonoMethodRuntimeGenericContext* */
831 return info;
832 } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || m_class_is_valuetype (method->klass)) {
833 /* A MonoVTable* */
834 return info;
835 } else {
836 /* Avoid returning a managed object */
837 MonoObject *this_obj = (MonoObject *)info;
839 return this_obj->vtable;
844 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
846 static MonoGenericContext
847 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
849 MonoGenericContext context = { NULL, NULL };
850 MonoClass *klass, *method_container_class;
851 MonoMethod *method;
853 g_assert (generic_info);
855 method = jinfo_get_method (ji);
856 g_assert (method->is_inflated);
857 if (mono_method_get_context (method)->method_inst) {
858 MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext *)generic_info;
860 klass = mrgctx->class_vtable->klass;
861 context.method_inst = mrgctx->method_inst;
862 g_assert (context.method_inst);
863 } else {
864 MonoVTable *vtable = (MonoVTable *)generic_info;
866 klass = vtable->klass;
869 //g_assert (!mono_class_is_gtd (method->klass));
870 if (mono_class_is_ginst (method->klass))
871 method_container_class = mono_class_get_generic_class (method->klass)->container_class;
872 else
873 method_container_class = method->klass;
875 /* class might refer to a subclass of method's class */
876 while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) {
877 klass = m_class_get_parent (klass);
878 g_assert (klass);
881 if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass))
882 context.class_inst = mini_class_get_context (klass)->class_inst;
884 if (mono_class_is_ginst (klass))
885 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass)->container_class, method_container_class));
886 else
887 g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class));
889 return context;
892 static MonoMethod*
893 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
895 ERROR_DECL (error);
896 MonoGenericContext context;
897 MonoMethod *method;
899 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
900 return jinfo_get_method (ji);
901 context = get_generic_context_from_stack_frame (ji, generic_info);
903 method = jinfo_get_method (ji);
904 method = mono_method_get_declaring_generic_method (method);
905 method = mono_class_inflate_generic_method_checked (method, &context, error);
906 g_assert (is_ok (error)); /* FIXME don't swallow the error */
908 return method;
912 * mono_exception_walk_native_trace:
913 * \param ex The exception object whose frames should be walked
914 * \param func callback to call for each stack frame
915 * \param user_data data passed to the callback
916 * This function walks the stacktrace of an exception. For
917 * each frame the callback function is called with the relevant info.
918 * The walk ends when no more stack frames are found or when the callback
919 * returns a TRUE value.
922 gboolean
923 mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
925 gboolean res;
927 MONO_ENTER_GC_UNSAFE;
928 res = mono_exception_walk_trace_internal (ex, func, user_data);
929 MONO_EXIT_GC_UNSAFE;
930 return res;
933 static gboolean
934 mono_exception_stackframe_obj_walk (MonoStackFrame *captured_frame, MonoExceptionFrameWalk func, gpointer user_data)
936 if (!captured_frame)
937 return TRUE;
939 gpointer ip = (gpointer) (captured_frame->method_address + captured_frame->native_offset);
940 MonoJitInfo *ji = mono_jit_info_table_find_internal (mono_domain_get (), ip, TRUE, TRUE);
942 // Other domain maybe?
943 if (!ji)
944 return FALSE;
945 MonoMethod *method = jinfo_get_method (ji);
947 gboolean r = func (method, (gpointer) captured_frame->method_address, captured_frame->native_offset, TRUE, user_data);
948 if (r)
949 return TRUE;
951 return FALSE;
954 static gboolean
955 mono_exception_stacktrace_obj_walk (MonoStackTrace *st, MonoExceptionFrameWalk func, gpointer user_data)
957 int num_captured = st->captured_traces ? mono_array_length_internal (st->captured_traces) : 0;
958 for (int i=0; i < num_captured; i++) {
959 MonoStackTrace *curr_trace = mono_array_get_fast (st->captured_traces, MonoStackTrace *, i);
960 mono_exception_stacktrace_obj_walk (curr_trace, func, user_data);
963 int num_frames = st->frames ? mono_array_length_internal (st->frames) : 0;
964 for (int frame = 0; frame < num_frames; frame++) {
965 gboolean r = mono_exception_stackframe_obj_walk (mono_array_get_fast (st->frames, MonoStackFrame *, frame), func, user_data);
966 if (r)
967 return TRUE;
970 return TRUE;
973 gboolean
974 mono_exception_walk_trace_internal (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
976 MONO_REQ_GC_UNSAFE_MODE;
978 MonoDomain *domain = mono_domain_get ();
979 MonoArray *ta = ex->trace_ips;
981 /* Exception is not thrown yet */
982 if (ta == NULL)
983 return FALSE;
985 int len = mono_array_length_internal (ta) / TRACE_IP_ENTRY_SIZE;
986 gboolean otherwise_has_traces = len > 0;
988 for (int i = 0; i < len; i++) {
989 ExceptionTraceIp trace_ip;
991 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
992 gpointer ip = trace_ip.ip;
993 gpointer generic_info = trace_ip.generic_info;
995 MonoJitInfo *ji = NULL;
996 if (trace_ip.ji) {
997 ji = trace_ip.ji;
998 } else {
999 ji = mono_jit_info_table_find (domain, ip);
1002 if (ji == NULL) {
1003 gboolean r;
1004 MONO_ENTER_GC_SAFE;
1005 r = func (NULL, ip, 0, FALSE, user_data);
1006 MONO_EXIT_GC_SAFE;
1007 if (r)
1008 break;
1009 } else {
1010 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
1011 if (func (method, ji->code_start, (char *) ip - (char *) ji->code_start, TRUE, user_data))
1012 break;
1016 ta = (MonoArray *) ex->captured_traces;
1017 len = ta ? mono_array_length_internal (ta) : 0;
1018 gboolean captured_has_traces = len > 0;
1020 for (int i = 0; i < len; i++) {
1021 MonoStackTrace *captured_trace = mono_array_get_fast (ta, MonoStackTrace *, i);
1022 if (!captured_trace)
1023 break;
1025 mono_exception_stacktrace_obj_walk (captured_trace, func, user_data);
1028 return captured_has_traces || otherwise_has_traces;
1031 MonoArray *
1032 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
1034 ERROR_DECL (error);
1035 MonoDomain *domain = mono_domain_get ();
1036 MonoArray *res;
1037 MonoArray *ta = exc->trace_ips;
1038 MonoDebugSourceLocation *location;
1039 int i, len;
1041 if (ta == NULL) {
1042 /* Exception is not thrown yet */
1043 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, error);
1044 mono_error_set_pending_exception (error);
1045 return res;
1048 len = mono_array_length_internal (ta) / TRACE_IP_ENTRY_SIZE;
1050 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, error);
1051 if (mono_error_set_pending_exception (error))
1052 return NULL;
1054 for (i = skip; i < len; i++) {
1055 MonoJitInfo *ji;
1056 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
1057 if (!is_ok (error)) {
1058 mono_error_set_pending_exception (error);
1059 return NULL;
1061 ExceptionTraceIp trace_ip;
1062 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
1063 gpointer ip = trace_ip.ip;
1064 gpointer generic_info = trace_ip.generic_info;
1065 MonoMethod *method;
1067 if (trace_ip.ji) {
1068 ji = trace_ip.ji;
1069 } else {
1070 ji = mono_jit_info_table_find (domain, ip);
1071 if (ji == NULL) {
1072 /* Unmanaged frame */
1073 mono_array_setref_internal (res, i, sf);
1074 continue;
1078 g_assert (ji != NULL);
1080 if (mono_llvm_only || !generic_info)
1081 /* Can't resolve actual method */
1082 method = jinfo_get_method (ji);
1083 else
1084 method = get_method_from_stack_frame (ji, generic_info);
1085 if (jinfo_get_method (ji)->wrapper_type) {
1086 char *s;
1088 sf->method = NULL;
1089 s = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION);
1090 MonoString *name = mono_string_new_checked (domain, s, error);
1091 g_free (s);
1092 if (!is_ok (error)) {
1093 mono_error_set_pending_exception (error);
1094 return NULL;
1096 MONO_OBJECT_SETREF_INTERNAL (sf, internal_method_name, name);
1098 else {
1099 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
1100 if (!is_ok (error)) {
1101 mono_error_set_pending_exception (error);
1102 return NULL;
1104 MONO_OBJECT_SETREF_INTERNAL (sf, method, rm);
1107 sf->method_index = ji->from_aot ? mono_aot_find_method_index (method) : 0xffffff;
1108 sf->method_address = (gsize) ji->code_start;
1109 sf->native_offset = (char *)ip - (char *)ji->code_start;
1112 * mono_debug_lookup_source_location() returns both the file / line number information
1113 * and the IL offset. Note that computing the IL offset is already an expensive
1114 * operation, so we shouldn't call this method twice.
1116 location = mono_debug_lookup_source_location (jinfo_get_method (ji), sf->native_offset, domain);
1117 if (location) {
1118 sf->il_offset = location->il_offset;
1119 } else {
1120 SeqPoint sp;
1121 if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (ji), sf->native_offset, NULL, &sp))
1122 sf->il_offset = sp.il_offset;
1123 else
1124 sf->il_offset = -1;
1127 if (need_file_info) {
1128 if (location && location->source_file) {
1129 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1130 if (!is_ok (error)) {
1131 mono_error_set_pending_exception (error);
1132 return NULL;
1134 MONO_OBJECT_SETREF_INTERNAL (sf, filename, filename);
1135 sf->line = location->row;
1136 sf->column = location->column;
1137 } else {
1138 sf->line = sf->column = 0;
1139 sf->filename = NULL;
1143 mono_debug_free_source_location (location);
1144 mono_array_setref_internal (res, i - skip, sf);
1147 return res;
1150 static void
1151 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1153 if (!start_ctx) {
1154 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1155 if (jit_tls && jit_tls->orig_ex_ctx_set)
1156 start_ctx = &jit_tls->orig_ex_ctx;
1158 mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
1161 * mono_walk_stack_with_ctx:
1162 * Unwind the current thread starting at \p start_ctx.
1163 * If \p start_ctx is null, we capture the current context.
1165 void
1166 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1168 MonoContext extra_ctx;
1169 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1170 MONO_ARCH_CONTEXT_DEF
1172 if (!thread || !thread->jit_data)
1173 return;
1175 if (!start_ctx) {
1176 mono_arch_flush_register_windows ();
1177 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
1178 start_ctx = &extra_ctx;
1181 mono_walk_stack_full (func, start_ctx, mono_domain_get (), thread->jit_data, mono_get_lmf (), unwind_options, user_data, FALSE);
1185 * mono_walk_stack_with_state:
1186 * Unwind a thread described by \p state.
1188 * State must be valid (state->valid == TRUE).
1190 * If you are using this function to unwind another thread, make sure it is suspended.
1192 * If \p state is null, we capture the current context.
1194 void
1195 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
1197 MonoThreadUnwindState extra_state;
1198 if (!state) {
1199 g_assert (!mono_thread_info_is_async_context ());
1200 if (!mono_thread_state_init_from_current (&extra_state))
1201 return;
1202 state = &extra_state;
1205 g_assert (state->valid);
1207 if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
1208 /* Not attached */
1209 return;
1211 mono_walk_stack_full (func,
1212 &state->ctx,
1213 (MonoDomain *)state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
1214 (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
1215 (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF],
1216 unwind_options, user_data, FALSE);
1219 void
1220 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
1222 MonoThreadUnwindState state;
1223 if (!mono_thread_state_init_from_current (&state))
1224 return;
1225 mono_walk_stack_with_state (func, &state, options, user_data);
1229 * mono_walk_stack_full:
1230 * \param func callback to call for each stack frame
1231 * \param domain starting appdomain, can be NULL to use the current domain
1232 * \param unwind_options what extra information the unwinder should gather
1233 * \param start_ctx starting state of the stack walk, can be NULL.
1234 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1235 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1236 * \param user_data data passed to the callback
1237 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1238 * This function walks the stack of a thread, starting from the state
1239 * represented by \p start_ctx. For each frame the callback
1240 * function is called with the relevant info. The walk ends when no more
1241 * managed stack frames are found or when the callback returns a TRUE value.
1243 static void
1244 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)
1246 gint il_offset;
1247 MonoContext ctx, new_ctx;
1248 StackFrameInfo frame;
1249 gboolean res;
1250 host_mgreg_t *reg_locations [MONO_MAX_IREGS];
1251 host_mgreg_t *new_reg_locations [MONO_MAX_IREGS];
1252 gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
1253 gboolean async = mono_thread_info_is_async_context ();
1254 Unwinder unwinder;
1256 memset (&frame, 0, sizeof (StackFrameInfo));
1258 #ifndef TARGET_WASM
1259 if (mono_llvm_only) {
1260 GSList *l, *ips;
1262 if (async)
1263 return;
1265 ips = get_unwind_backtrace ();
1266 for (l = ips; l; l = l->next) {
1267 guint8 *ip = (guint8*)l->data;
1268 memset (&frame, 0, sizeof (StackFrameInfo));
1269 frame.ji = mini_jit_info_table_find (domain, ip, &frame.domain);
1270 if (!frame.ji || frame.ji->is_trampoline)
1271 continue;
1272 frame.type = FRAME_TYPE_MANAGED;
1273 frame.method = jinfo_get_method (frame.ji);
1274 // FIXME: Cannot lookup the actual method
1275 frame.actual_method = frame.method;
1276 if (frame.type == FRAME_TYPE_MANAGED) {
1277 if (!frame.method->wrapper_type || frame.method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
1278 frame.managed = TRUE;
1280 frame.native_offset = ip - (guint8*)frame.ji->code_start;
1281 frame.il_offset = -1;
1283 if (func (&frame, NULL, user_data))
1284 break;
1286 g_slist_free (ips);
1287 return;
1289 #endif
1291 if (!start_ctx) {
1292 g_warning ("start_ctx required for stack walk");
1293 return;
1296 if (!domain) {
1297 g_warning ("domain required for stack walk");
1298 return;
1301 if (!jit_tls) {
1302 g_warning ("jit_tls required for stack walk");
1303 return;
1306 /*The LMF will be null if the target have no managed frames.*/
1307 /* g_assert (lmf); */
1308 if (async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD)) {
1309 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1310 return;
1313 memcpy (&ctx, start_ctx, sizeof (MonoContext));
1314 memset (reg_locations, 0, sizeof (reg_locations));
1316 unwinder_init (&unwinder);
1318 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
1319 frame.lmf = lmf;
1320 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
1321 if (!res)
1322 return;
1324 if (frame.type == FRAME_TYPE_TRAMPOLINE)
1325 goto next;
1327 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) {
1328 MonoDebugSourceLocation *source = NULL;
1330 // Don't do this when we can be in a signal handler
1331 if (!crash_context)
1332 source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
1333 if (source) {
1334 il_offset = source->il_offset;
1335 } else {
1336 MonoSeqPointInfo *seq_points = NULL;
1338 // It's more reliable to look into the global cache if possible
1339 if (crash_context)
1340 seq_points = (MonoSeqPointInfo *) frame.ji->seq_points;
1341 else
1342 seq_points = mono_get_seq_points (domain, jinfo_get_method (frame.ji));
1344 SeqPoint sp;
1345 if (seq_points && mono_seq_point_find_prev_by_native_offset (seq_points, frame.native_offset, &sp))
1346 il_offset = sp.il_offset;
1347 else
1348 il_offset = -1;
1350 mono_debug_free_source_location (source);
1351 } else
1352 il_offset = -1;
1354 frame.il_offset = il_offset;
1356 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) {
1357 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
1358 } else {
1359 frame.actual_method = frame.method;
1362 if (get_reg_locations)
1363 frame.reg_locations = reg_locations;
1365 if (func (&frame, &ctx, user_data))
1366 return;
1368 next:
1369 if (get_reg_locations) {
1370 for (int i = 0; i < MONO_MAX_IREGS; ++i)
1371 if (new_reg_locations [i])
1372 reg_locations [i] = new_reg_locations [i];
1375 ctx = new_ctx;
1379 #ifdef DISABLE_CRASH_REPORTING
1381 static void
1382 mono_summarize_managed_stack (MonoThreadSummary *out)
1384 return;
1387 static void
1388 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1390 return;
1393 static void
1394 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1396 return;
1399 static void
1400 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1402 return;
1405 static void
1406 mono_crash_reporting_allow_all_native_libraries ()
1408 return;
1412 #else
1414 typedef struct {
1415 MonoFrameSummary *frames;
1416 int num_frames;
1417 int max_frames;
1418 MonoStackHash *hashes;
1419 const char *error;
1420 } MonoSummarizeUserData;
1422 static void
1423 copy_summary_string_safe (char *dest, const char *src)
1425 g_strlcpy (dest, src, MONO_MAX_SUMMARY_NAME_LEN);
1428 static void
1429 fill_frame_managed_info (MonoFrameSummary *frame, MonoMethod * method)
1431 MonoImage *image = mono_class_get_image (method->klass);
1432 // Used for hashing, more stable across rebuilds than using GUID
1433 copy_summary_string_safe (frame->str_descr, image->assembly_name);
1435 frame->managed_data.guid = image->guid;
1436 frame->managed_data.token = method->token;
1437 frame->managed_data.filename = image->module_name;
1439 MonoDotNetHeader *header = &image->image_info->cli_header;
1440 frame->managed_data.image_size = header->nt.pe_image_size;
1441 frame->managed_data.time_date_stamp = image->time_date_stamp;
1444 typedef struct {
1445 char *suffix;
1446 char *exported_name;
1447 } MonoLibWhitelistEntry;
1449 static GList *native_library_whitelist;
1450 static gboolean allow_all_native_libraries = FALSE;
1452 static void
1453 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1455 // Examples: libsystem_pthread.dylib -> "pthread"
1456 // Examples: libsystem_platform.dylib -> "platform"
1457 // Examples: mono-sgen -> "mono" from above line
1458 MonoLibWhitelistEntry *entry = g_new0 (MonoLibWhitelistEntry, 1);
1459 entry->suffix = g_strdup (module_path);
1460 entry->exported_name = g_strdup (module_name);
1461 native_library_whitelist = g_list_append (native_library_whitelist, entry);
1464 static void
1465 mono_crash_reporting_allow_all_native_libraries ()
1467 allow_all_native_libraries = TRUE;
1470 static gboolean
1471 check_whitelisted_module (const char *in_name, const char **out_module)
1473 #ifndef MONO_PRIVATE_CRASHES
1474 return TRUE;
1475 #else
1476 if (g_str_has_suffix (in_name, "mono-sgen")) {
1477 if (out_module)
1478 copy_summary_string_safe ((char *) *out_module, "mono");
1479 return TRUE;
1481 if (allow_all_native_libraries) {
1482 if (out_module) {
1483 /* for a module name, use the basename of the full path in in_name */
1484 char *basename = (char *) in_name, *p = (char *) in_name;
1485 while (*p != '\0') {
1486 if (*p == '/')
1487 basename = p + 1;
1488 p++;
1490 if (*basename)
1491 copy_summary_string_safe ((char *) *out_module, basename);
1492 else
1493 copy_summary_string_safe ((char *) *out_module, "unknown");
1496 return TRUE;
1499 for (GList *cursor = native_library_whitelist; cursor; cursor = cursor->next) {
1500 MonoLibWhitelistEntry *iter = (MonoLibWhitelistEntry *) cursor->data;
1501 if (!g_str_has_suffix (in_name, iter->suffix))
1502 continue;
1503 if (out_module)
1504 copy_summary_string_safe ((char *) *out_module, iter->exported_name);
1505 return TRUE;
1508 return FALSE;
1509 #endif
1512 static intptr_t
1513 mono_make_portable_ip (intptr_t in_ip, intptr_t module_base)
1515 // FIXME: Make generalize away from llvm tools?
1516 // So lldb starts the pointer base at 0x100000000
1517 // and expects to get pointers as (offset + constant)
1519 // Quirk shared by:
1520 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1521 // *CoreSymbolicationDT.framework version: 63750*/
1522 intptr_t offset = in_ip - module_base;
1523 intptr_t magic_value = offset + 0x100000000;
1524 return magic_value;
1527 static gboolean
1528 mono_get_portable_ip (intptr_t in_ip, intptr_t *out_ip, gint32 *out_offset, const char **out_module, char *out_name)
1530 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1531 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1532 // non-recursive lock twice on this thread, and will deadlock.
1533 char sname [256], fname [256];
1534 void *saddr = NULL, *fbase = NULL;
1535 gboolean success = g_module_address ((void*)in_ip, fname, 256, &fbase, sname, 256, &saddr);
1536 if (!success)
1537 return FALSE;
1539 if (!check_whitelisted_module (fname, out_module))
1540 return FALSE;
1542 *out_ip = mono_make_portable_ip ((intptr_t) saddr, (intptr_t) fbase);
1543 *out_offset = in_ip - (intptr_t) saddr;
1545 if (saddr && out_name)
1546 copy_summary_string_safe (out_name, sname);
1547 return TRUE;
1550 static guint64
1551 summarize_offset_free_hash (guint64 accum, MonoFrameSummary *frame)
1553 if (!frame->is_managed)
1554 return accum;
1556 // See: mono_ptrarray_hash
1557 guint64 hash_accum = accum;
1559 // The assembly and the method token, no offsets
1560 hash_accum += mono_metadata_str_hash (frame->str_descr);
1561 hash_accum += frame->managed_data.token;
1563 return hash_accum;
1566 static guint64
1567 summarize_offset_rich_hash (guint64 accum, MonoFrameSummary *frame)
1569 // See: mono_ptrarray_hash
1570 guint64 hash_accum = accum;
1572 if (!frame->is_managed) {
1573 hash_accum += frame->unmanaged_data.ip;
1574 } else {
1575 hash_accum += mono_metadata_str_hash (frame->str_descr);
1576 hash_accum += frame->managed_data.token;
1577 hash_accum += frame->managed_data.il_offset;
1580 return hash_accum;
1583 static gboolean
1584 summarize_frame_internal (MonoMethod *method, gpointer ip, size_t native_offset, int il_offset, gboolean managed, gpointer user_data)
1586 MonoSummarizeUserData *ud = (MonoSummarizeUserData *) user_data;
1588 gboolean valid_state = ud->num_frames + 1 < ud->max_frames;
1589 if (!valid_state) {
1590 ud->error = "Exceeded the maximum number of frames";
1591 return TRUE;
1594 MonoFrameSummary *dest = &ud->frames [ud->num_frames];
1596 dest->unmanaged_data.ip = (intptr_t) ip;
1597 dest->is_managed = managed;
1598 dest->unmanaged_data.module [0] = '\0';
1600 if (!managed && method && method->wrapper_type != MONO_WRAPPER_NONE && method->wrapper_type < MONO_WRAPPER_NUM) {
1601 dest->is_managed = FALSE;
1602 dest->unmanaged_data.has_name = TRUE;
1603 copy_summary_string_safe (dest->str_descr, mono_wrapper_type_to_str (method->wrapper_type));
1606 #ifndef MONO_PRIVATE_CRASHES
1607 if (method)
1608 dest->managed_data.name = (char *) method->name;
1609 #endif
1611 if (managed) {
1612 if (!method) {
1613 ud->error = "Managed method frame, but no provided managed method";
1614 return TRUE;
1616 fill_frame_managed_info (dest, method);
1617 dest->managed_data.native_offset = native_offset;
1618 dest->managed_data.il_offset = il_offset;
1619 } else {
1620 dest->managed_data.token = -1;
1624 ud->hashes->offset_free_hash = summarize_offset_free_hash (ud->hashes->offset_free_hash, dest);
1625 ud->hashes->offset_rich_hash = summarize_offset_rich_hash (ud->hashes->offset_rich_hash, dest);
1627 // We return FALSE, so we're continuing walking
1628 // And we increment the pointer because we're done with this cell in the array
1629 ud->num_frames++;
1630 return FALSE;
1633 static gboolean
1634 summarize_frame_managed_walk (MonoMethod *method, gpointer ip, size_t frame_native_offset, gboolean managed, gpointer user_data)
1636 int il_offset = -1;
1638 if (managed && method) {
1639 MonoDebugSourceLocation *location = mono_debug_lookup_source_location (method, frame_native_offset, mono_domain_get ());
1640 if (location) {
1641 il_offset = location->il_offset;
1642 mono_debug_free_source_location (location);
1646 intptr_t portable_ip = 0;
1647 gint32 offset = 0;
1648 mono_get_portable_ip ((intptr_t) ip, &portable_ip, &offset, NULL, NULL);
1650 return summarize_frame_internal (method, (gpointer) portable_ip, frame_native_offset, il_offset, managed, user_data);
1654 static gboolean
1655 summarize_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
1657 // Don't record trampolines between managed frames
1658 if (frame->ji && frame->ji->is_trampoline)
1659 return TRUE;
1661 if (frame->ji && (frame->ji->is_trampoline || frame->ji->async))
1662 return FALSE; // Keep unwinding
1664 intptr_t ip = 0;
1665 gint32 offset = 0;
1666 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx), &ip, &offset, NULL, NULL);
1667 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1669 gboolean is_managed = (frame->type == FRAME_TYPE_MANAGED || frame->type == FRAME_TYPE_INTERP);
1670 MonoMethod *method = NULL;
1671 if (frame && frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
1672 method = jinfo_get_method (frame->ji);
1674 if (is_managed)
1675 method = jinfo_get_method (frame->ji);
1677 return summarize_frame_internal (method, (gpointer) ip, offset, frame->il_offset, is_managed, data);
1680 static void
1681 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1683 memset (out, 0, sizeof (MonoThreadSummary));
1685 MonoException *inner_exc = exc;
1686 int exc_index = 0;
1688 for (exc_index = 0; exc_index < MONO_MAX_SUMMARY_EXCEPTIONS; exc_index++) {
1689 if (inner_exc == NULL)
1690 break;
1692 // Set up state to walk this MonoException's stack
1693 MonoSummarizeUserData data;
1694 memset (&data, 0, sizeof (MonoSummarizeUserData));
1695 data.max_frames = MONO_MAX_SUMMARY_FRAMES;
1696 data.num_frames = 0;
1697 data.frames = out->exceptions [exc_index].managed_frames;
1699 // Accumulate all hashes from all exceptions in traveral order
1700 data.hashes = &out->hashes;
1702 mono_exception_walk_trace (inner_exc, summarize_frame_managed_walk, &data);
1704 // Save per-MonoException info
1705 out->exceptions [exc_index].managed_exc_type = inner_exc->object.vtable->klass;
1706 out->exceptions [exc_index].num_managed_frames = data.num_frames;
1708 // Continue to traverse nesting of exceptions
1709 inner_exc = (MonoException *) inner_exc->inner_ex;
1712 out->num_exceptions = exc_index;
1716 static void
1717 mono_summarize_managed_stack (MonoThreadSummary *out)
1719 MonoSummarizeUserData data;
1720 memset (&data, 0, sizeof (MonoSummarizeUserData));
1721 data.max_frames = MONO_MAX_SUMMARY_FRAMES;
1722 data.num_frames = 0;
1723 data.frames = out->managed_frames;
1724 data.hashes = &out->hashes;
1726 // FIXME: collect stack pointer for both and sort frames by SP
1727 // so people can see relative ordering of both managed and unmanaged frames.
1730 // Summarize managed stack
1732 mono_walk_stack_full (summarize_frame, out->ctx, out->domain, out->jit_tls, out->lmf, MONO_UNWIND_LOOKUP_IL_OFFSET, &data, TRUE);
1733 out->num_managed_frames = data.num_frames;
1735 if (data.error != NULL)
1736 out->error_msg = data.error;
1737 out->is_managed = (out->num_managed_frames != 0);
1740 // Always runs on the dumped thread
1741 static void
1742 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1744 MONO_ARCH_CONTEXT_DEF
1746 // Summarize unmanaged stack
1748 #ifdef HAVE_BACKTRACE_SYMBOLS
1749 intptr_t frame_ips [MONO_MAX_SUMMARY_FRAMES];
1751 out->num_unmanaged_frames = backtrace ((void **)frame_ips, MONO_MAX_SUMMARY_FRAMES);
1753 for (int i =0; i < out->num_unmanaged_frames; ++i) {
1754 intptr_t ip = frame_ips [i];
1755 MonoFrameSummary *frame = &out->unmanaged_frames [i];
1756 const char* module_buf = frame->unmanaged_data.module;
1757 int success = mono_get_portable_ip (ip, &frame->unmanaged_data.ip, &frame->unmanaged_data.offset, &module_buf, (char *) frame->str_descr);
1759 /* attempt to look up any managed method at that ip */
1760 /* TODO: Trampolines - follow examples from mono_print_method_from_ip() */
1762 MonoJitInfo *ji;
1763 MonoDomain *domain = mono_domain_get ();
1764 MonoDomain *target_domain;
1765 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
1766 if (ji) {
1767 frame->is_managed = TRUE;
1768 if (!ji->async && !ji->is_trampoline) {
1769 MonoMethod *method = jinfo_get_method (ji);
1770 fill_frame_managed_info (frame, method);
1771 #ifndef MONO_PRIVATE_CRASHES
1772 frame->managed_data.name = method->name;
1773 #endif
1777 if (!success && !ji) {
1778 frame->unmanaged_data.ip = ip;
1779 continue;
1782 if (out->unmanaged_frames [i].str_descr [0] != '\0')
1783 out->unmanaged_frames [i].unmanaged_data.has_name = TRUE;
1785 #endif
1787 out->lmf = mono_get_lmf ();
1789 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1790 out->info_addr = (intptr_t) thread;
1791 out->jit_tls = thread->jit_data;
1792 out->domain = mono_domain_get ();
1794 if (!out->ctx) {
1795 out->ctx = &out->ctx_mem;
1796 mono_arch_flush_register_windows ();
1797 MONO_INIT_CONTEXT_FROM_FUNC (out->ctx, mono_summarize_unmanaged_stack);
1800 return;
1802 #endif
1805 MonoBoolean
1806 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
1807 MonoReflectionMethod **method,
1808 gint32 *iloffset, gint32 *native_offset,
1809 MonoString **file, gint32 *line, gint32 *column)
1811 ERROR_DECL (error);
1812 MonoDomain *domain = mono_domain_get ();
1813 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1814 MonoLMF *lmf = mono_get_lmf ();
1815 MonoJitInfo *ji = NULL;
1816 MonoContext ctx, new_ctx;
1817 MonoDebugSourceLocation *location;
1818 MonoMethod *jmethod = NULL, *actual_method;
1819 StackFrameInfo frame;
1820 gboolean res;
1821 Unwinder unwinder;
1822 int il_offset = -1;
1824 MONO_ARCH_CONTEXT_DEF;
1826 g_assert (skip >= 0);
1828 if (mono_llvm_only) {
1829 GSList *l, *ips;
1830 MonoDomain *frame_domain;
1831 guint8 *frame_ip = NULL;
1833 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1834 jmethod = NULL;
1835 ips = get_unwind_backtrace ();
1836 for (l = ips; l && skip >= 0; l = l->next) {
1837 guint8 *ip = (guint8*)l->data;
1839 frame_ip = ip;
1841 ji = mini_jit_info_table_find (mono_domain_get (), ip, &frame_domain);
1842 if (!ji || ji->is_trampoline)
1843 continue;
1845 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1846 jmethod = jinfo_get_method (ji);
1847 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1848 continue;
1849 skip--;
1851 g_slist_free (ips);
1852 if (!jmethod || !l)
1853 return FALSE;
1854 /* No way to resolve generic instances */
1855 actual_method = jmethod;
1856 *native_offset = frame_ip - (guint8*)ji->code_start;
1857 } else {
1858 mono_arch_flush_register_windows ();
1859 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
1861 unwinder_init (&unwinder);
1863 new_ctx = ctx;
1864 do {
1865 ctx = new_ctx;
1866 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1867 if (!res)
1868 return FALSE;
1869 switch (frame.type) {
1870 case FRAME_TYPE_MANAGED_TO_NATIVE:
1871 case FRAME_TYPE_DEBUGGER_INVOKE:
1872 case FRAME_TYPE_TRAMPOLINE:
1873 case FRAME_TYPE_INTERP_TO_MANAGED:
1874 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
1875 continue;
1876 case FRAME_TYPE_INTERP:
1877 case FRAME_TYPE_MANAGED:
1878 ji = frame.ji;
1879 *native_offset = frame.native_offset;
1881 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1882 jmethod = jinfo_get_method (ji);
1883 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1884 continue;
1885 skip--;
1886 break;
1887 default:
1888 g_assert_not_reached ();
1890 } while (skip >= 0);
1892 if (frame.type == FRAME_TYPE_INTERP) {
1893 jmethod = frame.method;
1894 actual_method = frame.actual_method;
1895 } else {
1896 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
1900 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, error);
1901 if (!is_ok (error)) {
1902 mono_error_set_pending_exception (error);
1903 return FALSE;
1905 mono_gc_wbarrier_generic_store_internal (method, (MonoObject*) rm);
1907 if (il_offset != -1) {
1908 location = mono_debug_lookup_source_location_by_il (jmethod, il_offset, domain);
1909 } else {
1910 location = mono_debug_lookup_source_location (jmethod, *native_offset, domain);
1912 if (location)
1913 *iloffset = location->il_offset;
1914 else
1915 *iloffset = 0;
1917 if (need_file_info) {
1918 if (location) {
1919 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1920 if (!is_ok (error)) {
1921 mono_error_set_pending_exception (error);
1922 return FALSE;
1924 mono_gc_wbarrier_generic_store_internal (file, (MonoObject*)filename);
1925 *line = location->row;
1926 *column = location->column;
1927 } else {
1928 *file = NULL;
1929 *line = *column = 0;
1933 mono_debug_free_source_location (location);
1935 return TRUE;
1938 static MonoClass*
1939 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1941 ERROR_DECL (error);
1942 MonoClass *catch_class = ei->data.catch_class;
1943 MonoType *inflated_type;
1944 MonoGenericContext context;
1946 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1947 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
1948 return NULL;
1950 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1951 return catch_class;
1952 context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1954 /* FIXME: we shouldn't inflate but instead put the
1955 type in the rgctx and fetch it from there. It
1956 might be a good idea to do this lazily, i.e. only
1957 when the exception is actually thrown, so as not to
1958 waste space for exception clauses which might never
1959 be encountered. */
1960 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
1961 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1963 catch_class = mono_class_from_mono_type_internal (inflated_type);
1964 mono_metadata_free_type (inflated_type);
1966 return catch_class;
1970 * mini_jit_info_table_find_ext:
1972 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1973 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1974 * OUT_DOMAIN if it is not NULL.
1976 MonoJitInfo*
1977 mini_jit_info_table_find_ext (MonoDomain *domain, gpointer addr, gboolean allow_trampolines, MonoDomain **out_domain)
1979 MonoJitInfo *ji;
1980 MonoInternalThread *t = mono_thread_internal_current ();
1981 gpointer *refs;
1983 if (out_domain)
1984 *out_domain = NULL;
1986 ji = mono_jit_info_table_find_internal (domain, addr, TRUE, allow_trampolines);
1987 if (ji) {
1988 if (out_domain)
1989 *out_domain = domain;
1990 return ji;
1993 /* maybe it is shared code, so we also search in the root domain */
1994 if (domain != mono_get_root_domain ()) {
1995 ji = mono_jit_info_table_find_internal (mono_get_root_domain (), addr, TRUE, allow_trampolines);
1996 if (ji) {
1997 if (out_domain)
1998 *out_domain = mono_get_root_domain ();
1999 return ji;
2003 if (!t)
2004 return NULL;
2006 refs = (gpointer *)((t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL);
2007 for (; refs && *refs; refs++) {
2008 if (*refs != domain && *refs != mono_get_root_domain ()) {
2009 ji = mono_jit_info_table_find_internal ((MonoDomain*) *refs, addr, TRUE, allow_trampolines);
2010 if (ji) {
2011 if (out_domain)
2012 *out_domain = (MonoDomain*) *refs;
2013 return ji;
2018 return NULL;
2021 MonoJitInfo*
2022 mini_jit_info_table_find (MonoDomain *domain, gpointer addr, MonoDomain **out_domain)
2024 return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain);
2027 /* Class lazy loading functions */
2028 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
2031 * wrap_non_exception_throws:
2033 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
2034 * WrapNonExceptionThrows flag set.
2036 static gboolean
2037 wrap_non_exception_throws (MonoMethod *m)
2039 ERROR_DECL (error);
2040 MonoAssembly *ass = m_class_get_image (m->klass)->assembly;
2041 MonoCustomAttrInfo* attrs;
2042 MonoClass *klass;
2043 int i;
2044 gboolean val = FALSE;
2046 if (m->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
2047 MonoDynamicMethod *dm = (MonoDynamicMethod *)m;
2048 if (dm->assembly)
2049 ass = dm->assembly;
2051 g_assert (ass);
2052 if (ass->wrap_non_exception_throws_inited)
2053 return ass->wrap_non_exception_throws;
2055 klass = mono_class_get_runtime_compat_attr_class ();
2057 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, error);
2058 mono_error_cleanup (error); /* FIXME don't swallow the error */
2059 if (attrs) {
2060 for (i = 0; i < attrs->num_attrs; ++i) {
2061 MonoCustomAttrEntry *attr = &attrs->attrs [i];
2062 const gchar *p;
2063 int num_named, named_type, name_len;
2064 char *name;
2066 if (!attr->ctor || attr->ctor->klass != klass)
2067 continue;
2068 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2069 p = (const char*)attr->data;
2070 g_assert (read16 (p) == 0x0001);
2071 p += 2;
2072 num_named = read16 (p);
2073 if (num_named != 1)
2074 continue;
2075 p += 2;
2076 named_type = *p;
2077 p ++;
2078 /* data_type = *p; */
2079 p ++;
2080 /* Property */
2081 if (named_type != 0x54)
2082 continue;
2083 name_len = mono_metadata_decode_blob_size (p, &p);
2084 name = (char *)g_malloc (name_len + 1);
2085 memcpy (name, p, name_len);
2086 name [name_len] = 0;
2087 p += name_len;
2088 g_assert (!strcmp (name, "WrapNonExceptionThrows"));
2089 g_free (name);
2090 /* The value is a BOOLEAN */
2091 val = *p;
2093 mono_custom_attrs_free (attrs);
2096 ass->wrap_non_exception_throws = val;
2097 mono_memory_barrier ();
2098 ass->wrap_non_exception_throws_inited = TRUE;
2100 return val;
2103 #define MAX_UNMANAGED_BACKTRACE 128
2104 static MonoArray*
2105 build_native_trace (MonoError *error)
2107 error_init (error);
2108 /* This puppy only makes sense on mobile, IOW, ARM. */
2109 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2110 MonoArray *res;
2111 void *native_trace [MAX_UNMANAGED_BACKTRACE];
2112 int size = -1;
2113 MONO_ENTER_GC_SAFE;
2114 size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE);
2115 MONO_EXIT_GC_SAFE;
2116 int i;
2118 if (!size)
2119 return NULL;
2120 res = mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, size, error);
2121 return_val_if_nok (error, NULL);
2123 for (i = 0; i < size; i++)
2124 mono_array_set_internal (res, gpointer, i, native_trace [i]);
2125 return res;
2126 #else
2127 return NULL;
2128 #endif
2131 static void
2132 remove_wrappers_from_trace (GList **trace_ips_p)
2134 GList *trace_ips = *trace_ips_p;
2135 GList *p = trace_ips;
2137 /* jit info, generic info, ip */
2138 while (p) {
2139 MonoJitInfo *jinfo = (MonoJitInfo*) p->data;
2140 GList *next_p = p->next->next->next;
2141 /* FIXME Maybe remove more wrapper types */
2142 if (jinfo->d.method->wrapper_type == MONO_WRAPPER_OTHER) {
2143 trace_ips = g_list_delete_link (trace_ips, p->next->next);
2144 trace_ips = g_list_delete_link (trace_ips, p->next);
2145 trace_ips = g_list_delete_link (trace_ips, p);
2147 p = next_p;
2150 *trace_ips_p = trace_ips;
2153 /* This can be called more than once on a MonoException. */
2154 static void
2155 setup_stack_trace (MonoException *mono_ex, GSList **dynamic_methods, GList *trace_ips, gboolean remove_wrappers)
2157 if (mono_ex) {
2158 GList *trace_ips_copy = g_list_copy (trace_ips);
2159 if (remove_wrappers)
2160 remove_wrappers_from_trace (&trace_ips_copy);
2161 trace_ips_copy = g_list_reverse (trace_ips_copy);
2162 ERROR_DECL (error);
2163 MonoArray *ips_arr = mono_glist_to_array (trace_ips_copy, mono_defaults.int_class, error);
2164 mono_error_assert_ok (error);
2165 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
2166 MONO_OBJECT_SETREF_INTERNAL (mono_ex, native_trace_ips, build_native_trace (error));
2167 mono_error_assert_ok (error);
2168 if (*dynamic_methods) {
2169 /* These methods could go away anytime, so save a reference to them in the exception object */
2170 GSList *l;
2171 MonoMList *list = (MonoMList*)mono_ex->dynamic_methods;
2173 for (l = *dynamic_methods; l; l = l->next) {
2174 guint32 dis_link;
2175 MonoDomain *domain = mono_domain_get ();
2177 if (domain->method_to_dyn_method) {
2178 mono_domain_lock (domain);
2179 dis_link = (guint32)(size_t)g_hash_table_lookup (domain->method_to_dyn_method, l->data);
2180 mono_domain_unlock (domain);
2181 if (dis_link) {
2182 MonoObject *o = mono_gchandle_get_target_internal (dis_link);
2183 if (o) {
2184 list = mono_mlist_prepend_checked (list, o, error);
2185 mono_error_assert_ok (error);
2191 MONO_OBJECT_SETREF_INTERNAL (mono_ex, dynamic_methods, list);
2193 g_slist_free (*dynamic_methods);
2194 *dynamic_methods = NULL;
2197 g_list_free (trace_ips_copy);
2201 typedef enum {
2202 MONO_FIRST_PASS_UNHANDLED,
2203 MONO_FIRST_PASS_CALLBACK_TO_NATIVE,
2204 MONO_FIRST_PASS_HANDLED,
2205 } MonoFirstPassResult;
2208 * handle_exception_first_pass:
2210 * The first pass of exception handling. Unwind the stack until a catch
2211 * clause which can catch OBJ is found. Store the index of the filter clause
2212 * which caught the exception into OUT_FILTER_IDX. Return
2213 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2214 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2215 * wrapper and an exception handling callback is installed (in which case
2216 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2218 static MonoFirstPassResult
2219 handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception, StackFrameInfo *catch_frame, gboolean *last_mono_wrapper_runtime_invoke)
2221 ERROR_DECL (error);
2222 MonoDomain *domain = mono_domain_get ();
2223 MonoJitInfo *ji = NULL;
2224 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2225 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2226 MonoLMF *lmf = mono_get_lmf ();
2227 GList *trace_ips = NULL;
2228 GSList *dynamic_methods = NULL;
2229 MonoException *mono_ex;
2230 gboolean stack_overflow = FALSE;
2231 MonoContext initial_ctx;
2232 MonoMethod *method;
2233 int frame_count = 0;
2234 gint32 filter_idx;
2235 int i;
2236 MonoObject *ex_obj;
2237 Unwinder unwinder;
2238 gboolean in_interp;
2240 MonoFirstPassResult result = MONO_FIRST_PASS_UNHANDLED;
2242 g_assert (ctx != NULL);
2243 *last_mono_wrapper_runtime_invoke = TRUE;
2244 if (obj == (MonoObject *)domain->stack_overflow_ex)
2245 stack_overflow = TRUE;
2247 mono_ex = (MonoException*)obj;
2248 MonoArray *initial_trace_ips = mono_ex->trace_ips;
2249 if (initial_trace_ips) {
2250 int len = mono_array_length_internal (initial_trace_ips) / TRACE_IP_ENTRY_SIZE;
2252 // If we catch in managed/non-wrapper, we don't save the catching frame
2253 if (!mono_ex->caught_in_unmanaged)
2254 len -= 1;
2256 for (i = 0; i < len; i++) {
2257 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
2258 gpointer p = mono_array_get_internal (initial_trace_ips, gpointer, (i * TRACE_IP_ENTRY_SIZE) + j);
2259 trace_ips = g_list_prepend (trace_ips, p);
2264 // Reset the state because we're making it be caught somewhere
2265 if (mono_ex->caught_in_unmanaged)
2266 MONO_OBJECT_SETREF_INTERNAL (mono_ex, caught_in_unmanaged, 0);
2268 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2269 mono_error_assert_ok (error);
2270 mono_ex = NULL;
2273 if (!call_filter)
2274 call_filter = (int (*) (MonoContext *, void *))mono_get_call_filter ();
2276 g_assert (jit_tls->end_of_stack);
2277 g_assert (jit_tls->abort_func);
2279 if (out_filter_idx)
2280 *out_filter_idx = -1;
2281 if (out_ji)
2282 *out_ji = NULL;
2283 if (out_prev_ji)
2284 *out_prev_ji = NULL;
2285 filter_idx = 0;
2286 initial_ctx = *ctx;
2288 unwinder_init (&unwinder);
2290 while (1) {
2291 MonoContext new_ctx;
2292 guint32 free_stack;
2293 int clause_index_start = 0;
2294 gboolean unwind_res = TRUE;
2296 StackFrameInfo frame;
2298 if (out_prev_ji)
2299 *out_prev_ji = ji;
2301 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2302 if (!unwind_res) {
2303 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, FALSE);
2304 g_list_free (trace_ips);
2305 return result;
2308 switch (frame.type) {
2309 case FRAME_TYPE_DEBUGGER_INVOKE:
2310 case FRAME_TYPE_MANAGED_TO_NATIVE:
2311 case FRAME_TYPE_TRAMPOLINE:
2312 case FRAME_TYPE_INTERP_TO_MANAGED:
2313 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2314 *ctx = new_ctx;
2315 continue;
2316 case FRAME_TYPE_INTERP:
2317 case FRAME_TYPE_MANAGED:
2318 break;
2319 default:
2320 g_assert_not_reached ();
2321 break;
2324 in_interp = frame.type == FRAME_TYPE_INTERP;
2325 ji = frame.ji;
2327 gpointer ip;
2328 if (in_interp)
2329 ip = (guint8*)ji->code_start + frame.native_offset;
2330 else
2331 ip = MONO_CONTEXT_GET_IP (ctx);
2333 frame_count ++;
2334 method = jinfo_get_method (ji);
2335 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2337 if (mini_debug_options.reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2338 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2339 "The native frame called the managed method:\n%s\n",
2340 mono_method_full_name (method, TRUE));
2343 if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
2344 // avoid giant stack traces during a stack overflow
2345 if (frame_count < 1000) {
2346 trace_ips = g_list_prepend (trace_ips, ip);
2347 trace_ips = g_list_prepend (trace_ips, get_generic_info_from_stack_frame (ji, ctx));
2348 trace_ips = g_list_prepend (trace_ips, ji);
2352 if (method->dynamic)
2353 dynamic_methods = g_slist_prepend (dynamic_methods, method);
2355 if (stack_overflow) {
2356 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2357 } else {
2358 free_stack = 0xffffff;
2361 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && ftnptr_eh_callback) {
2362 result = MONO_FIRST_PASS_CALLBACK_TO_NATIVE;
2366 for (i = clause_index_start; i < ji->num_clauses; i++) {
2367 MonoJitExceptionInfo *ei = &ji->clauses [i];
2368 gboolean filtered = FALSE;
2371 * During stack overflow, wait till the unwinding frees some stack
2372 * space before running handlers/finalizers.
2374 if (free_stack <= (64 * 1024))
2375 continue;
2377 if (is_address_protected (ji, ei, ip)) {
2378 /* catch block */
2379 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2382 * Have to unwrap RuntimeWrappedExceptions if the
2383 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2385 if (non_exception && !wrap_non_exception_throws (method))
2386 ex_obj = non_exception;
2387 else
2388 ex_obj = obj;
2390 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2391 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, FALSE);
2393 #ifndef DISABLE_PERFCOUNTERS
2394 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_filters);
2395 #endif
2397 if (!ji->is_interp) {
2398 #ifndef MONO_CROSS_COMPILE
2399 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2400 if (ji->from_llvm)
2401 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2402 else
2403 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2404 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2405 #else
2406 g_assert (!ji->from_llvm);
2407 /* store the exception object in bp + ei->exvar_offset */
2408 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2409 #endif
2410 #endif
2412 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2414 * Pass the original il clause index to the landing pad so it can
2415 * branch to the landing pad associated with the il clause.
2416 * This is needed because llvm compiled code assumes that the EH
2417 * code always branches to the innermost landing pad.
2419 if (ji->from_llvm)
2420 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2421 #endif
2424 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex, ctx, &initial_ctx);
2426 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2427 jit_tls->orig_ex_ctx_set = TRUE;
2428 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2429 jit_tls->orig_ex_ctx_set = FALSE;
2432 if (ji->is_interp) {
2433 /* The filter ends where the exception handler starts */
2434 filtered = mini_get_interp_callbacks ()->run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter, ei->handler_start);
2435 } else {
2436 filtered = call_filter (ctx, ei->data.filter);
2438 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex, ctx, &initial_ctx);
2439 if (filtered && out_filter_idx)
2440 *out_filter_idx = filter_idx;
2441 if (out_ji)
2442 *out_ji = ji;
2443 filter_idx ++;
2445 if (filtered) {
2446 g_list_free (trace_ips);
2447 /* mono_debugger_agent_handle_exception () needs this */
2448 mini_set_abort_threshold (&frame);
2449 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2450 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
2451 *catch_frame = frame;
2452 result = MONO_FIRST_PASS_HANDLED;
2453 return result;
2457 ERROR_DECL (isinst_error); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2458 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, error)) {
2459 /* runtime invokes catch even unhandled exceptions */
2460 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE);
2461 g_list_free (trace_ips);
2463 if (out_ji)
2464 *out_ji = ji;
2466 /* mono_debugger_agent_handle_exception () needs this */
2467 if (!in_interp)
2468 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2469 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
2470 *catch_frame = frame;
2471 result = MONO_FIRST_PASS_HANDLED;
2472 if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2473 //try to find threadpool_perform_wait_callback_method
2474 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &new_ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2475 while (unwind_res) {
2476 if (frame.ji && !frame.ji->is_trampoline && jinfo_get_method (frame.ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2477 *last_mono_wrapper_runtime_invoke = FALSE;
2478 break;
2480 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &new_ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2483 return result;
2485 mono_error_cleanup (isinst_error);
2489 *ctx = new_ctx;
2492 g_assert_not_reached ();
2496 * We implement delaying of aborts when in finally blocks by reusing the
2497 * abort protected block mechanism. The problem is that when throwing an
2498 * exception in a finally block we don't get to exit the protected block.
2499 * We exit it here when unwinding. Given that the order of the clauses
2500 * in the jit info is from inner clauses to the outer clauses, when we
2501 * want to exit the finally blocks inner to the clause that handles the
2502 * exception, we need to search up to its index.
2504 * FIXME We should do this inside interp, but with mixed mode we can
2505 * resume directly, without giving control back to the interp.
2507 static void
2508 interp_exit_finally_abort_blocks (MonoJitInfo *ji, int start_clause, int end_clause, gpointer ip)
2510 int i;
2511 for (i = start_clause; i < end_clause; i++) {
2512 MonoJitExceptionInfo *ei = &ji->clauses [i];
2513 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY &&
2514 ip >= ei->handler_start &&
2515 ip < ei->data.handler_end) {
2516 mono_threads_end_abort_protected_block ();
2521 static MonoException *
2522 mono_get_exception_runtime_wrapped_checked (MonoObject *wrapped_exception_raw, MonoError *error)
2524 HANDLE_FUNCTION_ENTER ();
2525 MONO_HANDLE_DCL (MonoObject, wrapped_exception);
2526 MonoExceptionHandle ret = mono_get_exception_runtime_wrapped_handle (wrapped_exception, error);
2527 HANDLE_FUNCTION_RETURN_OBJ (ret);
2531 * mono_handle_exception_internal:
2532 * \param ctx saved processor state
2533 * \param obj the exception object
2534 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2536 static gboolean
2537 mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji)
2539 ERROR_DECL (error);
2540 MonoDomain *domain = mono_domain_get ();
2541 MonoJitInfo *ji, *prev_ji;
2542 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2543 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2544 MonoLMF *lmf = mono_get_lmf ();
2545 MonoException *mono_ex;
2546 gboolean stack_overflow = FALSE;
2547 MonoContext initial_ctx;
2548 MonoMethod *method;
2549 int frame_count = 0;
2550 gint32 filter_idx, first_filter_idx = 0;
2551 int i;
2552 MonoObject *ex_obj = NULL;
2553 MonoObject *non_exception = NULL;
2554 Unwinder unwinder;
2555 gboolean in_interp;
2556 gboolean is_caught_unmanaged = FALSE;
2557 gboolean last_mono_wrapper_runtime_invoke = TRUE;
2559 g_assert (ctx != NULL);
2560 if (!obj) {
2561 MonoException *ex = mono_get_exception_null_reference ();
2562 MonoString *msg = mono_string_new_checked (domain, "Object reference not set to an instance of an object", error);
2563 mono_error_assert_ok (error);
2564 MONO_OBJECT_SETREF_INTERNAL (ex, message, msg);
2565 obj = (MonoObject *)ex;
2569 * Allocate a new exception object instead of the preconstructed ones.
2571 if (obj == (MonoObject *)domain->stack_overflow_ex) {
2573 * It is not a good idea to try and put even more pressure on the little stack available.
2574 * obj = mono_get_exception_stack_overflow ();
2576 stack_overflow = TRUE;
2578 else if (obj == (MonoObject *)domain->null_reference_ex) {
2579 obj = (MonoObject *)mono_get_exception_null_reference ();
2582 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2583 mono_error_assert_ok (error);
2584 non_exception = obj;
2585 obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, error);
2586 mono_error_assert_ok (error);
2589 mono_ex = (MonoException*)obj;
2591 if (mini_debug_options.suspend_on_exception) {
2592 mono_runtime_printf_err ("Exception thrown, suspending...");
2593 while (1)
2597 if (mono_ex->caught_in_unmanaged)
2598 is_caught_unmanaged = TRUE;
2601 if (mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2602 mono_ex = (MonoException*)obj;
2603 } else {
2604 mono_error_assert_ok (error);
2605 mono_ex = NULL;
2608 if (mono_ex && jit_tls->class_cast_from) {
2609 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "InvalidCastException")) {
2610 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
2611 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
2612 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
2613 mono_ex->message = mono_string_new_checked (domain, msg, error);
2614 g_free (from_name);
2615 g_free (to_name);
2616 if (!is_ok (error)) {
2617 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg);
2618 mono_error_assert_ok (error);
2620 g_free (msg);
2622 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "ArrayTypeMismatchException")) {
2623 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
2624 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
2625 char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
2626 mono_ex->message = mono_string_new_checked (domain, msg, error);
2627 g_free (from_name);
2628 g_free (to_name);
2629 if (!is_ok (error)) {
2630 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg);
2631 mono_error_assert_ok (error);
2633 g_free (msg);
2637 if (!call_filter)
2638 call_filter = (int (*)(MonoContext *, void*))mono_get_call_filter ();
2640 g_assert (jit_tls->end_of_stack);
2641 g_assert (jit_tls->abort_func);
2644 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2645 * end up being TRUE on any code path.
2647 memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
2649 if (!resume) {
2650 MonoContext ctx_cp = *ctx;
2651 if (mono_trace_is_enabled ()) {
2652 ERROR_DECL (error);
2653 MonoMethod *system_exception_get_message = mono_class_get_method_from_name_checked (mono_defaults.exception_class, "get_Message", 0, 0, error);
2654 mono_error_cleanup (error);
2655 error_init (error);
2656 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method_internal (obj, system_exception_get_message);
2657 MonoObject *message;
2658 const char *type_name = m_class_get_name (mono_object_class (mono_ex));
2659 char *msg = NULL;
2660 if (get_message == NULL) {
2661 message = NULL;
2662 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
2663 message = NULL;
2664 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
2665 } else {
2666 MonoObject *exc = NULL;
2667 message = mono_runtime_try_invoke (get_message, obj, NULL, &exc, error);
2668 g_assert (exc == NULL);
2669 mono_error_assert_ok (error);
2671 if (msg == NULL) {
2672 if (message) {
2673 msg = mono_string_to_utf8_checked_internal ((MonoString *) message, error);
2674 if (!is_ok (error)) {
2675 mono_error_cleanup (error);
2676 msg = g_strdup ("(error while display System.Exception.Message property)");
2678 } else {
2679 msg = g_strdup ("(System.Exception.Message property not available)");
2682 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);
2683 g_free (msg);
2684 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
2685 mono_print_thread_dump_from_ctx (ctx);
2687 jit_tls->orig_ex_ctx_set = TRUE;
2688 MONO_PROFILER_RAISE (exception_throw, (obj));
2689 jit_tls->orig_ex_ctx_set = FALSE;
2691 StackFrameInfo catch_frame;
2692 MonoFirstPassResult res;
2693 res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame, &last_mono_wrapper_runtime_invoke);
2695 if (res == MONO_FIRST_PASS_UNHANDLED) {
2696 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2697 /* Reached the top interpreted frames, but there might be native frames above us */
2698 throw_exception (obj, TRUE);
2699 g_assert_not_reached ();
2701 if (mini_debug_options.break_on_exc)
2702 G_BREAKPOINT ();
2703 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2705 if (mini_debug_options.suspend_on_unhandled && mono_object_class (obj) != mono_defaults.threadabortexception_class) {
2706 mono_runtime_printf_err ("Unhandled exception, suspending...");
2707 while (1)
2711 // FIXME: This runs managed code so it might cause another stack overflow when
2712 // we are handling a stack overflow
2713 mini_set_abort_threshold (&catch_frame);
2714 mono_unhandled_exception_internal (obj);
2715 } else {
2716 gboolean unhandled = FALSE;
2719 * The exceptions caught by the mono_runtime_invoke_checked () calls
2720 * in the threadpool needs to be treated as unhandled (#669836).
2722 * FIXME: The check below is hackish, but its hard to distinguish
2723 * these runtime invoke calls from others in the runtime.
2725 #ifndef ENABLE_NETCORE
2726 if (ji && jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2727 if (prev_ji && jinfo_get_method (prev_ji) == mono_defaults.threadpool_perform_wait_callback_method)
2728 unhandled = TRUE;
2730 #endif
2732 if (unhandled)
2733 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2734 else if (!ji || (jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
2735 if (last_mono_wrapper_runtime_invoke && mono_thread_get_main () && (mono_thread_internal_current () == mono_thread_get_main ()->internal_thread))
2736 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2737 else
2738 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2740 else if (res != MONO_FIRST_PASS_CALLBACK_TO_NATIVE)
2741 if (!is_caught_unmanaged)
2742 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2746 if (out_ji)
2747 *out_ji = NULL;
2748 filter_idx = 0;
2749 initial_ctx = *ctx;
2751 unwinder_init (&unwinder);
2753 while (1) {
2754 MonoContext new_ctx;
2755 guint32 free_stack;
2756 int clause_index_start = 0;
2757 gboolean unwind_res = TRUE;
2758 StackFrameInfo frame;
2759 gpointer ip;
2761 if (resume) {
2762 resume = FALSE;
2763 ji = jit_tls->resume_state.ji;
2764 new_ctx = jit_tls->resume_state.new_ctx;
2765 clause_index_start = jit_tls->resume_state.clause_index;
2766 lmf = jit_tls->resume_state.lmf;
2767 first_filter_idx = jit_tls->resume_state.first_filter_idx;
2768 filter_idx = jit_tls->resume_state.filter_idx;
2769 in_interp = FALSE;
2770 } else {
2771 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2772 if (!unwind_res) {
2773 *(mono_get_lmf_addr ()) = lmf;
2775 jit_tls->abort_func (obj);
2776 g_assert_not_reached ();
2778 switch (frame.type) {
2779 case FRAME_TYPE_DEBUGGER_INVOKE:
2780 case FRAME_TYPE_MANAGED_TO_NATIVE:
2781 case FRAME_TYPE_TRAMPOLINE:
2782 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2783 *ctx = new_ctx;
2784 continue;
2785 case FRAME_TYPE_INTERP_TO_MANAGED:
2786 continue;
2787 case FRAME_TYPE_INTERP:
2788 case FRAME_TYPE_MANAGED:
2789 break;
2790 default:
2791 g_assert_not_reached ();
2792 break;
2794 in_interp = frame.type == FRAME_TYPE_INTERP;
2795 ji = frame.ji;
2798 if (in_interp)
2799 ip = (guint8*)ji->code_start + frame.native_offset;
2800 else
2801 ip = MONO_CONTEXT_GET_IP (ctx);
2803 method = jinfo_get_method (ji);
2804 frame_count ++;
2805 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2807 if (stack_overflow) {
2808 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2809 } else {
2810 free_stack = 0xffffff;
2813 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && ftnptr_eh_callback) {
2814 guint32 handle = mono_gchandle_new_internal (obj, FALSE);
2815 MONO_STACKDATA (stackptr);
2817 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr);
2818 mono_set_lmf (lmf);
2819 ftnptr_eh_callback (handle);
2820 g_error ("Did not expect ftnptr_eh_callback to return.");
2823 for (i = clause_index_start; i < ji->num_clauses; i++) {
2824 MonoJitExceptionInfo *ei = &ji->clauses [i];
2825 gboolean filtered = FALSE;
2828 * During stack overflow, wait till the unwinding frees some stack
2829 * space before running handlers/finalizers.
2831 if (free_stack <= (64 * 1024))
2832 continue;
2834 if (is_address_protected (ji, ei, ip)) {
2835 /* catch block */
2836 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2839 * Have to unwrap RuntimeWrappedExceptions if the
2840 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2842 if (non_exception && !wrap_non_exception_throws (method))
2843 ex_obj = non_exception;
2844 else
2845 ex_obj = obj;
2847 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
2848 #ifndef MONO_CROSS_COMPILE
2849 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2850 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2851 #else
2852 g_assert (!ji->from_llvm);
2853 /* store the exception object in bp + ei->exvar_offset */
2854 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2855 #endif
2856 #endif
2859 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2860 if (ji->from_llvm)
2861 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2862 #endif
2864 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2866 * Filter clauses should only be run in the
2867 * first pass of exception handling.
2869 filtered = (filter_idx == first_filter_idx);
2870 filter_idx ++;
2873 error_init (error);
2874 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
2875 mono_object_isinst_checked (ex_obj, catch_class, error)) || filtered) {
2877 * This guards against the situation that we abort a thread that is executing a finally clause
2878 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2879 * check for this situation here and resume interruption if we are below the guarded block.
2881 if (G_UNLIKELY (jit_tls->handler_block)) {
2882 gboolean is_outside = FALSE;
2883 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
2884 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
2885 //FIXME make this stack direction aware
2887 if (catch_bp > prot_bp) {
2888 is_outside = TRUE;
2889 } else if (catch_bp == prot_bp) {
2890 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2891 * So we check if the catch handler_start is protected by the guarded handler protected region
2893 * Assumptions:
2894 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2895 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2896 * There aren't any further finally/fault handler blocks down the stack over this exception.
2897 * This must be ensured by the code that installs the guard trampoline.
2899 g_assert (ji == mini_jit_info_table_find (domain, (char *)MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
2901 if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
2902 is_outside = TRUE;
2905 if (is_outside) {
2906 jit_tls->handler_block = NULL;
2907 mono_thread_resume_interruption (TRUE); /*We ignore the exception here, it will be raised later*/
2911 if (mono_trace_is_enabled () && mono_trace_eval (method))
2912 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2915 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2916 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2917 * clause. Since we specifically want to indicate that we're executing the
2918 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2919 * instead of ei->flags.
2921 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2922 jit_tls->orig_ex_ctx_set = TRUE;
2923 MONO_PROFILER_RAISE (exception_clause, (method, i, MONO_EXCEPTION_CLAUSE_NONE, ex_obj));
2924 jit_tls->orig_ex_ctx_set = FALSE;
2927 mini_set_abort_threshold (&frame);
2929 if (in_interp) {
2930 interp_exit_finally_abort_blocks (ji, clause_index_start, i, ip);
2932 * ctx->pc points into the interpreter, after the call which transitioned to
2933 * JITted code. Store the unwind state into the
2934 * interpeter state, then resume, the interpreter will unwind itself until
2935 * it reaches the target frame and will continue execution from there.
2936 * The resuming is kinda hackish, from the native code standpoint, it looks
2937 * like the call which transitioned to JITted code has succeeded, but the
2938 * return value register etc. is not set, so we have to be careful.
2940 mini_get_interp_callbacks ()->set_resume_state (jit_tls, mono_ex, ei, frame.interp_frame, ei->handler_start);
2941 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2942 /* ip == 0 means an interpreter frame */
2943 if (MONO_CONTEXT_GET_IP (ctx) != 0)
2944 mono_arch_undo_ip_adjustment (ctx);
2945 } else {
2946 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2948 mono_set_lmf (lmf);
2949 #ifndef DISABLE_PERFCOUNTERS
2950 mono_atomic_fetch_add_i32 (&mono_perfcounters->exceptions_depth, frame_count);
2951 #endif
2952 if (obj == (MonoObject *)domain->stack_overflow_ex)
2953 jit_tls->handling_stack_ovf = FALSE;
2955 return 0;
2957 mono_error_cleanup (error);
2958 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
2959 if (mono_trace_is_enabled () && mono_trace_eval (method))
2960 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2962 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2963 jit_tls->orig_ex_ctx_set = TRUE;
2964 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2965 jit_tls->orig_ex_ctx_set = FALSE;
2968 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2969 if (mono_trace_is_enabled () && mono_trace_eval (method))
2970 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2972 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2973 jit_tls->orig_ex_ctx_set = TRUE;
2974 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2975 jit_tls->orig_ex_ctx_set = FALSE;
2978 #ifndef DISABLE_PERFCOUNTERS
2979 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_finallys);
2980 #endif
2982 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2983 mono_set_lmf (lmf);
2984 if (ji->from_llvm) {
2986 * LLVM compiled finally handlers follow the design
2987 * of the c++ ehabi, i.e. they call a resume function
2988 * at the end instead of returning to the caller.
2989 * So save the exception handling state,
2990 * mono_resume_unwind () will call us again to continue
2991 * the unwinding.
2993 jit_tls->resume_state.ex_obj = obj;
2994 jit_tls->resume_state.ji = ji;
2995 jit_tls->resume_state.clause_index = i + 1;
2996 jit_tls->resume_state.ctx = *ctx;
2997 jit_tls->resume_state.new_ctx = new_ctx;
2998 jit_tls->resume_state.lmf = lmf;
2999 jit_tls->resume_state.first_filter_idx = first_filter_idx;
3000 jit_tls->resume_state.filter_idx = filter_idx;
3001 mini_set_abort_threshold (&frame);
3002 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
3003 return 0;
3004 } else {
3005 mini_set_abort_threshold (&frame);
3006 if (in_interp) {
3007 gboolean has_ex = mini_get_interp_callbacks ()->run_finally (&frame, i, ei->handler_start, ei->data.handler_end);
3008 if (has_ex) {
3010 * If run_finally didn't resume to a context, it means that the handler frame
3011 * is linked to the frame calling finally through interpreter frames. This
3012 * means that we will reach the handler frame by resuming the current context.
3014 if (MONO_CONTEXT_GET_IP (ctx) != 0)
3015 mono_arch_undo_ip_adjustment (ctx);
3016 return 0;
3018 } else {
3019 call_filter (ctx, ei->handler_start);
3026 if (in_interp)
3027 interp_exit_finally_abort_blocks (ji, clause_index_start, ji->num_clauses, ip);
3029 if (MONO_PROFILER_ENABLED (method_exception_leave) &&
3030 mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) {
3031 jit_tls->orig_ex_ctx_set = TRUE;
3032 MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
3033 jit_tls->orig_ex_ctx_set = FALSE;
3036 *ctx = new_ctx;
3039 g_assert_not_reached ();
3043 * mono_debugger_run_finally:
3044 * \param start_ctx saved processor state
3045 * This method is called by the Mono Debugger to call all \c finally clauses of the
3046 * current stack frame. It's used when the user issues a \c return command to make
3047 * the current stack frame return. After returning from this method, the debugger
3048 * unwinds the stack one frame and gives control back to the user.
3049 * NOTE: This method is only used when running inside the Mono Debugger.
3051 void
3052 mono_debugger_run_finally (MonoContext *start_ctx)
3054 static int (*call_filter) (MonoContext *, gpointer) = NULL;
3055 MonoDomain *domain = mono_domain_get ();
3056 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3057 MonoLMF *lmf = mono_get_lmf ();
3058 MonoContext ctx, new_ctx;
3059 MonoJitInfo *ji, rji;
3060 int i;
3062 ctx = *start_ctx;
3064 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
3065 if (!ji || ji == (gpointer)-1)
3066 return;
3068 if (!call_filter)
3069 call_filter = (int (*)(MonoContext *, void *))mono_get_call_filter ();
3071 for (i = 0; i < ji->num_clauses; i++) {
3072 MonoJitExceptionInfo *ei = &ji->clauses [i];
3074 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
3075 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
3076 call_filter (&ctx, ei->handler_start);
3082 * mono_handle_exception:
3083 * \param ctx saved processor state
3084 * \param obj the exception object
3086 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3087 * return TRUE.
3089 gboolean
3090 mono_handle_exception (MonoContext *ctx, gpointer void_obj)
3092 MonoObject *obj = (MonoObject*)void_obj;
3094 MONO_REQ_GC_UNSAFE_MODE;
3096 #ifndef DISABLE_PERFCOUNTERS
3097 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_thrown);
3098 #endif
3100 return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
3103 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3105 #ifndef MONO_ARCH_USE_SIGACTION
3106 #error "Can't use sigaltstack without sigaction"
3107 #endif
3109 void
3110 mono_setup_altstack (MonoJitTlsData *tls)
3112 size_t stsize = 0;
3113 stack_t sa;
3114 guint8 *staddr = NULL;
3115 #if defined(TARGET_OSX) || defined(_AIX)
3117 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3118 * stack pages. Stack overflow on main thread will kill the app.
3120 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3121 * do this for thread 1 with its stack at the top of memory. Other threads seem
3122 * fine for the altstack guard page, though.
3124 gboolean disable_stack_guard = mono_threads_platform_is_main_thread ();
3125 #else
3126 gboolean disable_stack_guard = FALSE;
3127 #endif
3129 if (mono_running_on_valgrind ())
3130 return;
3132 mono_thread_info_get_stack_bounds (&staddr, &stsize);
3134 g_assert (staddr);
3136 tls->end_of_stack = staddr + stsize;
3137 tls->stack_size = stsize;
3139 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3141 if (!disable_stack_guard) {
3142 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
3143 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
3145 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
3147 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
3148 /* mprotect can fail for the main thread stack */
3149 gpointer gaddr = mono_valloc (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON|MONO_MMAP_FIXED, MONO_MEM_ACCOUNT_EXCEPTIONS);
3150 if (gaddr) {
3151 g_assert (gaddr == tls->stack_ovf_guard_base);
3152 tls->stack_ovf_valloced = TRUE;
3153 } else {
3154 g_warning ("couldn't allocate guard page, continue without it");
3155 tls->stack_ovf_guard_base = NULL;
3156 tls->stack_ovf_guard_size = 0;
3161 /* Setup an alternate signal stack */
3162 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);
3163 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3165 g_assert (tls->signal_stack);
3167 sa.ss_sp = tls->signal_stack;
3168 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3169 sa.ss_flags = 0;
3170 g_assert (sigaltstack (&sa, NULL) == 0);
3172 if (tls->stack_ovf_guard_base)
3173 mono_gc_register_altstack ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size, (char*)staddr + stsize - ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size), tls->signal_stack, tls->signal_stack_size);
3174 else
3175 mono_gc_register_altstack (staddr, stsize, tls->signal_stack, tls->signal_stack_size);
3179 void
3180 mono_free_altstack (MonoJitTlsData *tls)
3182 stack_t sa;
3183 int err;
3185 sa.ss_sp = tls->signal_stack;
3186 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3187 sa.ss_flags = SS_DISABLE;
3188 err = sigaltstack (&sa, NULL);
3189 g_assert (err == 0);
3191 if (tls->signal_stack)
3192 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MEM_ACCOUNT_EXCEPTIONS);
3194 if (!tls->stack_ovf_guard_base)
3195 return;
3196 if (tls->stack_ovf_valloced)
3197 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MEM_ACCOUNT_EXCEPTIONS);
3198 else
3199 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3202 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3204 void
3205 mono_setup_altstack (MonoJitTlsData *tls)
3209 void
3210 mono_free_altstack (MonoJitTlsData *tls)
3214 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3216 gboolean
3217 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
3219 if (!jit_tls)
3220 return FALSE;
3222 if (mono_llvm_only)
3223 return FALSE;
3225 /* we got a stack overflow in the soft-guard pages
3226 * There are two cases:
3227 * 1) managed code caused the overflow: we unprotect the soft-guard page
3228 * and let the arch-specific code trigger the exception handling mechanism
3229 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3230 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3231 * and hope we can continue with those enabled, at least until the hard-guard page
3232 * is hit. The alternative to continuing here is to just print a message and abort.
3233 * We may add in the future the code to protect the pages again in the codepath
3234 * when we return from unmanaged to managed code.
3236 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
3237 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
3238 gboolean handled = FALSE;
3240 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3241 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3242 if (ji) {
3243 mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE);
3244 handled = TRUE;
3246 #endif
3247 if (!handled) {
3248 /* We print a message: after this even managed stack overflows
3249 * may crash the runtime
3251 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
3252 if (!jit_tls->handling_stack_ovf) {
3253 jit_tls->handling_stack_ovf = 1;
3254 } else {
3255 /*fprintf (stderr, "Already handling stack overflow\n");*/
3258 return TRUE;
3260 return FALSE;
3263 typedef struct {
3264 MonoMethod *omethod;
3265 int count;
3266 } PrintOverflowUserData;
3268 static gboolean
3269 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3271 MonoMethod *method = NULL;
3272 PrintOverflowUserData *user_data = (PrintOverflowUserData *)data;
3273 gchar *location;
3275 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3276 method = jinfo_get_method (frame->ji);
3278 if (method) {
3279 if (user_data->count == 0) {
3280 /* The first frame is in its prolog, so a line number cannot be computed */
3281 user_data->count ++;
3282 return FALSE;
3285 /* If this is a one method overflow, skip the other instances */
3286 if (method == user_data->omethod)
3287 return FALSE;
3289 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
3290 mono_runtime_printf_err (" %s", location);
3291 g_free (location);
3293 if (user_data->count == 1) {
3294 mono_runtime_printf_err (" <...>");
3295 user_data->omethod = method;
3296 } else {
3297 user_data->omethod = NULL;
3300 user_data->count ++;
3301 } else
3302 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame->native_offset);
3304 return FALSE;
3307 void
3308 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *mctx, guint8* fault_addr)
3310 PrintOverflowUserData ud;
3312 /* we don't do much now, but we can warn the user with a useful message */
3313 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx), fault_addr);
3315 mono_runtime_printf_err ("Stacktrace:");
3317 memset (&ud, 0, sizeof (ud));
3319 mono_walk_stack_with_ctx (print_overflow_stack_frame, mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
3321 _exit (1);
3324 static gboolean
3325 print_stack_frame_signal_safe (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3327 MonoMethod *method = NULL;
3329 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3330 method = jinfo_get_method (frame->ji);
3332 if (method) {
3333 const char *name_space = m_class_get_name_space (method->klass);
3334 g_async_safe_printf("\t at %s%s%s:%s <0x%05x>\n", name_space, (name_space [0] != '\0' ? "." : ""), m_class_get_name (method->klass), method->name, frame->native_offset);
3335 } else {
3336 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame->native_offset);
3339 return FALSE;
3342 static G_GNUC_UNUSED gboolean
3343 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3345 GString *p = (GString*)data;
3346 MonoMethod *method = NULL;
3348 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3349 method = jinfo_get_method (frame->ji);
3351 if (method && frame->domain) {
3352 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3353 g_string_append_printf (p, " %s\n", location);
3354 g_free (location);
3355 } else
3356 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3358 return FALSE;
3361 #ifndef MONO_CROSS_COMPILE
3362 static gboolean handle_crash_loop = FALSE;
3365 * mono_handle_native_crash:
3367 * Handle a native crash (e.g. SIGSEGV) while in native code by
3368 * printing diagnostic information and aborting.
3370 void
3371 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3373 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3375 if (handle_crash_loop)
3376 return;
3378 #ifdef MONO_ARCH_USE_SIGACTION
3379 struct sigaction sa;
3380 sa.sa_handler = SIG_DFL;
3381 sigemptyset (&sa.sa_mask);
3382 sa.sa_flags = 0;
3384 /* Remove our SIGABRT handler */
3385 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
3387 /* On some systems we get a SIGILL when calling abort (), because it might
3388 * fail to raise SIGABRT */
3389 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
3391 /* Remove SIGCHLD, it uses the finalizer thread */
3392 g_assert (sigaction (SIGCHLD, &sa, NULL) != -1);
3394 /* Remove SIGQUIT, we are already dumping threads */
3395 g_assert (sigaction (SIGQUIT, &sa, NULL) != -1);
3397 #endif
3399 if (mini_debug_options.suspend_on_native_crash) {
3400 g_async_safe_printf ("Received %s, suspending...\n", signal);
3401 while (1) {
3402 // Sleep for 1 second.
3403 g_usleep (1000 * 1000);
3407 /* prevent infinite loops in crash handling */
3408 handle_crash_loop = TRUE;
3411 * A SIGSEGV indicates something went very wrong so we can no longer depend
3412 * on anything working. So try to print out lots of diagnostics, starting
3413 * with ones which have a greater chance of working.
3416 g_async_safe_printf("\n=================================================================\n");
3417 g_async_safe_printf("\tNative Crash Reporting\n");
3418 g_async_safe_printf("=================================================================\n");
3419 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal);
3420 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3421 g_async_safe_printf("used by your application.\n");
3422 g_async_safe_printf("=================================================================\n");
3423 mono_dump_native_crash_info (signal, mctx, info);
3425 /* !jit_tls means the thread was not registered with the runtime */
3426 // This must be below the native crash dump, because we can't safely
3427 // do runtime state probing after we have walked the managed stack here.
3428 if (jit_tls && mono_thread_internal_current () && mctx) {
3429 g_async_safe_printf ("\n=================================================================\n");
3430 g_async_safe_printf ("\tManaged Stacktrace:\n");
3431 g_async_safe_printf ("=================================================================\n");
3433 mono_walk_stack_full (print_stack_frame_signal_safe, mctx, mono_domain_get (), jit_tls, mono_get_lmf (), MONO_UNWIND_LOOKUP_IL_OFFSET, NULL, TRUE);
3434 g_async_safe_printf ("=================================================================\n");
3437 mono_post_native_crash_handler (signal, mctx, info, mono_do_crash_chaining);
3440 #else
3442 void
3443 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3445 g_assert_not_reached ();
3448 #endif /* !MONO_CROSS_COMPILE */
3450 static void
3451 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
3453 MonoInternalThread *thread = mono_thread_internal_current ();
3454 MonoContext ctx;
3455 GString* text;
3457 if (!thread)
3458 return;
3460 text = g_string_new (0);
3462 mono_gstring_append_thread_name (text, thread);
3464 g_string_append_printf (text, " tid=%p this=%p ", (gpointer)(gsize)thread->tid, thread);
3465 mono_thread_internal_describe (thread, text);
3466 g_string_append (text, "\n");
3468 if (start_ctx) {
3469 memcpy (&ctx, start_ctx, sizeof (MonoContext));
3470 } else if (!sigctx)
3471 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
3472 else
3473 mono_sigctx_to_monoctx (sigctx, &ctx);
3475 mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
3477 mono_runtime_printf ("%s", text->str);
3479 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3480 OutputDebugStringA(text->str);
3481 #endif
3483 g_string_free (text, TRUE);
3484 mono_runtime_stdout_fflush ();
3488 * mono_print_thread_dump:
3490 * Print information about the current thread to stdout.
3491 * \p sigctx can be NULL, allowing this to be called from gdb.
3493 void
3494 mono_print_thread_dump (void *sigctx)
3496 mono_print_thread_dump_internal (sigctx, NULL);
3499 void
3500 mono_print_thread_dump_from_ctx (MonoContext *ctx)
3502 mono_print_thread_dump_internal (NULL, ctx);
3506 * mono_resume_unwind:
3508 * This is called by a trampoline from LLVM compiled finally clauses to continue
3509 * unwinding.
3511 void
3512 mono_resume_unwind (MonoContext *ctx)
3514 MONO_REQ_GC_UNSAFE_MODE;
3516 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3517 MonoContext new_ctx;
3519 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
3520 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
3521 new_ctx = *ctx;
3523 mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL);
3525 mono_restore_context (&new_ctx);
3528 typedef struct {
3529 MonoJitInfo *ji;
3530 MonoContext ctx;
3531 MonoJitExceptionInfo *ei;
3532 } FindHandlerBlockData;
3534 static gboolean
3535 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3537 int i;
3538 gpointer ip;
3539 FindHandlerBlockData *pdata = (FindHandlerBlockData *)data;
3540 MonoJitInfo *ji = frame->ji;
3542 if (!ji)
3543 return FALSE;
3545 ip = MONO_CONTEXT_GET_IP (ctx);
3547 for (i = 0; i < ji->num_clauses; ++i) {
3548 MonoJitExceptionInfo *ei = ji->clauses + i;
3549 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3550 continue;
3551 /*If ip points to the first instruction it means the handler block didn't start
3552 so we can leave its execution to the EH machinery*/
3553 if (ei->handler_start <= ip && ip < ei->data.handler_end) {
3554 pdata->ji = ji;
3555 pdata->ei = ei;
3556 pdata->ctx = *ctx;
3557 break;
3560 return FALSE;
3564 static void
3565 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
3567 int i;
3568 MonoJitExceptionInfo *clause = NULL;
3569 gpointer ip;
3570 guint8 *bp;
3572 ip = MONO_CONTEXT_GET_IP (ctx);
3574 for (i = 0; i < ji->num_clauses; ++i) {
3575 clause = &ji->clauses [i];
3576 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3577 continue;
3578 if (clause->handler_start <= ip && clause->data.handler_end > ip)
3579 break;
3582 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3583 g_assert (i < ji->num_clauses);
3585 /*Load the spvar*/
3586 bp = (guint8*)MONO_CONTEXT_GET_BP (ctx);
3587 *(bp + clause->exvar_offset) = 1;
3591 * Finds the bottom handler block running and install a block guard if needed.
3593 static gboolean
3594 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
3596 FindHandlerBlockData data = { 0 };
3597 MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
3599 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3600 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3602 if (!jit_tls || jit_tls->handler_block)
3603 return FALSE;
3605 /* Do an async safe stack walk */
3606 mono_thread_info_set_is_async_context (TRUE);
3607 mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data);
3608 mono_thread_info_set_is_async_context (FALSE);
3610 if (!data.ji)
3611 return FALSE;
3613 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
3615 install_handler_block_guard (data.ji, &data.ctx);
3617 jit_tls->handler_block = data.ei;
3619 return TRUE;
3622 static void
3623 mono_uninstall_current_handler_block_guard (void)
3625 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3626 if (jit_tls)
3627 jit_tls->handler_block = NULL;
3631 static gboolean
3632 mono_current_thread_has_handle_block_guard (void)
3634 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3635 return jit_tls && jit_tls->handler_block != NULL;
3638 void
3639 mono_set_cast_details (MonoClass *from, MonoClass *to)
3641 MonoJitTlsData *jit_tls = NULL;
3643 if (mini_debug_options.better_cast_details) {
3644 jit_tls = mono_tls_get_jit_tls ();
3645 jit_tls->class_cast_from = from;
3646 jit_tls->class_cast_to = to;
3651 /*returns false if the thread is not attached*/
3652 gboolean
3653 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
3655 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3656 if (!thread) {
3657 ctx->valid = FALSE;
3658 return FALSE;
3661 if (sigctx) {
3662 mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
3664 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3665 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3666 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3668 else {
3669 mono_thread_state_init (ctx);
3672 if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
3673 return FALSE;
3675 ctx->valid = TRUE;
3676 return TRUE;
3679 void
3680 mono_thread_state_init (MonoThreadUnwindState *ctx)
3682 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3684 #if defined(MONO_CROSS_COMPILE)
3685 ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
3686 #elif MONO_ARCH_HAS_MONO_CONTEXT
3687 MONO_CONTEXT_GET_CURRENT (ctx->ctx);
3688 #else
3689 g_error ("Use a null sigctx requires a working mono-context");
3690 #endif
3692 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3693 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3694 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
3695 ctx->valid = TRUE;
3699 gboolean
3700 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
3702 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3703 if (!thread) {
3704 ctx->valid = FALSE;
3705 return FALSE;
3708 ctx->ctx = *mctx;
3709 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3710 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3711 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3712 ctx->valid = TRUE;
3713 return TRUE;
3716 /*returns false if the thread is not attached*/
3717 gboolean
3718 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
3720 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3721 MONO_ARCH_CONTEXT_DEF
3723 mono_arch_flush_register_windows ();
3725 if (!thread || !thread->jit_data) {
3726 ctx->valid = FALSE;
3727 return FALSE;
3729 MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
3731 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3732 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3733 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3734 ctx->valid = TRUE;
3735 return TRUE;
3738 static void
3739 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
3741 mono_handle_exception (ctx, (MonoObject *)exc);
3742 mono_restore_context (ctx);
3745 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3746 void
3747 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
3749 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3750 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3751 jit_tls->ex_ctx = *ctx;
3753 mono_arch_setup_async_callback (ctx, async_cb, user_data);
3754 #else
3755 g_error ("This target doesn't support mono_arch_setup_async_callback");
3756 #endif
3760 * mono_restore_context:
3762 * Call the architecture specific restore context function.
3764 void
3765 mono_restore_context (MonoContext *ctx)
3767 static void (*restore_context) (MonoContext *);
3769 if (!restore_context)
3770 restore_context = (void (*)(MonoContext *))mono_get_restore_context ();
3771 restore_context (ctx);
3772 g_assert_not_reached ();
3776 * mono_jinfo_get_unwind_info:
3778 * Return the unwind info for JI.
3780 guint8*
3781 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
3783 if (ji->has_unwind_info) {
3784 /* The address/length in the MonoJitInfo structure itself */
3785 MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji);
3786 *unwind_info_len = info->unw_info_len;
3787 return info->unw_info;
3788 } else if (ji->from_aot)
3789 return mono_aot_get_unwind_info (ji, unwind_info_len);
3790 else
3791 return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
3795 mono_jinfo_get_epilog_size (MonoJitInfo *ji)
3797 MonoArchEHJitInfo *info;
3799 info = mono_jit_info_get_arch_eh_info (ji);
3800 g_assert (info);
3802 return info->epilog_size;
3806 * mono_install_ftnptr_eh_callback:
3808 * Install a callback that should be called when there is a managed exception
3809 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3810 * managed exception to a native exception, to properly unwind the native
3811 * stack; this native exception will then be converted back to a managed
3812 * exception in their managed-to-native wrapper.
3814 void
3815 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
3817 ftnptr_eh_callback = callback;
3821 * LLVM/Bitcode exception handling.
3824 static void
3825 throw_exception (MonoObject *ex, gboolean rethrow)
3827 MONO_REQ_GC_UNSAFE_MODE;
3829 ERROR_DECL (error);
3830 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3831 MonoException *mono_ex;
3833 if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, error)) {
3834 mono_error_assert_ok (error);
3835 mono_ex = mono_get_exception_runtime_wrapped_checked (ex, error);
3836 mono_error_assert_ok (error);
3837 jit_tls->thrown_non_exc = mono_gchandle_new_internal (ex, FALSE);
3839 else
3840 mono_ex = (MonoException*)ex;
3842 // Note: Not pinned
3843 jit_tls->thrown_exc = mono_gchandle_new_internal ((MonoObject*)mono_ex, FALSE);
3845 if (!rethrow) {
3846 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3847 GList *l, *ips = NULL;
3848 GList *trace;
3850 _Unwind_Backtrace (build_stack_trace, &ips);
3851 /* The list contains ip-gshared info pairs */
3852 trace = NULL;
3853 ips = g_list_reverse (ips);
3854 for (l = ips; l; l = l->next) {
3855 trace = g_list_append (trace, l->data);
3856 trace = g_list_append (trace, NULL);
3857 trace = g_list_append (trace, NULL);
3859 MonoArray *ips_arr = mono_glist_to_array (trace, mono_defaults.int_class, error);
3860 mono_error_assert_ok (error);
3861 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3862 g_list_free (l);
3863 g_list_free (trace);
3864 #endif
3867 mono_llvm_cpp_throw_exception ();
3870 void
3871 mono_llvm_throw_exception (MonoObject *ex)
3873 throw_exception (ex, FALSE);
3876 void
3877 mono_llvm_rethrow_exception (MonoObject *ex)
3879 throw_exception (ex, TRUE);
3882 void
3883 mono_llvm_raise_exception (MonoException *e)
3885 mono_llvm_throw_exception ((MonoObject*)e);
3888 void
3889 mono_llvm_reraise_exception (MonoException *e)
3891 mono_llvm_rethrow_exception ((MonoObject*)e);
3894 void
3895 mono_llvm_throw_corlib_exception (guint32 ex_token_index)
3897 guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
3898 MonoException *ex;
3900 ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token);
3902 mono_llvm_throw_exception ((MonoObject*)ex);
3906 * mono_llvm_resume_exception:
3908 * Resume exception propagation.
3910 void
3911 mono_llvm_resume_exception (void)
3913 mono_llvm_cpp_throw_exception ();
3917 * mono_llvm_load_exception:
3919 * Return the currently thrown exception.
3921 MonoObject *
3922 mono_llvm_load_exception (void)
3924 ERROR_DECL (error);
3925 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3927 MonoException *mono_ex = (MonoException*)mono_gchandle_get_target_internal (jit_tls->thrown_exc);
3929 MonoArray *ta = mono_ex->trace_ips;
3931 if (ta) {
3932 GList *trace_ips = NULL;
3933 gpointer ip = MONO_RETURN_ADDRESS ();
3935 size_t upper = mono_array_length_internal (ta);
3937 for (int i = 0; i < upper; i += TRACE_IP_ENTRY_SIZE) {
3938 gpointer curr_ip = mono_array_get_internal (ta, gpointer, i);
3939 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
3940 gpointer p = mono_array_get_internal (ta, gpointer, i + j);
3941 trace_ips = g_list_append (trace_ips, p);
3943 if (ip == curr_ip)
3944 break;
3947 // FIXME: Does this work correctly for rethrows?
3948 // We may be discarding useful information
3949 // when this gets GC'ed
3950 MonoArray *ips_arr = mono_glist_to_array (trace_ips, mono_defaults.int_class, error);
3951 mono_error_assert_ok (error);
3952 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3953 g_list_free (trace_ips);
3955 // FIXME:
3956 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3957 } else {
3958 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, 0, error));
3959 mono_error_assert_ok (error);
3960 MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, mono_array_new_checked (mono_domain_get (), mono_defaults.stack_frame_class, 0, error));
3961 mono_error_assert_ok (error);
3964 return &mono_ex->object;
3968 * mono_llvm_clear_exception:
3970 * Mark the currently thrown exception as handled.
3972 void
3973 mono_llvm_clear_exception (void)
3975 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3976 mono_gchandle_free_internal (jit_tls->thrown_exc);
3977 jit_tls->thrown_exc = 0;
3978 if (jit_tls->thrown_non_exc)
3979 mono_gchandle_free_internal (jit_tls->thrown_non_exc);
3980 jit_tls->thrown_non_exc = 0;
3982 mono_memory_barrier ();
3986 * mono_llvm_match_exception:
3988 * Return the innermost clause containing REGION_START-REGION_END which can handle
3989 * the current exception.
3991 gint32
3992 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
3994 ERROR_DECL (error);
3995 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3996 MonoObject *exc;
3997 gint32 index = -1;
3999 g_assert (jit_tls->thrown_exc);
4000 exc = mono_gchandle_get_target_internal (jit_tls->thrown_exc);
4001 if (jit_tls->thrown_non_exc) {
4003 * Have to unwrap RuntimeWrappedExceptions if the
4004 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
4006 if (!wrap_non_exception_throws (jinfo_get_method (jinfo)))
4007 exc = mono_gchandle_get_target_internal (jit_tls->thrown_non_exc);
4010 for (int i = 0; i < jinfo->num_clauses; i++) {
4011 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
4012 MonoClass *catch_class;
4014 if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
4015 continue;
4017 catch_class = ei->data.catch_class;
4018 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class))) {
4019 MonoGenericContext context;
4020 MonoType *inflated_type;
4022 g_assert (rgctx || this_obj);
4023 context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
4024 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
4025 mono_error_assert_ok (error); /* FIXME don't swallow the error */
4027 catch_class = mono_class_from_mono_type_internal (inflated_type);
4028 mono_metadata_free_type (inflated_type);
4031 // FIXME: Handle edge cases handled in get_exception_catch_class
4032 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, error)) {
4033 index = ei->clause_index;
4034 break;
4035 } else
4036 mono_error_assert_ok (error);
4038 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4039 g_assert_not_reached ();
4043 return index;
4046 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4047 G_EXTERN_C _Unwind_Reason_Code mono_debug_personality (int a, _Unwind_Action b,
4048 uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
4050 g_assert_not_reached ();
4052 #else
4053 G_EXTERN_C void mono_debug_personality (void);
4055 void
4056 mono_debug_personality (void)
4058 g_assert_not_reached ();
4060 #endif