[tests] Reenable enum equals test on interpreter (#18673)
[mono-project.git] / mono / mini / mini-exceptions.c
blobf000d579a45e14a3c25c36e581442cf04f6aaf61
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 "debugger-engine.h"
76 #include "seq-points.h"
77 #include "llvm-runtime.h"
78 #include "mini-llvm.h"
79 #include "aot-runtime.h"
80 #include "mini-runtime.h"
81 #include "interp/interp.h"
83 #ifdef ENABLE_LLVM
84 #include "mini-llvm-cpp.h"
85 #endif
87 #ifdef TARGET_ARM
88 #include "mini-arm.h"
89 #endif
91 #ifndef MONO_ARCH_CONTEXT_DEF
92 #define MONO_ARCH_CONTEXT_DEF
93 #endif
95 #if !defined(DISABLE_CRASH_REPORTING)
96 #include <gmodule.h>
97 #endif
98 #include "mono/utils/mono-tls-inline.h"
101 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
102 * This structure represents one entry.
103 * This should consists of pointers only.
105 typedef struct
107 gpointer ip;
108 gpointer generic_info;
109 /* Only for interpreter frames */
110 MonoJitInfo *ji;
111 } ExceptionTraceIp;
113 /* Number of words in trace_ips belonging to one entry */
114 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
116 static gpointer restore_context_func, call_filter_func;
117 static gpointer throw_exception_func, rethrow_exception_func, rethrow_preserve_exception_func;
118 static gpointer throw_corlib_exception_func;
120 static MonoFtnPtrEHCallback ftnptr_eh_callback;
122 static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data, gboolean crash_context);
123 static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx);
124 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
125 static gboolean mono_current_thread_has_handle_block_guard (void);
126 static gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx);
127 static void mono_uninstall_current_handler_block_guard (void);
128 static gboolean mono_exception_walk_trace_internal (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data);
129 static void throw_exception (MonoObject *ex, gboolean rethrow);
131 static void mono_summarize_managed_stack (MonoThreadSummary *out);
132 static void mono_summarize_unmanaged_stack (MonoThreadSummary *out);
133 static void mono_summarize_exception (MonoException *exc, MonoThreadSummary *out);
134 static void mono_crash_reporting_register_native_library (const char *module_path, const char *module_name);
135 static void mono_crash_reporting_allow_all_native_libraries (void);
137 static gboolean
138 first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
140 gpointer *data = (gpointer *)addr;
142 if (!frame->managed)
143 return FALSE;
145 if (!ctx) {
146 // FIXME: Happens with llvm_only
147 *data = NULL;
148 return TRUE;
151 *data = frame->frame_addr;
152 g_assert (*data);
153 return TRUE;
156 static gpointer
157 mono_thread_get_managed_sp (void)
159 gpointer addr = NULL;
160 mono_walk_stack (first_managed, MONO_UNWIND_SIGNAL_SAFE, &addr);
161 return addr;
164 static void
165 mini_clear_abort_threshold (void)
167 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
168 jit_tls->abort_exc_stack_threshold = NULL;
171 static void
172 mini_set_abort_threshold (StackFrameInfo *frame)
174 gpointer sp = frame->frame_addr;
175 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
176 // Only move it up, to avoid thrown/caught
177 // exceptions lower in the stack from triggering
178 // a rethrow
179 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
180 if (!jit_tls->abort_exc_stack_threshold || above_threshold) {
181 jit_tls->abort_exc_stack_threshold = sp;
185 // Note: In the case that the frame is above where the thread abort
186 // was set we bump the threshold so that functions called from the new,
187 // higher threshold don't trigger the thread abort exception
188 static gboolean
189 mini_above_abort_threshold (void)
191 gpointer sp = mono_thread_get_managed_sp ();
192 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
194 if (!sp)
195 return TRUE;
197 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
199 if (above_threshold)
200 jit_tls->abort_exc_stack_threshold = sp;
202 return above_threshold;
205 static int
206 mono_get_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
208 SeqPoint sp;
209 if (mono_find_prev_seq_point_for_native_offset (domain, method, native_offset, NULL, &sp))
210 return sp.il_offset;
211 return -1;
214 void
215 mono_exceptions_init (void)
217 MonoRuntimeExceptionHandlingCallbacks cbs;
218 if (mono_ee_features.use_aot_trampolines) {
219 restore_context_func = mono_aot_get_trampoline ("restore_context");
220 call_filter_func = mono_aot_get_trampoline ("call_filter");
221 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
222 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
223 rethrow_preserve_exception_func = mono_aot_get_trampoline ("rethrow_preserve_exception");
224 } else if (!mono_llvm_only) {
225 MonoTrampInfo *info;
227 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
228 mono_tramp_info_register (info, NULL);
229 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
230 mono_tramp_info_register (info, NULL);
231 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
232 mono_tramp_info_register (info, NULL);
233 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
234 mono_tramp_info_register (info, NULL);
235 rethrow_preserve_exception_func = mono_arch_get_rethrow_preserve_exception (&info, FALSE);
236 mono_tramp_info_register (info, NULL);
239 mono_arch_exceptions_init ();
241 cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
242 cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
243 cbs.mono_summarize_managed_stack = mono_summarize_managed_stack;
244 cbs.mono_summarize_unmanaged_stack = mono_summarize_unmanaged_stack;
245 cbs.mono_summarize_exception = mono_summarize_exception;
246 cbs.mono_register_native_library = mono_crash_reporting_register_native_library;
247 cbs.mono_allow_all_native_libraries = mono_crash_reporting_allow_all_native_libraries;
249 if (mono_llvm_only) {
250 cbs.mono_raise_exception = mono_llvm_raise_exception;
251 cbs.mono_reraise_exception = mono_llvm_reraise_exception;
252 } else {
253 cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception ();
254 cbs.mono_reraise_exception = (void (*)(MonoException *))mono_get_rethrow_exception ();
256 cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
257 cbs.mono_exception_walk_trace = mono_exception_walk_trace;
258 cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
259 cbs.mono_uninstall_current_handler_block_guard = mono_uninstall_current_handler_block_guard;
260 cbs.mono_current_thread_has_handle_block_guard = mono_current_thread_has_handle_block_guard;
261 cbs.mono_clear_abort_threshold = mini_clear_abort_threshold;
262 cbs.mono_above_abort_threshold = mini_above_abort_threshold;
263 mono_install_eh_callbacks (&cbs);
264 mono_install_get_seq_point (mono_get_seq_point_for_native_offset);
267 gpointer
268 mono_get_throw_exception (void)
270 g_assert (throw_exception_func);
271 return throw_exception_func;
274 gpointer
275 mono_get_rethrow_exception (void)
277 g_assert (rethrow_exception_func);
278 return rethrow_exception_func;
281 gpointer
282 mono_get_rethrow_preserve_exception (void)
284 g_assert (rethrow_preserve_exception_func);
285 return rethrow_preserve_exception_func;
288 static void
289 no_call_filter (void)
291 g_assert_not_reached ();
294 gpointer
295 mono_get_call_filter (void)
297 /* This is called even in llvmonly mode etc. */
298 if (!call_filter_func)
299 return (gpointer)no_call_filter;
300 return call_filter_func;
303 gpointer
304 mono_get_restore_context (void)
306 g_assert (restore_context_func);
307 return restore_context_func;
310 gpointer
311 mono_get_throw_corlib_exception (void)
313 gpointer code = NULL;
314 MonoTrampInfo *info;
316 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
317 if (throw_corlib_exception_func)
318 return throw_corlib_exception_func;
320 if (mono_ee_features.use_aot_trampolines)
321 code = mono_aot_get_trampoline ("throw_corlib_exception");
322 else {
323 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
324 mono_tramp_info_register (info, NULL);
327 mono_memory_barrier ();
329 throw_corlib_exception_func = code;
331 return throw_corlib_exception_func;
335 * mono_get_throw_exception_addr:
337 * Return an address which stores the result of
338 * mono_get_throw_exception.
340 gpointer
341 mono_get_throw_exception_addr (void)
343 return &throw_exception_func;
346 gpointer
347 mono_get_rethrow_preserve_exception_addr (void)
349 return &rethrow_preserve_exception_func;
352 static gboolean
353 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
355 MonoTryBlockHoleTableJitInfo *table;
356 int i;
357 guint32 offset;
358 guint16 clause;
360 if (ei->try_start > ip || ip >= ei->try_end)
361 return FALSE;
363 if (!ji->has_try_block_holes)
364 return TRUE;
366 table = mono_jit_info_get_try_block_hole_table_info (ji);
367 offset = (guint32)((char*)ip - (char*)ji->code_start);
368 clause = (guint16)(ei - ji->clauses);
369 g_assert (clause < ji->num_clauses);
371 for (i = 0; i < table->num_holes; ++i) {
372 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
373 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
374 return FALSE;
376 return TRUE;
379 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
381 #if 0
382 static gboolean show_native_addresses = TRUE;
383 #else
384 static gboolean show_native_addresses = FALSE;
385 #endif
387 static _Unwind_Reason_Code
388 build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
390 MonoDomain *domain = mono_domain_get ();
391 uintptr_t ip = _Unwind_GetIP (frame_ctx);
393 if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
394 GList **trace_ips = (GList **)state;
395 *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
398 return _URC_NO_REASON;
401 static GSList*
402 get_unwind_backtrace (void)
404 GSList *ips = NULL;
406 _Unwind_Backtrace (build_stack_trace, &ips);
408 return g_slist_reverse (ips);
411 #else
413 static GSList*
414 get_unwind_backtrace (void)
416 return NULL;
419 #endif
421 static gboolean
422 arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
423 MonoJitInfo *ji, MonoContext *ctx,
424 MonoContext *new_ctx, MonoLMF **lmf,
425 host_mgreg_t **save_locations,
426 StackFrameInfo *frame)
428 if (!ji && *lmf) {
429 if (((gsize)(*lmf)->previous_lmf) & 2) {
430 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
432 memset (frame, 0, sizeof (StackFrameInfo));
433 frame->ji = ji;
435 *new_ctx = *ctx;
437 if (ext->kind == MONO_LMFEXT_DEBUGGER_INVOKE) {
439 * This LMF entry is created by the soft debug code to mark transitions to
440 * managed code done during invokes.
442 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
443 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
444 } else if (ext->kind == MONO_LMFEXT_INTERP_EXIT || ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX) {
445 frame->type = FRAME_TYPE_INTERP_TO_MANAGED;
446 frame->interp_exit_data = ext->interp_exit_data;
447 if (ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX) {
448 frame->type = FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX;
449 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
451 } else {
452 g_assert_not_reached ();
455 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~3);
457 return TRUE;
461 return mono_arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
465 * find_jit_info:
467 * Translate between the mono_arch_unwind_frame function and the old API.
469 static MonoJitInfo *
470 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
471 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
473 StackFrameInfo frame;
474 MonoJitInfo *ji;
475 gboolean err;
476 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
478 /* Avoid costly table lookup during stack overflow */
479 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
480 ji = prev_ji;
481 else
482 ji = mini_jit_info_table_find (domain, ip, NULL);
484 if (managed)
485 *managed = FALSE;
487 err = arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
488 if (!err)
489 return (MonoJitInfo *)-1;
491 if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
493 * Remove any unused lmf.
494 * Mask out the lower bits which might be used to hold additional information.
496 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P -1));
499 /* Convert between the new and the old APIs */
500 switch (frame.type) {
501 case FRAME_TYPE_MANAGED:
502 if (managed)
503 *managed = TRUE;
504 return frame.ji;
505 case FRAME_TYPE_TRAMPOLINE:
506 return frame.ji;
507 case FRAME_TYPE_MANAGED_TO_NATIVE:
508 if (frame.ji)
509 return frame.ji;
510 else {
511 memset (res, 0, sizeof (MonoJitInfo));
512 res->d.method = frame.method;
513 return res;
515 case FRAME_TYPE_DEBUGGER_INVOKE: {
516 MonoContext tmp_ctx;
519 * The normal exception handling code can't handle this frame, so just
520 * skip it.
522 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
523 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
524 return ji;
526 default:
527 g_assert_not_reached ();
528 return NULL;
532 /* mono_find_jit_info:
534 * This function is used to gather information from @ctx. It return the
535 * MonoJitInfo of the corresponding function, unwinds one stack frame and
536 * stores the resulting context into @new_ctx. It also stores a string
537 * describing the stack location into @trace (if not NULL), and modifies
538 * the @lmf if necessary. @native_offset return the IP offset from the
539 * start of the function or -1 if that info is not available.
541 MonoJitInfo *
542 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
543 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
544 gboolean *managed)
546 gboolean managed2;
547 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
548 MonoJitInfo *ji;
549 MonoMethod *method = NULL;
551 if (trace)
552 *trace = NULL;
554 if (native_offset)
555 *native_offset = -1;
557 if (managed)
558 *managed = FALSE;
560 ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
562 if (ji == (gpointer)-1)
563 return ji;
565 if (ji && !ji->is_trampoline)
566 method = jinfo_get_method (ji);
568 if (managed2 || (method && method->wrapper_type)) {
569 const char *real_ip, *start;
570 gint32 offset;
572 start = (const char *)ji->code_start;
573 if (!managed2)
574 /* ctx->ip points into native code */
575 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
576 else
577 real_ip = (const char*)ip;
579 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
580 offset = real_ip - start;
581 else
582 offset = -1;
584 if (native_offset)
585 *native_offset = offset;
587 if (managed)
588 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
589 *managed = TRUE;
591 if (trace)
592 *trace = mono_debug_print_stack_frame (method, offset, domain);
593 } else {
594 if (trace) {
595 char *fname = mono_method_full_name (jinfo_get_method (res), TRUE);
596 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
597 g_free (fname);
601 return ji;
605 * mono_find_jit_info_ext:
607 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
608 * structure.
609 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
610 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
611 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
612 * to obtain the last managed frame.
613 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
614 * On return, it will be filled with the locations where callee saved registers are saved
615 * by the current frame. This is returned outside of StackFrameInfo because it can be
616 * quite large on some platforms.
617 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
618 * not be set.
620 gboolean
621 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
622 MonoJitInfo *prev_ji, MonoContext *ctx,
623 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
624 host_mgreg_t **save_locations,
625 StackFrameInfo *frame)
627 gboolean err;
628 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
629 MonoJitInfo *ji;
630 MonoDomain *target_domain = domain;
631 MonoMethod *method = NULL;
632 gboolean async = mono_thread_info_is_async_context ();
634 if (trace)
635 *trace = NULL;
637 /* Avoid costly table lookup during stack overflow */
638 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
639 ji = prev_ji;
640 else
641 ji = mini_jit_info_table_find_ext (domain, ip, TRUE, &target_domain);
643 if (!target_domain)
644 target_domain = domain;
646 if (save_locations)
647 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (host_mgreg_t*));
649 err = arch_unwind_frame (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
650 if (!err)
651 return FALSE;
653 gboolean not_i2m = frame->type != FRAME_TYPE_INTERP_TO_MANAGED && frame->type != FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX;
655 if (not_i2m && *lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
657 * Remove any unused lmf.
658 * Mask out the lower bits which might be used to hold additional information.
660 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P -1));
663 if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async)
664 method = jinfo_get_method (frame->ji);
666 if (frame->type == FRAME_TYPE_MANAGED && method) {
667 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
668 frame->managed = TRUE;
671 if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
673 * This type of frame is just a marker, the caller should unwind once more to get the
674 * last managed frame.
676 frame->ji = NULL;
677 frame->method = NULL;
680 frame->native_offset = -1;
681 frame->domain = target_domain;
682 frame->async_context = async;
683 frame->frame_addr = MONO_CONTEXT_GET_SP (ctx);
685 ji = frame->ji;
687 if (frame->type == FRAME_TYPE_MANAGED)
688 frame->method = method;
690 if (ji && (frame->managed || (method && method->wrapper_type))) {
691 const char *real_ip, *start;
693 start = (const char *)ji->code_start;
694 if (frame->type == FRAME_TYPE_MANAGED)
695 real_ip = (const char*)ip;
696 else
697 /* ctx->ip points into native code */
698 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
700 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
701 frame->native_offset = real_ip - start;
702 else {
703 frame->native_offset = -1;
706 if (trace)
707 *trace = mono_debug_print_stack_frame (method, frame->native_offset, domain);
708 } else {
709 if (trace && frame->method) {
710 char *fname = mono_method_full_name (frame->method, TRUE);
711 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
712 g_free (fname);
716 return TRUE;
719 typedef struct {
720 gboolean in_interp;
721 MonoInterpStackIter interp_iter;
722 gpointer last_frame_addr;
723 } Unwinder;
725 static void
726 unwinder_init (Unwinder *unwinder)
728 memset (unwinder, 0, sizeof (Unwinder));
731 #if defined(__GNUC__) && defined(TARGET_ARM64)
732 /* gcc 4.9.2 seems to miscompile this on arm64 */
733 static __attribute__((optimize("O0"))) gboolean
734 #else
735 static gboolean
736 #endif
737 unwinder_unwind_frame (Unwinder *unwinder,
738 MonoDomain *domain, MonoJitTlsData *jit_tls,
739 MonoJitInfo *prev_ji, MonoContext *ctx,
740 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
741 host_mgreg_t **save_locations,
742 StackFrameInfo *frame)
744 gpointer parent;
745 if (unwinder->in_interp) {
746 memcpy (new_ctx, ctx, sizeof (MonoContext));
748 /* Process debugger invokes */
749 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
750 if (unwinder->last_frame_addr < (gpointer)(*lmf)) {
751 if (((gsize)(*lmf)->previous_lmf) & 2) {
752 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
753 if (ext->kind == MONO_LMFEXT_DEBUGGER_INVOKE) {
754 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~7);
755 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
756 return TRUE;
761 unwinder->in_interp = mini_get_interp_callbacks ()->frame_iter_next (&unwinder->interp_iter, frame);
762 if (frame->type == FRAME_TYPE_INTERP) {
763 parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame);
764 if (parent)
765 unwinder->last_frame_addr = mini_get_interp_callbacks ()->frame_get_native_stack_addr (parent);
766 else
767 unwinder->last_frame_addr = NULL;
769 if (!unwinder->in_interp)
770 return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame);
771 return TRUE;
772 } else {
773 gboolean res = mono_find_jit_info_ext (domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf,
774 save_locations, frame);
775 if (!res)
776 return FALSE;
777 if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED || frame->type == FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX) {
778 unwinder->in_interp = TRUE;
779 mini_get_interp_callbacks ()->frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data);
781 unwinder->last_frame_addr = frame->frame_addr;
782 return TRUE;
787 * This function is async-safe.
789 static gpointer
790 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
792 MonoGenericJitInfo *gi;
793 MonoMethod *method;
794 gpointer info;
796 if (!ji->has_generic_jit_info)
797 return NULL;
798 gi = mono_jit_info_get_generic_jit_info (ji);
799 if (!gi->has_this)
800 return NULL;
802 info = NULL;
804 * Search location list if available, it contains the precise location of the
805 * argument for every pc offset, even if the method was interrupted while it was in
806 * its prolog.
808 if (gi->nlocs) {
809 int offset = (gsize)MONO_CONTEXT_GET_IP (ctx) - (gsize)ji->code_start;
810 int i;
812 for (i = 0; i < gi->nlocs; ++i) {
813 MonoDwarfLocListEntry *entry = &gi->locations [i];
815 if (offset >= entry->from && (offset < entry->to || entry->to == 0)) {
816 if (entry->is_reg)
817 info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg);
818 else
819 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset);
820 break;
823 g_assert (i < gi->nlocs);
824 } else {
825 if (gi->this_in_reg)
826 info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg);
827 else
828 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
829 gi->this_offset);
832 method = jinfo_get_method (ji);
833 if (mono_method_get_context (method)->method_inst) {
834 /* A MonoMethodRuntimeGenericContext* */
835 return info;
836 } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || m_class_is_valuetype (method->klass)) {
837 /* A MonoVTable* */
838 return info;
839 } else {
840 /* Avoid returning a managed object */
841 MonoObject *this_obj = (MonoObject *)info;
843 return this_obj->vtable;
848 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
850 MonoGenericContext
851 mono_get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
853 MonoGenericContext context = { NULL, NULL };
854 MonoClass *klass, *method_container_class;
855 MonoMethod *method;
857 g_assert (generic_info);
859 method = jinfo_get_method (ji);
860 g_assert (method->is_inflated);
861 if (mono_method_get_context (method)->method_inst) {
862 MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext *)generic_info;
864 klass = mrgctx->class_vtable->klass;
865 context.method_inst = mrgctx->method_inst;
866 g_assert (context.method_inst);
867 } else {
868 MonoVTable *vtable = (MonoVTable *)generic_info;
870 klass = vtable->klass;
873 //g_assert (!mono_class_is_gtd (method->klass));
874 if (mono_class_is_ginst (method->klass))
875 method_container_class = mono_class_get_generic_class (method->klass)->container_class;
876 else
877 method_container_class = method->klass;
879 /* class might refer to a subclass of method's class */
880 while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) {
881 klass = m_class_get_parent (klass);
882 g_assert (klass);
885 if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass))
886 context.class_inst = mini_class_get_context (klass)->class_inst;
888 if (mono_class_is_ginst (klass))
889 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass)->container_class, method_container_class));
890 else
891 g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class));
893 return context;
897 static MonoMethod*
898 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
900 ERROR_DECL (error);
901 MonoGenericContext context;
902 MonoMethod *method;
904 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
905 return jinfo_get_method (ji);
906 context = mono_get_generic_context_from_stack_frame (ji, generic_info);
908 method = jinfo_get_method (ji);
909 method = mono_method_get_declaring_generic_method (method);
910 method = mono_class_inflate_generic_method_checked (method, &context, error);
911 g_assert (is_ok (error)); /* FIXME don't swallow the error */
913 return method;
917 * mono_exception_walk_native_trace:
918 * \param ex The exception object whose frames should be walked
919 * \param func callback to call for each stack frame
920 * \param user_data data passed to the callback
921 * This function walks the stacktrace of an exception. For
922 * each frame the callback function is called with the relevant info.
923 * The walk ends when no more stack frames are found or when the callback
924 * returns a TRUE value.
927 gboolean
928 mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
930 gboolean res;
932 MONO_ENTER_GC_UNSAFE;
933 res = mono_exception_walk_trace_internal (ex, func, user_data);
934 MONO_EXIT_GC_UNSAFE;
935 return res;
938 static gboolean
939 mono_exception_stackframe_obj_walk (MonoStackFrame *captured_frame, MonoExceptionFrameWalk func, gpointer user_data)
941 if (!captured_frame)
942 return TRUE;
944 gpointer ip = (gpointer) (captured_frame->method_address + captured_frame->native_offset);
945 MonoJitInfo *ji = mono_jit_info_table_find_internal (mono_domain_get (), ip, TRUE, TRUE);
947 // Other domain maybe?
948 if (!ji)
949 return FALSE;
950 MonoMethod *method = jinfo_get_method (ji);
952 gboolean r = func (method, (gpointer) captured_frame->method_address, captured_frame->native_offset, TRUE, user_data);
953 if (r)
954 return TRUE;
956 return FALSE;
959 static gboolean
960 mono_exception_stacktrace_obj_walk (MonoStackTrace *st, MonoExceptionFrameWalk func, gpointer user_data)
962 int num_captured = st->captured_traces ? mono_array_length_internal (st->captured_traces) : 0;
963 for (int i=0; i < num_captured; i++) {
964 MonoStackTrace *curr_trace = mono_array_get_fast (st->captured_traces, MonoStackTrace *, i);
965 mono_exception_stacktrace_obj_walk (curr_trace, func, user_data);
968 int num_frames = st->frames ? mono_array_length_internal (st->frames) : 0;
969 for (int frame = 0; frame < num_frames; frame++) {
970 gboolean r = mono_exception_stackframe_obj_walk (mono_array_get_fast (st->frames, MonoStackFrame *, frame), func, user_data);
971 if (r)
972 return TRUE;
975 return TRUE;
978 gboolean
979 mono_exception_walk_trace_internal (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
981 MONO_REQ_GC_UNSAFE_MODE;
983 MonoDomain *domain = mono_domain_get ();
984 MonoArray *ta = ex->trace_ips;
986 /* Exception is not thrown yet */
987 if (ta == NULL)
988 return FALSE;
990 int len = mono_array_length_internal (ta) / TRACE_IP_ENTRY_SIZE;
991 gboolean otherwise_has_traces = len > 0;
993 for (int i = 0; i < len; i++) {
994 ExceptionTraceIp trace_ip;
996 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
997 gpointer ip = trace_ip.ip;
998 gpointer generic_info = trace_ip.generic_info;
1000 MonoJitInfo *ji = NULL;
1001 if (trace_ip.ji) {
1002 ji = trace_ip.ji;
1003 } else {
1004 ji = mono_jit_info_table_find (domain, ip);
1007 if (ji == NULL) {
1008 gboolean r;
1009 MONO_ENTER_GC_SAFE;
1010 r = func (NULL, ip, 0, FALSE, user_data);
1011 MONO_EXIT_GC_SAFE;
1012 if (r)
1013 break;
1014 } else {
1015 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
1016 if (func (method, ji->code_start, (char *) ip - (char *) ji->code_start, TRUE, user_data))
1017 break;
1021 ta = (MonoArray *) ex->captured_traces;
1022 len = ta ? mono_array_length_internal (ta) : 0;
1023 gboolean captured_has_traces = len > 0;
1025 for (int i = 0; i < len; i++) {
1026 MonoStackTrace *captured_trace = mono_array_get_fast (ta, MonoStackTrace *, i);
1027 if (!captured_trace)
1028 break;
1030 mono_exception_stacktrace_obj_walk (captured_trace, func, user_data);
1033 return captured_has_traces || otherwise_has_traces;
1036 MonoArray *
1037 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
1039 ERROR_DECL (error);
1040 MonoDomain *domain = mono_domain_get ();
1041 MonoArray *res;
1042 MonoArray *ta = exc->trace_ips;
1043 MonoDebugSourceLocation *location;
1044 int i, len;
1046 if (ta == NULL) {
1047 /* Exception is not thrown yet */
1048 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, error);
1049 mono_error_set_pending_exception (error);
1050 return res;
1053 len = mono_array_length_internal (ta) / TRACE_IP_ENTRY_SIZE;
1055 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, error);
1056 if (mono_error_set_pending_exception (error))
1057 return NULL;
1059 for (i = skip; i < len; i++) {
1060 MonoJitInfo *ji;
1061 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
1062 if (!is_ok (error)) {
1063 mono_error_set_pending_exception (error);
1064 return NULL;
1066 ExceptionTraceIp trace_ip;
1067 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
1068 gpointer ip = trace_ip.ip;
1069 gpointer generic_info = trace_ip.generic_info;
1070 MonoMethod *method;
1072 if (trace_ip.ji) {
1073 ji = trace_ip.ji;
1074 } else {
1075 ji = mono_jit_info_table_find (domain, ip);
1076 if (ji == NULL) {
1077 /* Unmanaged frame */
1078 mono_array_setref_internal (res, i, sf);
1079 continue;
1083 g_assert (ji != NULL);
1085 if (mono_llvm_only || !generic_info)
1086 /* Can't resolve actual method */
1087 method = jinfo_get_method (ji);
1088 else
1089 method = get_method_from_stack_frame (ji, generic_info);
1090 if (jinfo_get_method (ji)->wrapper_type) {
1091 char *s;
1093 sf->method = NULL;
1094 s = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION);
1095 MonoString *name = mono_string_new_checked (domain, s, error);
1096 g_free (s);
1097 if (!is_ok (error)) {
1098 mono_error_set_pending_exception (error);
1099 return NULL;
1101 MONO_OBJECT_SETREF_INTERNAL (sf, internal_method_name, name);
1103 else {
1104 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
1105 if (!is_ok (error)) {
1106 mono_error_set_pending_exception (error);
1107 return NULL;
1109 MONO_OBJECT_SETREF_INTERNAL (sf, method, rm);
1112 sf->method_index = ji->from_aot ? mono_aot_find_method_index (method) : 0xffffff;
1113 sf->method_address = (gsize) ji->code_start;
1114 sf->native_offset = (char *)ip - (char *)ji->code_start;
1117 * mono_debug_lookup_source_location() returns both the file / line number information
1118 * and the IL offset. Note that computing the IL offset is already an expensive
1119 * operation, so we shouldn't call this method twice.
1121 location = mono_debug_lookup_source_location (jinfo_get_method (ji), sf->native_offset, domain);
1122 if (location) {
1123 sf->il_offset = location->il_offset;
1124 } else {
1125 SeqPoint sp;
1126 if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (ji), sf->native_offset, NULL, &sp))
1127 sf->il_offset = sp.il_offset;
1128 else
1129 sf->il_offset = -1;
1132 if (need_file_info) {
1133 if (location && location->source_file) {
1134 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1135 if (!is_ok (error)) {
1136 mono_error_set_pending_exception (error);
1137 return NULL;
1139 MONO_OBJECT_SETREF_INTERNAL (sf, filename, filename);
1140 sf->line = location->row;
1141 sf->column = location->column;
1142 } else {
1143 sf->line = sf->column = 0;
1144 sf->filename = NULL;
1148 mono_debug_free_source_location (location);
1149 mono_array_setref_internal (res, i - skip, sf);
1152 return res;
1155 static void
1156 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1158 if (!start_ctx) {
1159 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1160 if (jit_tls && jit_tls->orig_ex_ctx_set)
1161 start_ctx = &jit_tls->orig_ex_ctx;
1163 mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
1166 * mono_walk_stack_with_ctx:
1167 * Unwind the current thread starting at \p start_ctx.
1168 * If \p start_ctx is null, we capture the current context.
1170 void
1171 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1173 MonoContext extra_ctx;
1174 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1175 MONO_ARCH_CONTEXT_DEF
1177 if (!thread || !thread->jit_data)
1178 return;
1180 if (!start_ctx) {
1181 mono_arch_flush_register_windows ();
1182 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
1183 start_ctx = &extra_ctx;
1186 mono_walk_stack_full (func, start_ctx, mono_domain_get (), thread->jit_data, mono_get_lmf (), unwind_options, user_data, FALSE);
1190 * mono_walk_stack_with_state:
1191 * Unwind a thread described by \p state.
1193 * State must be valid (state->valid == TRUE).
1195 * If you are using this function to unwind another thread, make sure it is suspended.
1197 * If \p state is null, we capture the current context.
1199 void
1200 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
1202 MonoThreadUnwindState extra_state;
1203 if (!state) {
1204 g_assert (!mono_thread_info_is_async_context ());
1205 if (!mono_thread_state_init_from_current (&extra_state))
1206 return;
1207 state = &extra_state;
1210 g_assert (state->valid);
1212 if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
1213 /* Not attached */
1214 return;
1216 mono_walk_stack_full (func,
1217 &state->ctx,
1218 (MonoDomain *)state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
1219 (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
1220 (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF],
1221 unwind_options, user_data, FALSE);
1224 void
1225 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
1227 MonoThreadUnwindState state;
1228 if (!mono_thread_state_init_from_current (&state))
1229 return;
1230 mono_walk_stack_with_state (func, &state, options, user_data);
1234 * mono_walk_stack_full:
1235 * \param func callback to call for each stack frame
1236 * \param domain starting appdomain, can be NULL to use the current domain
1237 * \param unwind_options what extra information the unwinder should gather
1238 * \param start_ctx starting state of the stack walk, can be NULL.
1239 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1240 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1241 * \param user_data data passed to the callback
1242 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1243 * This function walks the stack of a thread, starting from the state
1244 * represented by \p start_ctx. For each frame the callback
1245 * function is called with the relevant info. The walk ends when no more
1246 * managed stack frames are found or when the callback returns a TRUE value.
1248 static void
1249 mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data, gboolean crash_context)
1251 gint il_offset;
1252 MonoContext ctx, new_ctx;
1253 StackFrameInfo frame;
1254 gboolean res;
1255 host_mgreg_t *reg_locations [MONO_MAX_IREGS];
1256 host_mgreg_t *new_reg_locations [MONO_MAX_IREGS];
1257 gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
1258 gboolean async = mono_thread_info_is_async_context ();
1259 Unwinder unwinder;
1261 memset (&frame, 0, sizeof (StackFrameInfo));
1263 #ifndef TARGET_WASM
1264 if (mono_llvm_only) {
1265 GSList *l, *ips;
1267 if (async)
1268 return;
1270 ips = get_unwind_backtrace ();
1271 for (l = ips; l; l = l->next) {
1272 guint8 *ip = (guint8*)l->data;
1273 memset (&frame, 0, sizeof (StackFrameInfo));
1274 frame.ji = mini_jit_info_table_find (domain, ip, &frame.domain);
1275 if (!frame.ji || frame.ji->is_trampoline)
1276 continue;
1277 frame.type = FRAME_TYPE_MANAGED;
1278 frame.method = jinfo_get_method (frame.ji);
1279 // FIXME: Cannot lookup the actual method
1280 frame.actual_method = frame.method;
1281 if (frame.type == FRAME_TYPE_MANAGED) {
1282 if (!frame.method->wrapper_type || frame.method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
1283 frame.managed = TRUE;
1285 frame.native_offset = ip - (guint8*)frame.ji->code_start;
1286 frame.il_offset = -1;
1288 if (func (&frame, NULL, user_data))
1289 break;
1291 g_slist_free (ips);
1292 return;
1294 #endif
1296 if (!start_ctx) {
1297 g_warning ("start_ctx required for stack walk");
1298 return;
1301 if (!domain) {
1302 g_warning ("domain required for stack walk");
1303 return;
1306 if (!jit_tls) {
1307 g_warning ("jit_tls required for stack walk");
1308 return;
1311 /*The LMF will be null if the target have no managed frames.*/
1312 /* g_assert (lmf); */
1313 if (async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD)) {
1314 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1315 return;
1318 memcpy (&ctx, start_ctx, sizeof (MonoContext));
1319 memset (reg_locations, 0, sizeof (reg_locations));
1321 unwinder_init (&unwinder);
1323 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
1324 frame.lmf = lmf;
1325 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
1326 if (!res)
1327 return;
1329 if (frame.type == FRAME_TYPE_TRAMPOLINE)
1330 goto next;
1332 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) {
1333 MonoDebugSourceLocation *source = NULL;
1335 // Don't do this when we can be in a signal handler
1336 if (!crash_context)
1337 source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
1338 if (source) {
1339 il_offset = source->il_offset;
1340 } else {
1341 MonoSeqPointInfo *seq_points = NULL;
1343 // It's more reliable to look into the global cache if possible
1344 if (crash_context)
1345 seq_points = (MonoSeqPointInfo *) frame.ji->seq_points;
1346 else
1347 seq_points = mono_get_seq_points (domain, jinfo_get_method (frame.ji));
1349 SeqPoint sp;
1350 if (seq_points && mono_seq_point_find_prev_by_native_offset (seq_points, frame.native_offset, &sp))
1351 il_offset = sp.il_offset;
1352 else
1353 il_offset = -1;
1355 mono_debug_free_source_location (source);
1356 } else
1357 il_offset = -1;
1359 frame.il_offset = il_offset;
1361 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) {
1362 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
1363 } else {
1364 frame.actual_method = frame.method;
1367 if (get_reg_locations)
1368 frame.reg_locations = reg_locations;
1370 if (func (&frame, &ctx, user_data))
1371 return;
1373 next:
1374 if (get_reg_locations) {
1375 for (int i = 0; i < MONO_MAX_IREGS; ++i)
1376 if (new_reg_locations [i])
1377 reg_locations [i] = new_reg_locations [i];
1380 ctx = new_ctx;
1384 #ifdef DISABLE_CRASH_REPORTING
1386 static void
1387 mono_summarize_managed_stack (MonoThreadSummary *out)
1389 return;
1392 static void
1393 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1395 return;
1398 static void
1399 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1401 return;
1404 static void
1405 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1407 return;
1410 static void
1411 mono_crash_reporting_allow_all_native_libraries ()
1413 return;
1417 #else
1419 typedef struct {
1420 MonoFrameSummary *frames;
1421 int num_frames;
1422 int max_frames;
1423 MonoStackHash *hashes;
1424 const char *error;
1425 } MonoSummarizeUserData;
1427 static void
1428 copy_summary_string_safe (char *dest, const char *src)
1430 g_strlcpy (dest, src, MONO_MAX_SUMMARY_NAME_LEN);
1433 static void
1434 fill_frame_managed_info (MonoFrameSummary *frame, MonoMethod * method)
1436 MonoImage *image = mono_class_get_image (method->klass);
1437 // Used for hashing, more stable across rebuilds than using GUID
1438 copy_summary_string_safe (frame->str_descr, image->assembly_name);
1440 frame->managed_data.guid = image->guid;
1441 frame->managed_data.token = method->token;
1442 frame->managed_data.filename = image->module_name;
1444 MonoDotNetHeader *header = &image->image_info->cli_header;
1445 frame->managed_data.image_size = header->nt.pe_image_size;
1446 frame->managed_data.time_date_stamp = image->time_date_stamp;
1449 typedef struct {
1450 char *suffix;
1451 char *exported_name;
1452 } MonoLibWhitelistEntry;
1454 static GList *native_library_whitelist;
1455 static gboolean allow_all_native_libraries = FALSE;
1457 static void
1458 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1460 // Examples: libsystem_pthread.dylib -> "pthread"
1461 // Examples: libsystem_platform.dylib -> "platform"
1462 // Examples: mono-sgen -> "mono" from above line
1463 MonoLibWhitelistEntry *entry = g_new0 (MonoLibWhitelistEntry, 1);
1464 entry->suffix = g_strdup (module_path);
1465 entry->exported_name = g_strdup (module_name);
1466 native_library_whitelist = g_list_append (native_library_whitelist, entry);
1469 static void
1470 mono_crash_reporting_allow_all_native_libraries ()
1472 allow_all_native_libraries = TRUE;
1475 static gboolean
1476 check_whitelisted_module (const char *in_name, const char **out_module)
1478 #ifndef MONO_PRIVATE_CRASHES
1479 return TRUE;
1480 #else
1481 if (g_str_has_suffix (in_name, "mono-sgen")) {
1482 if (out_module)
1483 copy_summary_string_safe ((char *) *out_module, "mono");
1484 return TRUE;
1486 if (allow_all_native_libraries) {
1487 if (out_module) {
1488 /* for a module name, use the basename of the full path in in_name */
1489 char *basename = (char *) in_name, *p = (char *) in_name;
1490 while (*p != '\0') {
1491 if (*p == '/')
1492 basename = p + 1;
1493 p++;
1495 if (*basename)
1496 copy_summary_string_safe ((char *) *out_module, basename);
1497 else
1498 copy_summary_string_safe ((char *) *out_module, "unknown");
1501 return TRUE;
1504 for (GList *cursor = native_library_whitelist; cursor; cursor = cursor->next) {
1505 MonoLibWhitelistEntry *iter = (MonoLibWhitelistEntry *) cursor->data;
1506 if (!g_str_has_suffix (in_name, iter->suffix))
1507 continue;
1508 if (out_module)
1509 copy_summary_string_safe ((char *) *out_module, iter->exported_name);
1510 return TRUE;
1513 return FALSE;
1514 #endif
1517 static intptr_t
1518 mono_make_portable_ip (intptr_t in_ip, intptr_t module_base)
1520 // FIXME: Make generalize away from llvm tools?
1521 // So lldb starts the pointer base at 0x100000000
1522 // and expects to get pointers as (offset + constant)
1524 // Quirk shared by:
1525 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1526 // *CoreSymbolicationDT.framework version: 63750*/
1527 intptr_t offset = in_ip - module_base;
1528 intptr_t magic_value = offset + 0x100000000;
1529 return magic_value;
1532 static gboolean
1533 mono_get_portable_ip (intptr_t in_ip, intptr_t *out_ip, gint32 *out_offset, const char **out_module, char *out_name)
1535 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1536 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1537 // non-recursive lock twice on this thread, and will deadlock.
1538 char sname [256], fname [256];
1539 void *saddr = NULL, *fbase = NULL;
1540 gboolean success = g_module_address ((void*)in_ip, fname, 256, &fbase, sname, 256, &saddr);
1541 if (!success)
1542 return FALSE;
1544 if (!check_whitelisted_module (fname, out_module))
1545 return FALSE;
1547 *out_ip = mono_make_portable_ip ((intptr_t) saddr, (intptr_t) fbase);
1548 *out_offset = in_ip - (intptr_t) saddr;
1550 if (saddr && out_name)
1551 copy_summary_string_safe (out_name, sname);
1552 return TRUE;
1555 static guint64
1556 summarize_offset_free_hash (guint64 accum, MonoFrameSummary *frame)
1558 if (!frame->is_managed)
1559 return accum;
1561 // See: mono_ptrarray_hash
1562 guint64 hash_accum = accum;
1564 // The assembly and the method token, no offsets
1565 hash_accum += mono_metadata_str_hash (frame->str_descr);
1566 hash_accum += frame->managed_data.token;
1568 return hash_accum;
1571 static guint64
1572 summarize_offset_rich_hash (guint64 accum, MonoFrameSummary *frame)
1574 // See: mono_ptrarray_hash
1575 guint64 hash_accum = accum;
1577 if (!frame->is_managed) {
1578 hash_accum += frame->unmanaged_data.ip;
1579 } else {
1580 hash_accum += mono_metadata_str_hash (frame->str_descr);
1581 hash_accum += frame->managed_data.token;
1582 hash_accum += frame->managed_data.il_offset;
1585 return hash_accum;
1588 static gboolean
1589 summarize_frame_internal (MonoMethod *method, gpointer ip, size_t native_offset, int il_offset, gboolean managed, gpointer user_data)
1591 MonoSummarizeUserData *ud = (MonoSummarizeUserData *) user_data;
1593 gboolean valid_state = ud->num_frames + 1 < ud->max_frames;
1594 if (!valid_state) {
1595 ud->error = "Exceeded the maximum number of frames";
1596 return TRUE;
1599 MonoFrameSummary *dest = &ud->frames [ud->num_frames];
1601 dest->unmanaged_data.ip = (intptr_t) ip;
1602 dest->is_managed = managed;
1603 dest->unmanaged_data.module [0] = '\0';
1605 if (!managed && method && method->wrapper_type != MONO_WRAPPER_NONE && method->wrapper_type < MONO_WRAPPER_NUM) {
1606 dest->is_managed = FALSE;
1607 dest->unmanaged_data.has_name = TRUE;
1608 copy_summary_string_safe (dest->str_descr, mono_wrapper_type_to_str (method->wrapper_type));
1611 #ifndef MONO_PRIVATE_CRASHES
1612 if (method)
1613 dest->managed_data.name = (char *) method->name;
1614 #endif
1616 if (managed) {
1617 if (!method) {
1618 ud->error = "Managed method frame, but no provided managed method";
1619 return TRUE;
1621 fill_frame_managed_info (dest, method);
1622 dest->managed_data.native_offset = native_offset;
1623 dest->managed_data.il_offset = il_offset;
1624 } else {
1625 dest->managed_data.token = -1;
1629 ud->hashes->offset_free_hash = summarize_offset_free_hash (ud->hashes->offset_free_hash, dest);
1630 ud->hashes->offset_rich_hash = summarize_offset_rich_hash (ud->hashes->offset_rich_hash, dest);
1632 // We return FALSE, so we're continuing walking
1633 // And we increment the pointer because we're done with this cell in the array
1634 ud->num_frames++;
1635 return FALSE;
1638 static gboolean
1639 summarize_frame_managed_walk (MonoMethod *method, gpointer ip, size_t frame_native_offset, gboolean managed, gpointer user_data)
1641 int il_offset = -1;
1643 if (managed && method) {
1644 MonoDebugSourceLocation *location = mono_debug_lookup_source_location (method, frame_native_offset, mono_domain_get ());
1645 if (location) {
1646 il_offset = location->il_offset;
1647 mono_debug_free_source_location (location);
1651 intptr_t portable_ip = 0;
1652 gint32 offset = 0;
1653 mono_get_portable_ip ((intptr_t) ip, &portable_ip, &offset, NULL, NULL);
1655 return summarize_frame_internal (method, (gpointer) portable_ip, frame_native_offset, il_offset, managed, user_data);
1659 static gboolean
1660 summarize_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
1662 // Don't record trampolines between managed frames
1663 if (frame->ji && frame->ji->is_trampoline)
1664 return TRUE;
1666 if (frame->ji && (frame->ji->is_trampoline || frame->ji->async))
1667 return FALSE; // Keep unwinding
1669 intptr_t ip = 0;
1670 gint32 offset = 0;
1671 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx), &ip, &offset, NULL, NULL);
1672 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1674 gboolean is_managed = (frame->type == FRAME_TYPE_MANAGED || frame->type == FRAME_TYPE_INTERP);
1675 MonoMethod *method = NULL;
1676 if (frame && frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
1677 method = jinfo_get_method (frame->ji);
1679 if (is_managed)
1680 method = jinfo_get_method (frame->ji);
1682 return summarize_frame_internal (method, (gpointer) ip, offset, frame->il_offset, is_managed, data);
1685 static void
1686 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1688 memset (out, 0, sizeof (MonoThreadSummary));
1690 MonoException *inner_exc = exc;
1691 int exc_index = 0;
1693 for (exc_index = 0; exc_index < MONO_MAX_SUMMARY_EXCEPTIONS; exc_index++) {
1694 if (inner_exc == NULL)
1695 break;
1697 // Set up state to walk this MonoException's stack
1698 MonoSummarizeUserData data;
1699 memset (&data, 0, sizeof (MonoSummarizeUserData));
1700 data.max_frames = MONO_MAX_SUMMARY_FRAMES;
1701 data.num_frames = 0;
1702 data.frames = out->exceptions [exc_index].managed_frames;
1704 // Accumulate all hashes from all exceptions in traveral order
1705 data.hashes = &out->hashes;
1707 mono_exception_walk_trace (inner_exc, summarize_frame_managed_walk, &data);
1709 // Save per-MonoException info
1710 out->exceptions [exc_index].managed_exc_type = inner_exc->object.vtable->klass;
1711 out->exceptions [exc_index].num_managed_frames = data.num_frames;
1713 // Continue to traverse nesting of exceptions
1714 inner_exc = (MonoException *) inner_exc->inner_ex;
1717 out->num_exceptions = exc_index;
1721 static void
1722 mono_summarize_managed_stack (MonoThreadSummary *out)
1724 MonoSummarizeUserData data;
1725 memset (&data, 0, sizeof (MonoSummarizeUserData));
1726 data.max_frames = MONO_MAX_SUMMARY_FRAMES;
1727 data.num_frames = 0;
1728 data.frames = out->managed_frames;
1729 data.hashes = &out->hashes;
1731 // FIXME: collect stack pointer for both and sort frames by SP
1732 // so people can see relative ordering of both managed and unmanaged frames.
1735 // Summarize managed stack
1737 mono_walk_stack_full (summarize_frame, out->ctx, out->domain, out->jit_tls, out->lmf, MONO_UNWIND_LOOKUP_IL_OFFSET, &data, TRUE);
1738 out->num_managed_frames = data.num_frames;
1740 if (data.error != NULL)
1741 out->error_msg = data.error;
1742 out->is_managed = (out->num_managed_frames != 0);
1745 // Always runs on the dumped thread
1746 static void
1747 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1749 MONO_ARCH_CONTEXT_DEF
1751 // Summarize unmanaged stack
1753 #ifdef HAVE_BACKTRACE_SYMBOLS
1754 intptr_t frame_ips [MONO_MAX_SUMMARY_FRAMES];
1756 out->num_unmanaged_frames = backtrace ((void **)frame_ips, MONO_MAX_SUMMARY_FRAMES);
1758 for (int i =0; i < out->num_unmanaged_frames; ++i) {
1759 intptr_t ip = frame_ips [i];
1760 MonoFrameSummary *frame = &out->unmanaged_frames [i];
1761 const char* module_buf = frame->unmanaged_data.module;
1762 int success = mono_get_portable_ip (ip, &frame->unmanaged_data.ip, &frame->unmanaged_data.offset, &module_buf, (char *) frame->str_descr);
1764 /* attempt to look up any managed method at that ip */
1765 /* TODO: Trampolines - follow examples from mono_print_method_from_ip() */
1767 MonoJitInfo *ji;
1768 MonoDomain *domain = mono_domain_get ();
1769 MonoDomain *target_domain;
1770 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
1771 if (ji) {
1772 frame->is_managed = TRUE;
1773 if (!ji->async && !ji->is_trampoline) {
1774 MonoMethod *method = jinfo_get_method (ji);
1775 fill_frame_managed_info (frame, method);
1776 #ifndef MONO_PRIVATE_CRASHES
1777 frame->managed_data.name = method->name;
1778 #endif
1782 if (!success && !ji) {
1783 frame->unmanaged_data.ip = ip;
1784 continue;
1787 if (out->unmanaged_frames [i].str_descr [0] != '\0')
1788 out->unmanaged_frames [i].unmanaged_data.has_name = TRUE;
1790 #endif
1792 out->lmf = mono_get_lmf ();
1794 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1795 out->info_addr = (intptr_t) thread;
1796 out->jit_tls = thread->jit_data;
1797 out->domain = mono_domain_get ();
1799 if (!out->ctx) {
1800 out->ctx = &out->ctx_mem;
1801 mono_arch_flush_register_windows ();
1802 MONO_INIT_CONTEXT_FROM_FUNC (out->ctx, mono_summarize_unmanaged_stack);
1805 return;
1807 #endif
1810 MonoBoolean
1811 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
1812 MonoReflectionMethod **method,
1813 gint32 *iloffset, gint32 *native_offset,
1814 MonoString **file, gint32 *line, gint32 *column)
1816 ERROR_DECL (error);
1817 MonoDomain *domain = mono_domain_get ();
1818 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1819 MonoLMF *lmf = mono_get_lmf ();
1820 MonoJitInfo *ji = NULL;
1821 MonoContext ctx, new_ctx;
1822 MonoDebugSourceLocation *location;
1823 MonoMethod *jmethod = NULL, *actual_method;
1824 StackFrameInfo frame;
1825 gboolean res;
1826 Unwinder unwinder;
1827 int il_offset = -1;
1829 MONO_ARCH_CONTEXT_DEF;
1831 g_assert (skip >= 0);
1833 if (mono_llvm_only) {
1834 GSList *l, *ips;
1835 MonoDomain *frame_domain;
1836 guint8 *frame_ip = NULL;
1838 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1839 jmethod = NULL;
1840 ips = get_unwind_backtrace ();
1841 for (l = ips; l && skip >= 0; l = l->next) {
1842 guint8 *ip = (guint8*)l->data;
1844 frame_ip = ip;
1846 ji = mini_jit_info_table_find (mono_domain_get (), ip, &frame_domain);
1847 if (!ji || ji->is_trampoline)
1848 continue;
1850 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1851 jmethod = jinfo_get_method (ji);
1852 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1853 continue;
1854 skip--;
1856 g_slist_free (ips);
1857 if (!jmethod || !l)
1858 return FALSE;
1859 /* No way to resolve generic instances */
1860 actual_method = jmethod;
1861 *native_offset = frame_ip - (guint8*)ji->code_start;
1862 } else {
1863 mono_arch_flush_register_windows ();
1864 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
1866 unwinder_init (&unwinder);
1868 new_ctx = ctx;
1869 do {
1870 ctx = new_ctx;
1871 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1872 if (!res)
1873 return FALSE;
1874 switch (frame.type) {
1875 case FRAME_TYPE_MANAGED_TO_NATIVE:
1876 case FRAME_TYPE_DEBUGGER_INVOKE:
1877 case FRAME_TYPE_TRAMPOLINE:
1878 case FRAME_TYPE_INTERP_TO_MANAGED:
1879 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
1880 continue;
1881 case FRAME_TYPE_INTERP:
1882 case FRAME_TYPE_MANAGED:
1883 ji = frame.ji;
1884 *native_offset = frame.native_offset;
1886 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1887 jmethod = jinfo_get_method (ji);
1888 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1889 continue;
1890 skip--;
1891 break;
1892 default:
1893 g_assert_not_reached ();
1895 } while (skip >= 0);
1897 if (frame.type == FRAME_TYPE_INTERP) {
1898 jmethod = frame.method;
1899 actual_method = frame.actual_method;
1900 } else {
1901 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
1905 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, error);
1906 if (!is_ok (error)) {
1907 mono_error_set_pending_exception (error);
1908 return FALSE;
1910 mono_gc_wbarrier_generic_store_internal (method, (MonoObject*) rm);
1912 if (il_offset != -1) {
1913 location = mono_debug_lookup_source_location_by_il (jmethod, il_offset, domain);
1914 } else {
1915 location = mono_debug_lookup_source_location (jmethod, *native_offset, domain);
1917 if (location)
1918 *iloffset = location->il_offset;
1919 else
1920 *iloffset = 0;
1922 if (need_file_info) {
1923 if (location) {
1924 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1925 if (!is_ok (error)) {
1926 mono_error_set_pending_exception (error);
1927 return FALSE;
1929 mono_gc_wbarrier_generic_store_internal (file, (MonoObject*)filename);
1930 *line = location->row;
1931 *column = location->column;
1932 } else {
1933 *file = NULL;
1934 *line = *column = 0;
1938 mono_debug_free_source_location (location);
1940 return TRUE;
1943 static MonoClass*
1944 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1946 ERROR_DECL (error);
1947 MonoClass *catch_class = ei->data.catch_class;
1948 MonoType *inflated_type;
1949 MonoGenericContext context;
1951 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1952 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
1953 return NULL;
1955 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1956 return catch_class;
1957 context = mono_get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1959 /* FIXME: we shouldn't inflate but instead put the
1960 type in the rgctx and fetch it from there. It
1961 might be a good idea to do this lazily, i.e. only
1962 when the exception is actually thrown, so as not to
1963 waste space for exception clauses which might never
1964 be encountered. */
1965 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
1966 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1968 catch_class = mono_class_from_mono_type_internal (inflated_type);
1969 mono_metadata_free_type (inflated_type);
1971 return catch_class;
1975 * mini_jit_info_table_find_ext:
1977 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1978 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1979 * OUT_DOMAIN if it is not NULL.
1981 MonoJitInfo*
1982 mini_jit_info_table_find_ext (MonoDomain *domain, gpointer addr, gboolean allow_trampolines, MonoDomain **out_domain)
1984 MonoJitInfo *ji;
1985 MonoInternalThread *t = mono_thread_internal_current ();
1986 gpointer *refs;
1988 if (out_domain)
1989 *out_domain = NULL;
1991 ji = mono_jit_info_table_find_internal (domain, addr, TRUE, allow_trampolines);
1992 if (ji) {
1993 if (out_domain)
1994 *out_domain = domain;
1995 return ji;
1998 /* maybe it is shared code, so we also search in the root domain */
1999 if (domain != mono_get_root_domain ()) {
2000 ji = mono_jit_info_table_find_internal (mono_get_root_domain (), addr, TRUE, allow_trampolines);
2001 if (ji) {
2002 if (out_domain)
2003 *out_domain = mono_get_root_domain ();
2004 return ji;
2008 if (!t)
2009 return NULL;
2011 refs = (gpointer *)((t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL);
2012 for (; refs && *refs; refs++) {
2013 if (*refs != domain && *refs != mono_get_root_domain ()) {
2014 ji = mono_jit_info_table_find_internal ((MonoDomain*) *refs, addr, TRUE, allow_trampolines);
2015 if (ji) {
2016 if (out_domain)
2017 *out_domain = (MonoDomain*) *refs;
2018 return ji;
2023 return NULL;
2026 MonoJitInfo*
2027 mini_jit_info_table_find (MonoDomain *domain, gpointer addr, MonoDomain **out_domain)
2029 return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain);
2032 /* Class lazy loading functions */
2033 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
2036 * wrap_non_exception_throws:
2038 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
2039 * WrapNonExceptionThrows flag set.
2041 static gboolean
2042 wrap_non_exception_throws (MonoMethod *m)
2044 ERROR_DECL (error);
2045 MonoAssembly *ass = m_class_get_image (m->klass)->assembly;
2046 MonoCustomAttrInfo* attrs;
2047 MonoClass *klass;
2048 int i;
2049 gboolean val = FALSE;
2051 if (m->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
2052 MonoDynamicMethod *dm = (MonoDynamicMethod *)m;
2053 if (dm->assembly)
2054 ass = dm->assembly;
2056 g_assert (ass);
2057 if (ass->wrap_non_exception_throws_inited)
2058 return ass->wrap_non_exception_throws;
2060 klass = mono_class_get_runtime_compat_attr_class ();
2062 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, error);
2063 mono_error_cleanup (error); /* FIXME don't swallow the error */
2064 if (attrs) {
2065 for (i = 0; i < attrs->num_attrs; ++i) {
2066 MonoCustomAttrEntry *attr = &attrs->attrs [i];
2067 const gchar *p;
2068 int num_named, named_type, name_len;
2069 char *name;
2071 if (!attr->ctor || attr->ctor->klass != klass)
2072 continue;
2073 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2074 p = (const char*)attr->data;
2075 g_assert (read16 (p) == 0x0001);
2076 p += 2;
2077 num_named = read16 (p);
2078 if (num_named != 1)
2079 continue;
2080 p += 2;
2081 named_type = *p;
2082 p ++;
2083 /* data_type = *p; */
2084 p ++;
2085 /* Property */
2086 if (named_type != 0x54)
2087 continue;
2088 name_len = mono_metadata_decode_blob_size (p, &p);
2089 name = (char *)g_malloc (name_len + 1);
2090 memcpy (name, p, name_len);
2091 name [name_len] = 0;
2092 p += name_len;
2093 g_assert (!strcmp (name, "WrapNonExceptionThrows"));
2094 g_free (name);
2095 /* The value is a BOOLEAN */
2096 val = *p;
2098 mono_custom_attrs_free (attrs);
2101 ass->wrap_non_exception_throws = val;
2102 mono_memory_barrier ();
2103 ass->wrap_non_exception_throws_inited = TRUE;
2105 return val;
2108 #define MAX_UNMANAGED_BACKTRACE 128
2109 static MonoArray*
2110 build_native_trace (MonoError *error)
2112 error_init (error);
2113 /* This puppy only makes sense on mobile, IOW, ARM. */
2114 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2115 MonoArray *res;
2116 void *native_trace [MAX_UNMANAGED_BACKTRACE];
2117 int size = -1;
2118 MONO_ENTER_GC_SAFE;
2119 size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE);
2120 MONO_EXIT_GC_SAFE;
2121 int i;
2123 if (!size)
2124 return NULL;
2125 res = mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, size, error);
2126 return_val_if_nok (error, NULL);
2128 for (i = 0; i < size; i++)
2129 mono_array_set_internal (res, gpointer, i, native_trace [i]);
2130 return res;
2131 #else
2132 return NULL;
2133 #endif
2136 static void
2137 remove_wrappers_from_trace (GList **trace_ips_p)
2139 GList *trace_ips = *trace_ips_p;
2140 GList *p = trace_ips;
2142 /* jit info, generic info, ip */
2143 while (p) {
2144 MonoJitInfo *jinfo = (MonoJitInfo*) p->data;
2145 GList *next_p = p->next->next->next;
2146 /* FIXME Maybe remove more wrapper types */
2147 if (jinfo->d.method->wrapper_type == MONO_WRAPPER_OTHER) {
2148 trace_ips = g_list_delete_link (trace_ips, p->next->next);
2149 trace_ips = g_list_delete_link (trace_ips, p->next);
2150 trace_ips = g_list_delete_link (trace_ips, p);
2152 p = next_p;
2155 *trace_ips_p = trace_ips;
2158 /* This can be called more than once on a MonoException. */
2159 static void
2160 setup_stack_trace (MonoException *mono_ex, GSList **dynamic_methods, GList *trace_ips, gboolean remove_wrappers)
2162 if (mono_ex) {
2163 GList *trace_ips_copy = g_list_copy (trace_ips);
2164 if (remove_wrappers)
2165 remove_wrappers_from_trace (&trace_ips_copy);
2166 trace_ips_copy = g_list_reverse (trace_ips_copy);
2167 ERROR_DECL (error);
2168 MonoArray *ips_arr = mono_glist_to_array (trace_ips_copy, mono_defaults.int_class, error);
2169 mono_error_assert_ok (error);
2170 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
2171 MONO_OBJECT_SETREF_INTERNAL (mono_ex, native_trace_ips, build_native_trace (error));
2172 mono_error_assert_ok (error);
2173 if (*dynamic_methods) {
2174 /* These methods could go away anytime, so save a reference to them in the exception object */
2175 GSList *l;
2176 MonoMList *list = (MonoMList*)mono_ex->dynamic_methods;
2178 for (l = *dynamic_methods; l; l = l->next) {
2179 guint32 dis_link;
2180 MonoDomain *domain = mono_domain_get ();
2182 if (domain->method_to_dyn_method) {
2183 mono_domain_lock (domain);
2184 dis_link = (guint32)(size_t)g_hash_table_lookup (domain->method_to_dyn_method, l->data);
2185 mono_domain_unlock (domain);
2186 if (dis_link) {
2187 MonoObject *o = mono_gchandle_get_target_internal (dis_link);
2188 if (o) {
2189 list = mono_mlist_prepend_checked (list, o, error);
2190 mono_error_assert_ok (error);
2196 MONO_OBJECT_SETREF_INTERNAL (mono_ex, dynamic_methods, list);
2198 g_slist_free (*dynamic_methods);
2199 *dynamic_methods = NULL;
2202 g_list_free (trace_ips_copy);
2206 typedef enum {
2207 MONO_FIRST_PASS_UNHANDLED,
2208 MONO_FIRST_PASS_CALLBACK_TO_NATIVE,
2209 MONO_FIRST_PASS_HANDLED,
2210 } MonoFirstPassResult;
2213 * handle_exception_first_pass:
2215 * The first pass of exception handling. Unwind the stack until a catch
2216 * clause which can catch OBJ is found. Store the index of the filter clause
2217 * which caught the exception into OUT_FILTER_IDX. Return
2218 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2219 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2220 * wrapper and an exception handling callback is installed (in which case
2221 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2223 static MonoFirstPassResult
2224 handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception, StackFrameInfo *catch_frame, gboolean *last_mono_wrapper_runtime_invoke)
2226 ERROR_DECL (error);
2227 MonoDomain *domain = mono_domain_get ();
2228 MonoJitInfo *ji = NULL;
2229 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2230 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2231 MonoLMF *lmf = mono_get_lmf ();
2232 GList *trace_ips = NULL;
2233 GSList *dynamic_methods = NULL;
2234 MonoException *mono_ex;
2235 gboolean stack_overflow = FALSE;
2236 MonoContext initial_ctx;
2237 MonoMethod *method;
2238 int frame_count = 0;
2239 gint32 filter_idx;
2240 int i;
2241 MonoObject *ex_obj;
2242 Unwinder unwinder;
2243 gboolean in_interp;
2245 MonoFirstPassResult result = MONO_FIRST_PASS_UNHANDLED;
2247 g_assert (ctx != NULL);
2248 *last_mono_wrapper_runtime_invoke = TRUE;
2249 if (obj == (MonoObject *)domain->stack_overflow_ex)
2250 stack_overflow = TRUE;
2252 mono_ex = (MonoException*)obj;
2253 MonoArray *initial_trace_ips = mono_ex->trace_ips;
2254 if (initial_trace_ips) {
2255 int len = mono_array_length_internal (initial_trace_ips) / TRACE_IP_ENTRY_SIZE;
2257 // If we catch in managed/non-wrapper, we don't save the catching frame
2258 if (!mono_ex->caught_in_unmanaged)
2259 len -= 1;
2261 for (i = 0; i < len; i++) {
2262 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
2263 gpointer p = mono_array_get_internal (initial_trace_ips, gpointer, (i * TRACE_IP_ENTRY_SIZE) + j);
2264 trace_ips = g_list_prepend (trace_ips, p);
2269 // Reset the state because we're making it be caught somewhere
2270 if (mono_ex->caught_in_unmanaged)
2271 MONO_OBJECT_SETREF_INTERNAL (mono_ex, caught_in_unmanaged, 0);
2273 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2274 mono_error_assert_ok (error);
2275 mono_ex = NULL;
2278 if (!call_filter)
2279 call_filter = (int (*) (MonoContext *, void *))mono_get_call_filter ();
2281 g_assert (jit_tls->end_of_stack);
2282 g_assert (jit_tls->abort_func);
2284 if (out_filter_idx)
2285 *out_filter_idx = -1;
2286 if (out_ji)
2287 *out_ji = NULL;
2288 if (out_prev_ji)
2289 *out_prev_ji = NULL;
2290 filter_idx = 0;
2291 initial_ctx = *ctx;
2293 unwinder_init (&unwinder);
2295 while (1) {
2296 MonoContext new_ctx;
2297 guint32 free_stack;
2298 int clause_index_start = 0;
2299 gboolean unwind_res = TRUE;
2301 StackFrameInfo frame;
2303 if (out_prev_ji)
2304 *out_prev_ji = ji;
2306 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2307 if (!unwind_res) {
2308 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, FALSE);
2309 g_list_free (trace_ips);
2310 return result;
2313 switch (frame.type) {
2314 case FRAME_TYPE_DEBUGGER_INVOKE:
2315 case FRAME_TYPE_MANAGED_TO_NATIVE:
2316 case FRAME_TYPE_TRAMPOLINE:
2317 case FRAME_TYPE_INTERP_TO_MANAGED:
2318 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2319 *ctx = new_ctx;
2320 continue;
2321 case FRAME_TYPE_INTERP:
2322 case FRAME_TYPE_MANAGED:
2323 break;
2324 default:
2325 g_assert_not_reached ();
2326 break;
2329 in_interp = frame.type == FRAME_TYPE_INTERP;
2330 ji = frame.ji;
2332 gpointer ip;
2333 if (in_interp)
2334 ip = (guint8*)ji->code_start + frame.native_offset;
2335 else
2336 ip = MONO_CONTEXT_GET_IP (ctx);
2338 frame_count ++;
2339 method = jinfo_get_method (ji);
2340 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2342 if (mini_debug_options.reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2343 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2344 "The native frame called the managed method:\n%s\n",
2345 mono_method_full_name (method, TRUE));
2348 if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
2349 // avoid giant stack traces during a stack overflow
2350 if (frame_count < 1000) {
2351 trace_ips = g_list_prepend (trace_ips, ip);
2352 trace_ips = g_list_prepend (trace_ips, get_generic_info_from_stack_frame (ji, ctx));
2353 trace_ips = g_list_prepend (trace_ips, ji);
2357 if (method->dynamic)
2358 dynamic_methods = g_slist_prepend (dynamic_methods, method);
2360 if (stack_overflow) {
2361 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2362 } else {
2363 free_stack = 0xffffff;
2366 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && ftnptr_eh_callback) {
2367 result = MONO_FIRST_PASS_CALLBACK_TO_NATIVE;
2371 for (i = clause_index_start; i < ji->num_clauses; i++) {
2372 MonoJitExceptionInfo *ei = &ji->clauses [i];
2373 gboolean filtered = FALSE;
2376 * During stack overflow, wait till the unwinding frees some stack
2377 * space before running handlers/finalizers.
2379 if (free_stack <= (64 * 1024))
2380 continue;
2382 if (is_address_protected (ji, ei, ip)) {
2383 /* catch block */
2384 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2387 * Have to unwrap RuntimeWrappedExceptions if the
2388 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2390 if (non_exception && !wrap_non_exception_throws (method))
2391 ex_obj = non_exception;
2392 else
2393 ex_obj = obj;
2395 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2396 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, FALSE);
2398 #ifndef DISABLE_PERFCOUNTERS
2399 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_filters);
2400 #endif
2402 if (!ji->is_interp) {
2403 #ifndef MONO_CROSS_COMPILE
2404 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2405 if (ji->from_llvm)
2406 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2407 else
2408 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2409 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2410 #else
2411 g_assert (!ji->from_llvm);
2412 /* store the exception object in bp + ei->exvar_offset */
2413 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2414 #endif
2415 #endif
2417 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2419 * Pass the original il clause index to the landing pad so it can
2420 * branch to the landing pad associated with the il clause.
2421 * This is needed because llvm compiled code assumes that the EH
2422 * code always branches to the innermost landing pad.
2424 if (ji->from_llvm)
2425 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2426 #endif
2429 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex, ctx, &initial_ctx);
2431 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2432 jit_tls->orig_ex_ctx_set = TRUE;
2433 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2434 jit_tls->orig_ex_ctx_set = FALSE;
2437 if (ji->is_interp) {
2438 /* The filter ends where the exception handler starts */
2439 filtered = mini_get_interp_callbacks ()->run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter, ei->handler_start);
2440 } else {
2441 filtered = call_filter (ctx, ei->data.filter);
2443 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex, ctx, &initial_ctx);
2444 if (filtered && out_filter_idx)
2445 *out_filter_idx = filter_idx;
2446 if (out_ji)
2447 *out_ji = ji;
2448 filter_idx ++;
2450 if (filtered) {
2451 g_list_free (trace_ips);
2452 /* mono_debugger_agent_handle_exception () needs this */
2453 mini_set_abort_threshold (&frame);
2454 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2455 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
2456 *catch_frame = frame;
2457 result = MONO_FIRST_PASS_HANDLED;
2458 return result;
2462 ERROR_DECL (isinst_error); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2463 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, error)) {
2464 /* runtime invokes catch even unhandled exceptions */
2465 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE);
2466 g_list_free (trace_ips);
2468 if (out_ji)
2469 *out_ji = ji;
2471 /* mono_debugger_agent_handle_exception () needs this */
2472 if (!in_interp)
2473 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2474 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
2475 *catch_frame = frame;
2476 result = MONO_FIRST_PASS_HANDLED;
2477 if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2478 //try to find threadpool_perform_wait_callback_method
2479 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &new_ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2480 while (unwind_res) {
2481 if (frame.ji && !frame.ji->is_trampoline && jinfo_get_method (frame.ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2482 *last_mono_wrapper_runtime_invoke = FALSE;
2483 break;
2485 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &new_ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2488 return result;
2490 mono_error_cleanup (isinst_error);
2494 *ctx = new_ctx;
2497 g_assert_not_reached ();
2501 * We implement delaying of aborts when in finally blocks by reusing the
2502 * abort protected block mechanism. The problem is that when throwing an
2503 * exception in a finally block we don't get to exit the protected block.
2504 * We exit it here when unwinding. Given that the order of the clauses
2505 * in the jit info is from inner clauses to the outer clauses, when we
2506 * want to exit the finally blocks inner to the clause that handles the
2507 * exception, we need to search up to its index.
2509 * FIXME We should do this inside interp, but with mixed mode we can
2510 * resume directly, without giving control back to the interp.
2512 static void
2513 interp_exit_finally_abort_blocks (MonoJitInfo *ji, int start_clause, int end_clause, gpointer ip)
2515 int i;
2516 for (i = start_clause; i < end_clause; i++) {
2517 MonoJitExceptionInfo *ei = &ji->clauses [i];
2518 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY &&
2519 ip >= ei->handler_start &&
2520 ip < ei->data.handler_end) {
2521 mono_threads_end_abort_protected_block ();
2526 static MonoException *
2527 mono_get_exception_runtime_wrapped_checked (MonoObject *wrapped_exception_raw, MonoError *error)
2529 HANDLE_FUNCTION_ENTER ();
2530 MONO_HANDLE_DCL (MonoObject, wrapped_exception);
2531 MonoExceptionHandle ret = mono_get_exception_runtime_wrapped_handle (wrapped_exception, error);
2532 HANDLE_FUNCTION_RETURN_OBJ (ret);
2536 * mono_handle_exception_internal:
2537 * \param ctx saved processor state
2538 * \param obj the exception object
2539 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2541 static gboolean
2542 mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji)
2544 ERROR_DECL (error);
2545 MonoDomain *domain = mono_domain_get ();
2546 MonoJitInfo *ji, *prev_ji;
2547 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2548 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2549 MonoLMF *lmf = mono_get_lmf ();
2550 MonoException *mono_ex;
2551 gboolean stack_overflow = FALSE;
2552 MonoContext initial_ctx;
2553 MonoMethod *method;
2554 int frame_count = 0;
2555 gint32 filter_idx, first_filter_idx = 0;
2556 int i;
2557 MonoObject *ex_obj = NULL;
2558 MonoObject *non_exception = NULL;
2559 Unwinder unwinder;
2560 gboolean in_interp;
2561 gboolean is_caught_unmanaged = FALSE;
2562 gboolean last_mono_wrapper_runtime_invoke = TRUE;
2564 g_assert (ctx != NULL);
2565 if (!obj) {
2566 MonoException *ex = mono_get_exception_null_reference ();
2567 MonoString *msg = mono_string_new_checked (domain, "Object reference not set to an instance of an object", error);
2568 mono_error_assert_ok (error);
2569 MONO_OBJECT_SETREF_INTERNAL (ex, message, msg);
2570 obj = (MonoObject *)ex;
2574 * Allocate a new exception object instead of the preconstructed ones.
2576 if (obj == (MonoObject *)domain->stack_overflow_ex) {
2578 * It is not a good idea to try and put even more pressure on the little stack available.
2579 * obj = mono_get_exception_stack_overflow ();
2581 stack_overflow = TRUE;
2583 else if (obj == (MonoObject *)domain->null_reference_ex) {
2584 obj = (MonoObject *)mono_get_exception_null_reference ();
2587 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2588 mono_error_assert_ok (error);
2589 non_exception = obj;
2590 obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, error);
2591 mono_error_assert_ok (error);
2594 mono_ex = (MonoException*)obj;
2596 if (mini_debug_options.suspend_on_exception) {
2597 mono_runtime_printf_err ("Exception thrown, suspending...");
2598 while (1)
2602 if (mono_ex->caught_in_unmanaged)
2603 is_caught_unmanaged = TRUE;
2606 if (mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2607 mono_ex = (MonoException*)obj;
2608 } else {
2609 mono_error_assert_ok (error);
2610 mono_ex = NULL;
2613 if (mono_ex && jit_tls->class_cast_from) {
2614 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "InvalidCastException")) {
2615 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
2616 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
2617 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
2618 mono_ex->message = mono_string_new_checked (domain, msg, error);
2619 g_free (from_name);
2620 g_free (to_name);
2621 if (!is_ok (error)) {
2622 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg);
2623 mono_error_assert_ok (error);
2625 g_free (msg);
2627 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "ArrayTypeMismatchException")) {
2628 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
2629 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
2630 char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
2631 mono_ex->message = mono_string_new_checked (domain, msg, error);
2632 g_free (from_name);
2633 g_free (to_name);
2634 if (!is_ok (error)) {
2635 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg);
2636 mono_error_assert_ok (error);
2638 g_free (msg);
2642 if (!call_filter)
2643 call_filter = (int (*)(MonoContext *, void*))mono_get_call_filter ();
2645 g_assert (jit_tls->end_of_stack);
2646 g_assert (jit_tls->abort_func);
2649 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2650 * end up being TRUE on any code path.
2652 memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
2654 if (!resume) {
2655 MonoContext ctx_cp = *ctx;
2656 if (mono_trace_is_enabled ()) {
2657 ERROR_DECL (error);
2658 MonoMethod *system_exception_get_message = mono_class_get_method_from_name_checked (mono_defaults.exception_class, "get_Message", 0, 0, error);
2659 mono_error_cleanup (error);
2660 error_init (error);
2661 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method_internal (obj, system_exception_get_message);
2662 MonoObject *message;
2663 const char *type_name = m_class_get_name (mono_object_class (mono_ex));
2664 char *msg = NULL;
2665 if (get_message == NULL) {
2666 message = NULL;
2667 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
2668 message = NULL;
2669 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
2670 } else {
2671 MonoObject *exc = NULL;
2672 message = mono_runtime_try_invoke (get_message, obj, NULL, &exc, error);
2673 g_assert (exc == NULL);
2674 mono_error_assert_ok (error);
2676 if (msg == NULL) {
2677 if (message) {
2678 msg = mono_string_to_utf8_checked_internal ((MonoString *) message, error);
2679 if (!is_ok (error)) {
2680 mono_error_cleanup (error);
2681 msg = g_strdup ("(error while display System.Exception.Message property)");
2683 } else {
2684 msg = g_strdup ("(System.Exception.Message property not available)");
2687 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)mono_native_thread_id_get (), m_class_get_name_space (mono_object_class (obj)), m_class_get_name (mono_object_class (obj)), msg);
2688 g_free (msg);
2689 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
2690 mono_print_thread_dump_from_ctx (ctx);
2692 jit_tls->orig_ex_ctx_set = TRUE;
2693 MONO_PROFILER_RAISE (exception_throw, (obj));
2694 jit_tls->orig_ex_ctx_set = FALSE;
2696 StackFrameInfo catch_frame;
2697 MonoFirstPassResult res;
2698 res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame, &last_mono_wrapper_runtime_invoke);
2700 if (res == MONO_FIRST_PASS_UNHANDLED) {
2701 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2702 /* Reached the top interpreted frames, but there might be native frames above us */
2703 throw_exception (obj, TRUE);
2704 g_assert_not_reached ();
2706 if (mini_debug_options.break_on_exc)
2707 G_BREAKPOINT ();
2708 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2710 // FIXME: This runs managed code so it might cause another stack overflow when
2711 // we are handling a stack overflow
2712 mini_set_abort_threshold (&catch_frame);
2713 mono_unhandled_exception_internal (obj);
2714 } else {
2715 gboolean unhandled = FALSE;
2718 * The exceptions caught by the mono_runtime_invoke_checked () calls
2719 * in the threadpool needs to be treated as unhandled (#669836).
2721 * FIXME: The check below is hackish, but its hard to distinguish
2722 * these runtime invoke calls from others in the runtime.
2724 #ifndef ENABLE_NETCORE
2725 if (ji && jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2726 if (prev_ji && jinfo_get_method (prev_ji) == mono_defaults.threadpool_perform_wait_callback_method)
2727 unhandled = TRUE;
2729 #endif
2731 if (unhandled)
2732 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2733 else if (!ji || (jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
2734 if (last_mono_wrapper_runtime_invoke && !mono_thread_internal_current ()->threadpool_thread) {
2735 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2736 if (mini_get_debug_options ()->top_runtime_invoke_unhandled) {
2737 mini_set_abort_threshold (&catch_frame);
2738 mono_unhandled_exception_internal (obj);
2740 } else {
2741 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2744 else if (res != MONO_FIRST_PASS_CALLBACK_TO_NATIVE)
2745 if (!is_caught_unmanaged)
2746 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2750 if (out_ji)
2751 *out_ji = NULL;
2752 filter_idx = 0;
2753 initial_ctx = *ctx;
2755 unwinder_init (&unwinder);
2757 while (1) {
2758 MonoContext new_ctx;
2759 guint32 free_stack;
2760 int clause_index_start = 0;
2761 gboolean unwind_res = TRUE;
2762 StackFrameInfo frame;
2763 gpointer ip;
2765 if (resume) {
2766 resume = FALSE;
2767 ji = jit_tls->resume_state.ji;
2768 new_ctx = jit_tls->resume_state.new_ctx;
2769 clause_index_start = jit_tls->resume_state.clause_index;
2770 lmf = jit_tls->resume_state.lmf;
2771 first_filter_idx = jit_tls->resume_state.first_filter_idx;
2772 filter_idx = jit_tls->resume_state.filter_idx;
2773 in_interp = FALSE;
2774 } else {
2775 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2776 if (!unwind_res) {
2777 *(mono_get_lmf_addr ()) = lmf;
2779 jit_tls->abort_func (obj);
2780 g_assert_not_reached ();
2782 switch (frame.type) {
2783 case FRAME_TYPE_DEBUGGER_INVOKE:
2784 case FRAME_TYPE_MANAGED_TO_NATIVE:
2785 case FRAME_TYPE_TRAMPOLINE:
2786 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2787 *ctx = new_ctx;
2788 continue;
2789 case FRAME_TYPE_INTERP_TO_MANAGED:
2790 continue;
2791 case FRAME_TYPE_INTERP:
2792 case FRAME_TYPE_MANAGED:
2793 break;
2794 default:
2795 g_assert_not_reached ();
2796 break;
2798 in_interp = frame.type == FRAME_TYPE_INTERP;
2799 ji = frame.ji;
2802 if (in_interp)
2803 ip = (guint8*)ji->code_start + frame.native_offset;
2804 else
2805 ip = MONO_CONTEXT_GET_IP (ctx);
2807 method = jinfo_get_method (ji);
2808 frame_count ++;
2809 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2811 if (stack_overflow) {
2812 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2813 } else {
2814 free_stack = 0xffffff;
2817 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && ftnptr_eh_callback) {
2818 guint32 handle = mono_gchandle_new_internal (obj, FALSE);
2819 MONO_STACKDATA (stackptr);
2821 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr);
2822 mono_set_lmf (lmf);
2823 ftnptr_eh_callback (handle);
2824 g_error ("Did not expect ftnptr_eh_callback to return.");
2827 for (i = clause_index_start; i < ji->num_clauses; i++) {
2828 MonoJitExceptionInfo *ei = &ji->clauses [i];
2829 gboolean filtered = FALSE;
2832 * During stack overflow, wait till the unwinding frees some stack
2833 * space before running handlers/finalizers.
2835 if (free_stack <= (64 * 1024))
2836 continue;
2838 if (is_address_protected (ji, ei, ip)) {
2839 /* catch block */
2840 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2843 * Have to unwrap RuntimeWrappedExceptions if the
2844 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2846 if (non_exception && !wrap_non_exception_throws (method))
2847 ex_obj = non_exception;
2848 else
2849 ex_obj = obj;
2851 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
2852 #ifndef MONO_CROSS_COMPILE
2853 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2854 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2855 #else
2856 g_assert (!ji->from_llvm);
2857 /* store the exception object in bp + ei->exvar_offset */
2858 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2859 #endif
2860 #endif
2863 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2864 if (ji->from_llvm)
2865 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2866 #endif
2868 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2870 * Filter clauses should only be run in the
2871 * first pass of exception handling.
2873 filtered = (filter_idx == first_filter_idx);
2874 filter_idx ++;
2877 error_init (error);
2878 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
2879 mono_object_isinst_checked (ex_obj, catch_class, error)) || filtered) {
2881 * This guards against the situation that we abort a thread that is executing a finally clause
2882 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2883 * check for this situation here and resume interruption if we are below the guarded block.
2885 if (G_UNLIKELY (jit_tls->handler_block)) {
2886 gboolean is_outside = FALSE;
2887 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
2888 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
2889 //FIXME make this stack direction aware
2891 if (catch_bp > prot_bp) {
2892 is_outside = TRUE;
2893 } else if (catch_bp == prot_bp) {
2894 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2895 * So we check if the catch handler_start is protected by the guarded handler protected region
2897 * Assumptions:
2898 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2899 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2900 * There aren't any further finally/fault handler blocks down the stack over this exception.
2901 * This must be ensured by the code that installs the guard trampoline.
2903 g_assert (ji == mini_jit_info_table_find (domain, (char *)MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
2905 if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
2906 is_outside = TRUE;
2909 if (is_outside) {
2910 jit_tls->handler_block = NULL;
2911 mono_thread_resume_interruption (TRUE); /*We ignore the exception here, it will be raised later*/
2915 if (mono_trace_is_enabled () && mono_trace_eval (method))
2916 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2919 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2920 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2921 * clause. Since we specifically want to indicate that we're executing the
2922 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2923 * instead of ei->flags.
2925 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2926 jit_tls->orig_ex_ctx_set = TRUE;
2927 MONO_PROFILER_RAISE (exception_clause, (method, i, MONO_EXCEPTION_CLAUSE_NONE, ex_obj));
2928 jit_tls->orig_ex_ctx_set = FALSE;
2931 mini_set_abort_threshold (&frame);
2933 if (in_interp) {
2934 interp_exit_finally_abort_blocks (ji, clause_index_start, i, ip);
2936 * ctx->pc points into the interpreter, after the call which transitioned to
2937 * JITted code. Store the unwind state into the
2938 * interpeter state, then resume, the interpreter will unwind itself until
2939 * it reaches the target frame and will continue execution from there.
2940 * The resuming is kinda hackish, from the native code standpoint, it looks
2941 * like the call which transitioned to JITted code has succeeded, but the
2942 * return value register etc. is not set, so we have to be careful.
2944 mini_get_interp_callbacks ()->set_resume_state (jit_tls, mono_ex, ei, frame.interp_frame, ei->handler_start);
2945 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2946 /* ip == 0 means an interpreter frame */
2947 if (MONO_CONTEXT_GET_IP (ctx) != 0)
2948 mono_arch_undo_ip_adjustment (ctx);
2949 } else {
2950 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2952 mono_set_lmf (lmf);
2953 #ifndef DISABLE_PERFCOUNTERS
2954 mono_atomic_fetch_add_i32 (&mono_perfcounters->exceptions_depth, frame_count);
2955 #endif
2956 if (obj == (MonoObject *)domain->stack_overflow_ex)
2957 jit_tls->handling_stack_ovf = FALSE;
2959 return 0;
2961 mono_error_cleanup (error);
2962 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
2963 if (mono_trace_is_enabled () && mono_trace_eval (method))
2964 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2966 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2967 jit_tls->orig_ex_ctx_set = TRUE;
2968 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2969 jit_tls->orig_ex_ctx_set = FALSE;
2972 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2973 if (mono_trace_is_enabled () && mono_trace_eval (method))
2974 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2976 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2977 jit_tls->orig_ex_ctx_set = TRUE;
2978 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2979 jit_tls->orig_ex_ctx_set = FALSE;
2982 #ifndef DISABLE_PERFCOUNTERS
2983 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_finallys);
2984 #endif
2986 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2987 mono_set_lmf (lmf);
2988 if (ji->from_llvm) {
2990 * LLVM compiled finally handlers follow the design
2991 * of the c++ ehabi, i.e. they call a resume function
2992 * at the end instead of returning to the caller.
2993 * So save the exception handling state,
2994 * mono_resume_unwind () will call us again to continue
2995 * the unwinding.
2997 jit_tls->resume_state.ex_obj = obj;
2998 jit_tls->resume_state.ji = ji;
2999 jit_tls->resume_state.clause_index = i + 1;
3000 jit_tls->resume_state.ctx = *ctx;
3001 jit_tls->resume_state.new_ctx = new_ctx;
3002 jit_tls->resume_state.lmf = lmf;
3003 jit_tls->resume_state.first_filter_idx = first_filter_idx;
3004 jit_tls->resume_state.filter_idx = filter_idx;
3005 mini_set_abort_threshold (&frame);
3006 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
3007 return 0;
3008 } else {
3009 mini_set_abort_threshold (&frame);
3010 if (in_interp) {
3011 gboolean has_ex = mini_get_interp_callbacks ()->run_finally (&frame, i, ei->handler_start, ei->data.handler_end);
3012 if (has_ex) {
3014 * If run_finally didn't resume to a context, it means that the handler frame
3015 * is linked to the frame calling finally through interpreter frames. This
3016 * means that we will reach the handler frame by resuming the current context.
3018 if (MONO_CONTEXT_GET_IP (ctx) != 0)
3019 mono_arch_undo_ip_adjustment (ctx);
3020 return 0;
3022 } else {
3023 call_filter (ctx, ei->handler_start);
3030 if (in_interp)
3031 interp_exit_finally_abort_blocks (ji, clause_index_start, ji->num_clauses, ip);
3033 if (MONO_PROFILER_ENABLED (method_exception_leave) &&
3034 mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) {
3035 jit_tls->orig_ex_ctx_set = TRUE;
3036 MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
3037 jit_tls->orig_ex_ctx_set = FALSE;
3040 *ctx = new_ctx;
3043 g_assert_not_reached ();
3047 * mono_debugger_run_finally:
3048 * \param start_ctx saved processor state
3049 * This method is called by the Mono Debugger to call all \c finally clauses of the
3050 * current stack frame. It's used when the user issues a \c return command to make
3051 * the current stack frame return. After returning from this method, the debugger
3052 * unwinds the stack one frame and gives control back to the user.
3053 * NOTE: This method is only used when running inside the Mono Debugger.
3055 void
3056 mono_debugger_run_finally (MonoContext *start_ctx)
3058 static int (*call_filter) (MonoContext *, gpointer) = NULL;
3059 MonoDomain *domain = mono_domain_get ();
3060 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3061 MonoLMF *lmf = mono_get_lmf ();
3062 MonoContext ctx, new_ctx;
3063 MonoJitInfo *ji, rji;
3064 int i;
3066 ctx = *start_ctx;
3068 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
3069 if (!ji || ji == (gpointer)-1)
3070 return;
3072 if (!call_filter)
3073 call_filter = (int (*)(MonoContext *, void *))mono_get_call_filter ();
3075 for (i = 0; i < ji->num_clauses; i++) {
3076 MonoJitExceptionInfo *ei = &ji->clauses [i];
3078 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
3079 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
3080 call_filter (&ctx, ei->handler_start);
3086 * mono_handle_exception:
3087 * \param ctx saved processor state
3088 * \param obj the exception object
3090 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3091 * return TRUE.
3093 gboolean
3094 mono_handle_exception (MonoContext *ctx, gpointer void_obj)
3096 MonoObject *obj = (MonoObject*)void_obj;
3098 MONO_REQ_GC_UNSAFE_MODE;
3100 #ifndef DISABLE_PERFCOUNTERS
3101 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_thrown);
3102 #endif
3104 return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
3107 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3109 #ifndef MONO_ARCH_USE_SIGACTION
3110 #error "Can't use sigaltstack without sigaction"
3111 #endif
3113 void
3114 mono_setup_altstack (MonoJitTlsData *tls)
3116 size_t stsize = 0;
3117 stack_t sa;
3118 guint8 *staddr = NULL;
3119 #if defined(TARGET_OSX) || defined(_AIX)
3121 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3122 * stack pages. Stack overflow on main thread will kill the app.
3124 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3125 * do this for thread 1 with its stack at the top of memory. Other threads seem
3126 * fine for the altstack guard page, though.
3128 gboolean disable_stack_guard = mono_threads_platform_is_main_thread ();
3129 #else
3130 gboolean disable_stack_guard = FALSE;
3131 #endif
3133 if (mono_running_on_valgrind ())
3134 return;
3136 mono_thread_info_get_stack_bounds (&staddr, &stsize);
3138 g_assert (staddr);
3140 tls->end_of_stack = staddr + stsize;
3141 tls->stack_size = stsize;
3143 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3145 if (!disable_stack_guard) {
3146 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
3147 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
3149 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
3151 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
3152 /* mprotect can fail for the main thread stack */
3153 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);
3154 if (gaddr) {
3155 g_assert (gaddr == tls->stack_ovf_guard_base);
3156 tls->stack_ovf_valloced = TRUE;
3157 } else {
3158 g_warning ("couldn't allocate guard page, continue without it");
3159 tls->stack_ovf_guard_base = NULL;
3160 tls->stack_ovf_guard_size = 0;
3165 /* Setup an alternate signal stack */
3166 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);
3167 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3169 g_assert (tls->signal_stack);
3171 sa.ss_sp = tls->signal_stack;
3172 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3173 sa.ss_flags = 0;
3174 g_assert (sigaltstack (&sa, NULL) == 0);
3176 if (tls->stack_ovf_guard_base)
3177 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);
3178 else
3179 mono_gc_register_altstack (staddr, stsize, tls->signal_stack, tls->signal_stack_size);
3183 void
3184 mono_free_altstack (MonoJitTlsData *tls)
3186 stack_t sa;
3187 int err;
3189 sa.ss_sp = tls->signal_stack;
3190 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3191 sa.ss_flags = SS_DISABLE;
3192 err = sigaltstack (&sa, NULL);
3193 g_assert (err == 0);
3195 if (tls->signal_stack)
3196 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MEM_ACCOUNT_EXCEPTIONS);
3198 if (!tls->stack_ovf_guard_base)
3199 return;
3200 if (tls->stack_ovf_valloced)
3201 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MEM_ACCOUNT_EXCEPTIONS);
3202 else
3203 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3206 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3208 void
3209 mono_setup_altstack (MonoJitTlsData *tls)
3213 void
3214 mono_free_altstack (MonoJitTlsData *tls)
3218 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3220 gboolean
3221 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
3223 if (!jit_tls)
3224 return FALSE;
3226 if (mono_llvm_only)
3227 return FALSE;
3229 /* we got a stack overflow in the soft-guard pages
3230 * There are two cases:
3231 * 1) managed code caused the overflow: we unprotect the soft-guard page
3232 * and let the arch-specific code trigger the exception handling mechanism
3233 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3234 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3235 * and hope we can continue with those enabled, at least until the hard-guard page
3236 * is hit. The alternative to continuing here is to just print a message and abort.
3237 * We may add in the future the code to protect the pages again in the codepath
3238 * when we return from unmanaged to managed code.
3240 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
3241 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
3242 gboolean handled = FALSE;
3244 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3245 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3246 if (ji) {
3247 mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE);
3248 handled = TRUE;
3250 #endif
3251 if (!handled) {
3252 /* We print a message: after this even managed stack overflows
3253 * may crash the runtime
3255 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
3256 if (!jit_tls->handling_stack_ovf) {
3257 jit_tls->handling_stack_ovf = 1;
3258 } else {
3259 /*fprintf (stderr, "Already handling stack overflow\n");*/
3262 return TRUE;
3264 return FALSE;
3267 typedef struct {
3268 MonoMethod *omethod;
3269 int count;
3270 } PrintOverflowUserData;
3272 static gboolean
3273 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3275 MonoMethod *method = NULL;
3276 PrintOverflowUserData *user_data = (PrintOverflowUserData *)data;
3277 gchar *location;
3279 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3280 method = jinfo_get_method (frame->ji);
3282 if (method) {
3283 if (user_data->count == 0) {
3284 /* The first frame is in its prolog, so a line number cannot be computed */
3285 user_data->count ++;
3286 return FALSE;
3289 /* If this is a one method overflow, skip the other instances */
3290 if (method == user_data->omethod)
3291 return FALSE;
3293 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
3294 mono_runtime_printf_err (" %s", location);
3295 g_free (location);
3297 if (user_data->count == 1) {
3298 mono_runtime_printf_err (" <...>");
3299 user_data->omethod = method;
3300 } else {
3301 user_data->omethod = NULL;
3304 user_data->count ++;
3305 } else
3306 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame->native_offset);
3308 return FALSE;
3311 void
3312 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *mctx, guint8* fault_addr)
3314 PrintOverflowUserData ud;
3316 /* we don't do much now, but we can warn the user with a useful message */
3317 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx), fault_addr);
3319 mono_runtime_printf_err ("Stacktrace:");
3321 memset (&ud, 0, sizeof (ud));
3323 mono_walk_stack_with_ctx (print_overflow_stack_frame, mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
3325 _exit (1);
3328 static gboolean
3329 print_stack_frame_signal_safe (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3331 MonoMethod *method = NULL;
3333 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3334 method = jinfo_get_method (frame->ji);
3336 if (method) {
3337 const char *name_space = m_class_get_name_space (method->klass);
3338 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);
3339 } else {
3340 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame->native_offset);
3343 return FALSE;
3346 static G_GNUC_UNUSED gboolean
3347 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3349 GString *p = (GString*)data;
3350 MonoMethod *method = NULL;
3352 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3353 method = jinfo_get_method (frame->ji);
3355 if (method && frame->domain) {
3356 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3357 g_string_append_printf (p, " %s\n", location);
3358 g_free (location);
3359 } else
3360 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3362 return FALSE;
3365 #ifndef MONO_CROSS_COMPILE
3366 static gboolean handle_crash_loop = FALSE;
3369 * mono_handle_native_crash:
3371 * Handle a native crash (e.g. SIGSEGV) while in native code by
3372 * printing diagnostic information and aborting.
3374 void
3375 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3377 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3379 if (handle_crash_loop)
3380 return;
3382 #ifdef MONO_ARCH_USE_SIGACTION
3383 struct sigaction sa;
3384 sa.sa_handler = SIG_DFL;
3385 sigemptyset (&sa.sa_mask);
3386 sa.sa_flags = 0;
3388 /* Remove our SIGABRT handler */
3389 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
3391 /* On some systems we get a SIGILL when calling abort (), because it might
3392 * fail to raise SIGABRT */
3393 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
3395 /* Remove SIGCHLD, it uses the finalizer thread */
3396 g_assert (sigaction (SIGCHLD, &sa, NULL) != -1);
3398 /* Remove SIGQUIT, we are already dumping threads */
3399 g_assert (sigaction (SIGQUIT, &sa, NULL) != -1);
3401 #endif
3403 if (mini_debug_options.suspend_on_native_crash) {
3404 g_async_safe_printf ("Received %s, suspending...\n", signal);
3405 while (1) {
3406 // Sleep for 1 second.
3407 g_usleep (1000 * 1000);
3411 /* prevent infinite loops in crash handling */
3412 handle_crash_loop = TRUE;
3415 * A SIGSEGV indicates something went very wrong so we can no longer depend
3416 * on anything working. So try to print out lots of diagnostics, starting
3417 * with ones which have a greater chance of working.
3420 g_async_safe_printf("\n=================================================================\n");
3421 g_async_safe_printf("\tNative Crash Reporting\n");
3422 g_async_safe_printf("=================================================================\n");
3423 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal);
3424 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3425 g_async_safe_printf("used by your application.\n");
3426 g_async_safe_printf("=================================================================\n");
3427 mono_dump_native_crash_info (signal, mctx, info);
3429 /* !jit_tls means the thread was not registered with the runtime */
3430 // This must be below the native crash dump, because we can't safely
3431 // do runtime state probing after we have walked the managed stack here.
3432 if (jit_tls && mono_thread_internal_current () && mctx) {
3433 g_async_safe_printf ("\n=================================================================\n");
3434 g_async_safe_printf ("\tManaged Stacktrace:\n");
3435 g_async_safe_printf ("=================================================================\n");
3437 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);
3438 g_async_safe_printf ("=================================================================\n");
3441 mono_post_native_crash_handler (signal, mctx, info, mono_do_crash_chaining);
3444 #else
3446 void
3447 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3449 g_assert_not_reached ();
3452 #endif /* !MONO_CROSS_COMPILE */
3454 static void
3455 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
3457 MonoInternalThread *thread = mono_thread_internal_current ();
3458 MonoContext ctx;
3459 GString* text;
3461 if (!thread)
3462 return;
3464 text = g_string_new (0);
3466 mono_gstring_append_thread_name (text, thread);
3468 g_string_append_printf (text, " tid=%p this=%p ", (gpointer)(gsize)thread->tid, thread);
3469 mono_thread_internal_describe (thread, text);
3470 g_string_append (text, "\n");
3472 if (start_ctx) {
3473 memcpy (&ctx, start_ctx, sizeof (MonoContext));
3474 } else if (!sigctx)
3475 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
3476 else
3477 mono_sigctx_to_monoctx (sigctx, &ctx);
3479 mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
3481 mono_runtime_printf ("%s", text->str);
3483 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3484 OutputDebugStringA(text->str);
3485 #endif
3487 g_string_free (text, TRUE);
3488 mono_runtime_stdout_fflush ();
3492 * mono_print_thread_dump:
3494 * Print information about the current thread to stdout.
3495 * \p sigctx can be NULL, allowing this to be called from gdb.
3497 void
3498 mono_print_thread_dump (void *sigctx)
3500 mono_print_thread_dump_internal (sigctx, NULL);
3503 void
3504 mono_print_thread_dump_from_ctx (MonoContext *ctx)
3506 mono_print_thread_dump_internal (NULL, ctx);
3510 * mono_resume_unwind:
3512 * This is called by a trampoline from LLVM compiled finally clauses to continue
3513 * unwinding.
3515 void
3516 mono_resume_unwind (MonoContext *ctx)
3518 MONO_REQ_GC_UNSAFE_MODE;
3520 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3521 MonoContext new_ctx;
3523 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
3524 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
3525 new_ctx = *ctx;
3527 mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL);
3529 mono_restore_context (&new_ctx);
3532 typedef struct {
3533 MonoJitInfo *ji;
3534 MonoContext ctx;
3535 MonoJitExceptionInfo *ei;
3536 } FindHandlerBlockData;
3538 static gboolean
3539 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3541 int i;
3542 gpointer ip;
3543 FindHandlerBlockData *pdata = (FindHandlerBlockData *)data;
3544 MonoJitInfo *ji = frame->ji;
3546 if (!ji)
3547 return FALSE;
3549 ip = MONO_CONTEXT_GET_IP (ctx);
3551 for (i = 0; i < ji->num_clauses; ++i) {
3552 MonoJitExceptionInfo *ei = ji->clauses + i;
3553 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3554 continue;
3555 /*If ip points to the first instruction it means the handler block didn't start
3556 so we can leave its execution to the EH machinery*/
3557 if (ei->handler_start <= ip && ip < ei->data.handler_end) {
3558 pdata->ji = ji;
3559 pdata->ei = ei;
3560 pdata->ctx = *ctx;
3561 break;
3564 return FALSE;
3568 static void
3569 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
3571 int i;
3572 MonoJitExceptionInfo *clause = NULL;
3573 gpointer ip;
3574 guint8 *bp;
3576 ip = MONO_CONTEXT_GET_IP (ctx);
3578 for (i = 0; i < ji->num_clauses; ++i) {
3579 clause = &ji->clauses [i];
3580 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3581 continue;
3582 if (clause->handler_start <= ip && clause->data.handler_end > ip)
3583 break;
3586 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3587 g_assert (i < ji->num_clauses);
3589 /*Load the spvar*/
3590 bp = (guint8*)MONO_CONTEXT_GET_BP (ctx);
3591 *(bp + clause->exvar_offset) = 1;
3595 * Finds the bottom handler block running and install a block guard if needed.
3597 static gboolean
3598 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
3600 FindHandlerBlockData data = { 0 };
3601 MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
3603 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3604 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3606 if (!jit_tls || jit_tls->handler_block)
3607 return FALSE;
3609 /* Do an async safe stack walk */
3610 mono_thread_info_set_is_async_context (TRUE);
3611 mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data);
3612 mono_thread_info_set_is_async_context (FALSE);
3614 if (!data.ji)
3615 return FALSE;
3617 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
3619 install_handler_block_guard (data.ji, &data.ctx);
3621 jit_tls->handler_block = data.ei;
3623 return TRUE;
3626 static void
3627 mono_uninstall_current_handler_block_guard (void)
3629 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3630 if (jit_tls)
3631 jit_tls->handler_block = NULL;
3635 static gboolean
3636 mono_current_thread_has_handle_block_guard (void)
3638 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3639 return jit_tls && jit_tls->handler_block != NULL;
3642 void
3643 mono_set_cast_details (MonoClass *from, MonoClass *to)
3645 MonoJitTlsData *jit_tls = NULL;
3647 if (mini_debug_options.better_cast_details) {
3648 jit_tls = mono_tls_get_jit_tls ();
3649 jit_tls->class_cast_from = from;
3650 jit_tls->class_cast_to = to;
3655 /*returns false if the thread is not attached*/
3656 gboolean
3657 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
3659 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3660 if (!thread) {
3661 ctx->valid = FALSE;
3662 return FALSE;
3665 if (sigctx) {
3666 mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
3668 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3669 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3670 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3672 else {
3673 mono_thread_state_init (ctx);
3676 if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
3677 return FALSE;
3679 ctx->valid = TRUE;
3680 return TRUE;
3683 void
3684 mono_thread_state_init (MonoThreadUnwindState *ctx)
3686 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3688 #if defined(MONO_CROSS_COMPILE)
3689 ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
3690 #elif MONO_ARCH_HAS_MONO_CONTEXT
3691 MONO_CONTEXT_GET_CURRENT (ctx->ctx);
3692 #else
3693 g_error ("Use a null sigctx requires a working mono-context");
3694 #endif
3696 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3697 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3698 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
3699 ctx->valid = TRUE;
3703 gboolean
3704 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
3706 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3707 if (!thread) {
3708 ctx->valid = FALSE;
3709 return FALSE;
3712 ctx->ctx = *mctx;
3713 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3714 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3715 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3716 ctx->valid = TRUE;
3717 return TRUE;
3720 /*returns false if the thread is not attached*/
3721 gboolean
3722 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
3724 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3725 MONO_ARCH_CONTEXT_DEF
3727 mono_arch_flush_register_windows ();
3729 if (!thread || !thread->jit_data) {
3730 ctx->valid = FALSE;
3731 return FALSE;
3733 MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
3735 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3736 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3737 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3738 ctx->valid = TRUE;
3739 return TRUE;
3742 static void
3743 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
3745 mono_handle_exception (ctx, (MonoObject *)exc);
3746 mono_restore_context (ctx);
3749 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3750 void
3751 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
3753 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3754 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3755 jit_tls->ex_ctx = *ctx;
3757 mono_arch_setup_async_callback (ctx, async_cb, user_data);
3758 #else
3759 g_error ("This target doesn't support mono_arch_setup_async_callback");
3760 #endif
3764 * mono_restore_context:
3766 * Call the architecture specific restore context function.
3768 void
3769 mono_restore_context (MonoContext *ctx)
3771 static void (*restore_context) (MonoContext *);
3773 if (!restore_context)
3774 restore_context = (void (*)(MonoContext *))mono_get_restore_context ();
3775 restore_context (ctx);
3776 g_assert_not_reached ();
3780 * mono_jinfo_get_unwind_info:
3782 * Return the unwind info for JI.
3784 guint8*
3785 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
3787 if (ji->has_unwind_info) {
3788 /* The address/length in the MonoJitInfo structure itself */
3789 MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji);
3790 *unwind_info_len = info->unw_info_len;
3791 return info->unw_info;
3792 } else if (ji->from_aot)
3793 return mono_aot_get_unwind_info (ji, unwind_info_len);
3794 else
3795 return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
3799 mono_jinfo_get_epilog_size (MonoJitInfo *ji)
3801 MonoArchEHJitInfo *info;
3803 info = mono_jit_info_get_arch_eh_info (ji);
3804 g_assert (info);
3806 return info->epilog_size;
3810 * mono_install_ftnptr_eh_callback:
3812 * Install a callback that should be called when there is a managed exception
3813 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3814 * managed exception to a native exception, to properly unwind the native
3815 * stack; this native exception will then be converted back to a managed
3816 * exception in their managed-to-native wrapper.
3818 void
3819 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
3821 ftnptr_eh_callback = callback;
3825 * LLVM/Bitcode exception handling.
3828 static void
3829 throw_exception (MonoObject *ex, gboolean rethrow)
3831 MONO_REQ_GC_UNSAFE_MODE;
3833 ERROR_DECL (error);
3834 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3835 MonoException *mono_ex;
3837 if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, error)) {
3838 mono_error_assert_ok (error);
3839 mono_ex = mono_get_exception_runtime_wrapped_checked (ex, error);
3840 mono_error_assert_ok (error);
3841 jit_tls->thrown_non_exc = mono_gchandle_new_internal (ex, FALSE);
3843 else
3844 mono_ex = (MonoException*)ex;
3846 // Note: Not pinned
3847 jit_tls->thrown_exc = mono_gchandle_new_internal ((MonoObject*)mono_ex, FALSE);
3849 if (!rethrow) {
3850 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3851 GList *l, *ips = NULL;
3852 GList *trace;
3854 _Unwind_Backtrace (build_stack_trace, &ips);
3855 /* The list contains ip-gshared info pairs */
3856 trace = NULL;
3857 ips = g_list_reverse (ips);
3858 for (l = ips; l; l = l->next) {
3859 trace = g_list_append (trace, l->data);
3860 trace = g_list_append (trace, NULL);
3861 trace = g_list_append (trace, NULL);
3863 MonoArray *ips_arr = mono_glist_to_array (trace, mono_defaults.int_class, error);
3864 mono_error_assert_ok (error);
3865 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3866 g_list_free (l);
3867 g_list_free (trace);
3868 #endif
3871 mono_llvm_cpp_throw_exception ();
3874 void
3875 mono_llvm_throw_exception (MonoObject *ex)
3877 throw_exception (ex, FALSE);
3880 void
3881 mono_llvm_rethrow_exception (MonoObject *ex)
3883 throw_exception (ex, TRUE);
3886 void
3887 mono_llvm_raise_exception (MonoException *e)
3889 mono_llvm_throw_exception ((MonoObject*)e);
3892 void
3893 mono_llvm_reraise_exception (MonoException *e)
3895 mono_llvm_rethrow_exception ((MonoObject*)e);
3898 void
3899 mono_llvm_throw_corlib_exception (guint32 ex_token_index)
3901 guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
3902 MonoException *ex;
3904 ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token);
3906 mono_llvm_throw_exception ((MonoObject*)ex);
3910 * mono_llvm_resume_exception:
3912 * Resume exception propagation.
3914 void
3915 mono_llvm_resume_exception (void)
3917 mono_llvm_cpp_throw_exception ();
3921 * mono_llvm_load_exception:
3923 * Return the currently thrown exception.
3925 MonoObject *
3926 mono_llvm_load_exception (void)
3928 ERROR_DECL (error);
3929 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3931 MonoException *mono_ex = (MonoException*)mono_gchandle_get_target_internal (jit_tls->thrown_exc);
3933 MonoArray *ta = mono_ex->trace_ips;
3935 if (ta) {
3936 GList *trace_ips = NULL;
3937 gpointer ip = MONO_RETURN_ADDRESS ();
3939 size_t upper = mono_array_length_internal (ta);
3941 for (int i = 0; i < upper; i += TRACE_IP_ENTRY_SIZE) {
3942 gpointer curr_ip = mono_array_get_internal (ta, gpointer, i);
3943 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
3944 gpointer p = mono_array_get_internal (ta, gpointer, i + j);
3945 trace_ips = g_list_append (trace_ips, p);
3947 if (ip == curr_ip)
3948 break;
3951 // FIXME: Does this work correctly for rethrows?
3952 // We may be discarding useful information
3953 // when this gets GC'ed
3954 MonoArray *ips_arr = mono_glist_to_array (trace_ips, mono_defaults.int_class, error);
3955 mono_error_assert_ok (error);
3956 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3957 g_list_free (trace_ips);
3959 // FIXME:
3960 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3961 } else {
3962 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, 0, error));
3963 mono_error_assert_ok (error);
3964 MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, mono_array_new_checked (mono_domain_get (), mono_defaults.stack_frame_class, 0, error));
3965 mono_error_assert_ok (error);
3968 return &mono_ex->object;
3972 * mono_llvm_clear_exception:
3974 * Mark the currently thrown exception as handled.
3976 void
3977 mono_llvm_clear_exception (void)
3979 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3980 mono_gchandle_free_internal (jit_tls->thrown_exc);
3981 jit_tls->thrown_exc = 0;
3982 if (jit_tls->thrown_non_exc)
3983 mono_gchandle_free_internal (jit_tls->thrown_non_exc);
3984 jit_tls->thrown_non_exc = 0;
3986 mono_memory_barrier ();
3990 * mono_llvm_match_exception:
3992 * Return the innermost clause containing REGION_START-REGION_END which can handle
3993 * the current exception.
3995 gint32
3996 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
3998 ERROR_DECL (error);
3999 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
4000 MonoObject *exc;
4001 gint32 index = -1;
4003 g_assert (jit_tls->thrown_exc);
4004 exc = mono_gchandle_get_target_internal (jit_tls->thrown_exc);
4005 if (jit_tls->thrown_non_exc) {
4007 * Have to unwrap RuntimeWrappedExceptions if the
4008 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
4010 if (!wrap_non_exception_throws (jinfo_get_method (jinfo)))
4011 exc = mono_gchandle_get_target_internal (jit_tls->thrown_non_exc);
4014 for (int i = 0; i < jinfo->num_clauses; i++) {
4015 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
4016 MonoClass *catch_class;
4018 if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
4019 continue;
4021 catch_class = ei->data.catch_class;
4022 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class))) {
4023 MonoGenericContext context;
4024 MonoType *inflated_type;
4026 g_assert (rgctx || this_obj);
4027 context = mono_get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
4028 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
4029 mono_error_assert_ok (error); /* FIXME don't swallow the error */
4031 catch_class = mono_class_from_mono_type_internal (inflated_type);
4032 mono_metadata_free_type (inflated_type);
4035 // FIXME: Handle edge cases handled in get_exception_catch_class
4036 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, error)) {
4037 index = ei->clause_index;
4038 break;
4039 } else
4040 mono_error_assert_ok (error);
4042 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4043 g_assert_not_reached ();
4047 return index;
4050 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4051 G_EXTERN_C _Unwind_Reason_Code mono_debug_personality (int a, _Unwind_Action b,
4052 uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
4054 g_assert_not_reached ();
4056 #else
4057 G_EXTERN_C void mono_debug_personality (void);
4059 void
4060 mono_debug_personality (void)
4062 g_assert_not_reached ();
4064 #endif