[interp] Reduce computation under calc_section mutex
[mono-project.git] / mono / mini / mini-exceptions.c
blob08ca9b1ba04ec5e712a2342b825c780f41f9a56b
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>
19 #ifdef HAVE_SIGNAL_H
20 #include <signal.h>
21 #endif
23 #ifdef HAVE_EXECINFO_H
24 #include <execinfo.h>
25 #endif
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
31 #ifdef HAVE_SYS_WAIT_H
32 #include <sys/wait.h>
33 #endif
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
39 #ifdef HAVE_SYS_SYSCALL_H
40 #include <sys/syscall.h>
41 #endif
43 #ifdef HAVE_SYS_PRCTL_H
44 #include <sys/prctl.h>
45 #endif
47 #ifdef HAVE_UNWIND_H
48 #include <unwind.h>
49 #endif
51 #include <mono/metadata/appdomain.h>
52 #include <mono/metadata/tabledefs.h>
53 #include <mono/metadata/threads.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/exception.h>
57 #include <mono/metadata/exception-internals.h>
58 #include <mono/metadata/object-internals.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/metadata/debug-internals.h>
62 #include <mono/metadata/mono-debug.h>
63 #include <mono/metadata/profiler-private.h>
64 #include <mono/metadata/mono-endian.h>
65 #include <mono/metadata/environment.h>
66 #include <mono/metadata/mono-mlist.h>
67 #include <mono/utils/mono-merp.h>
68 #include <mono/utils/mono-mmap.h>
69 #include <mono/utils/mono-logger-internals.h>
70 #include <mono/utils/mono-error.h>
71 #include <mono/utils/mono-error-internals.h>
72 #include <mono/utils/mono-state.h>
73 #include <mono/utils/mono-threads-debug.h>
75 #include "mini.h"
76 #include "trace.h"
77 #include "debugger-agent.h"
78 #include "seq-points.h"
79 #include "llvm-runtime.h"
80 #include "mini-llvm.h"
81 #include "aot-runtime.h"
82 #include "mini-runtime.h"
83 #include "interp/interp.h"
85 #ifdef ENABLE_LLVM
86 #include "mini-llvm-cpp.h"
87 #endif
89 #ifdef TARGET_ARM
90 #include "mini-arm.h"
91 #endif
93 #ifndef MONO_ARCH_CONTEXT_DEF
94 #define MONO_ARCH_CONTEXT_DEF
95 #endif
97 #ifndef HOST_WIN32
98 #include <dlfcn.h>
99 #endif
102 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
103 * This structure represents one entry.
104 * This should consists of pointers only.
106 typedef struct
108 gpointer ip;
109 gpointer generic_info;
110 /* Only for interpreter frames */
111 MonoJitInfo *ji;
112 } ExceptionTraceIp;
114 /* Number of words in trace_ips belonging to one entry */
115 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
117 static gpointer restore_context_func, call_filter_func;
118 static gpointer throw_exception_func, rethrow_exception_func, rethrow_preserve_exception_func;
119 static gpointer throw_corlib_exception_func;
121 static MonoFtnPtrEHCallback ftnptr_eh_callback;
123 static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data, gboolean crash_context);
124 static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx);
125 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
126 static gboolean mono_current_thread_has_handle_block_guard (void);
127 static gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx);
128 static void mono_uninstall_current_handler_block_guard (void);
129 static gboolean mono_exception_walk_trace_internal (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data);
130 static void throw_exception (MonoObject *ex, gboolean rethrow);
132 static void mono_summarize_managed_stack (MonoThreadSummary *out);
133 static void mono_summarize_unmanaged_stack (MonoThreadSummary *out);
134 static void mono_summarize_exception (MonoException *exc, MonoThreadSummary *out);
135 static void mono_crash_reporting_register_native_library (const char *module_path, const char *module_name);
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 inline 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 inline 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 inline 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;
248 if (mono_llvm_only) {
249 cbs.mono_raise_exception = mono_llvm_raise_exception;
250 cbs.mono_reraise_exception = mono_llvm_reraise_exception;
251 } else {
252 cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception ();
253 cbs.mono_reraise_exception = (void (*)(MonoException *))mono_get_rethrow_exception ();
255 cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
256 cbs.mono_exception_walk_trace = mono_exception_walk_trace;
257 cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
258 cbs.mono_uninstall_current_handler_block_guard = mono_uninstall_current_handler_block_guard;
259 cbs.mono_current_thread_has_handle_block_guard = mono_current_thread_has_handle_block_guard;
260 cbs.mono_clear_abort_threshold = mini_clear_abort_threshold;
261 cbs.mono_above_abort_threshold = mini_above_abort_threshold;
262 mono_install_eh_callbacks (&cbs);
263 mono_install_get_seq_point (mono_get_seq_point_for_native_offset);
266 gpointer
267 mono_get_throw_exception (void)
269 g_assert (throw_exception_func);
270 return throw_exception_func;
273 gpointer
274 mono_get_rethrow_exception (void)
276 g_assert (rethrow_exception_func);
277 return rethrow_exception_func;
280 gpointer
281 mono_get_rethrow_preserve_exception (void)
283 g_assert (rethrow_preserve_exception_func);
284 return rethrow_preserve_exception_func;
287 static void
288 no_call_filter (void)
290 g_assert_not_reached ();
293 gpointer
294 mono_get_call_filter (void)
296 /* This is called even in llvmonly mode etc. */
297 if (!call_filter_func)
298 return (gpointer)no_call_filter;
299 return call_filter_func;
302 gpointer
303 mono_get_restore_context (void)
305 g_assert (restore_context_func);
306 return restore_context_func;
309 gpointer
310 mono_get_throw_corlib_exception (void)
312 gpointer code = NULL;
313 MonoTrampInfo *info;
315 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
316 if (throw_corlib_exception_func)
317 return throw_corlib_exception_func;
319 if (mono_ee_features.use_aot_trampolines)
320 code = mono_aot_get_trampoline ("throw_corlib_exception");
321 else {
322 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
323 mono_tramp_info_register (info, NULL);
326 mono_memory_barrier ();
328 throw_corlib_exception_func = code;
330 return throw_corlib_exception_func;
334 * mono_get_throw_exception_addr:
336 * Return an address which stores the result of
337 * mono_get_throw_exception.
339 gpointer
340 mono_get_throw_exception_addr (void)
342 return &throw_exception_func;
345 gpointer
346 mono_get_rethrow_preserve_exception_addr (void)
348 return &rethrow_preserve_exception_func;
351 static gboolean
352 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
354 MonoTryBlockHoleTableJitInfo *table;
355 int i;
356 guint32 offset;
357 guint16 clause;
359 if (ei->try_start > ip || ip >= ei->try_end)
360 return FALSE;
362 if (!ji->has_try_block_holes)
363 return TRUE;
365 table = mono_jit_info_get_try_block_hole_table_info (ji);
366 offset = (guint32)((char*)ip - (char*)ji->code_start);
367 clause = (guint16)(ei - ji->clauses);
368 g_assert (clause < ji->num_clauses);
370 for (i = 0; i < table->num_holes; ++i) {
371 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
372 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
373 return FALSE;
375 return TRUE;
378 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
380 #if 0
381 static gboolean show_native_addresses = TRUE;
382 #else
383 static gboolean show_native_addresses = FALSE;
384 #endif
386 static _Unwind_Reason_Code
387 build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
389 MonoDomain *domain = mono_domain_get ();
390 uintptr_t ip = _Unwind_GetIP (frame_ctx);
392 if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
393 GList **trace_ips = (GList **)state;
394 *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
397 return _URC_NO_REASON;
400 static GSList*
401 get_unwind_backtrace (void)
403 GSList *ips = NULL;
405 _Unwind_Backtrace (build_stack_trace, &ips);
407 return g_slist_reverse (ips);
410 #else
412 static GSList*
413 get_unwind_backtrace (void)
415 return NULL;
418 #endif
420 static gboolean
421 arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
422 MonoJitInfo *ji, MonoContext *ctx,
423 MonoContext *new_ctx, MonoLMF **lmf,
424 host_mgreg_t **save_locations,
425 StackFrameInfo *frame)
427 if (!ji && *lmf) {
428 if (((gsize)(*lmf)->previous_lmf) & 2) {
429 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
431 memset (frame, 0, sizeof (StackFrameInfo));
432 frame->ji = ji;
434 *new_ctx = *ctx;
436 if (ext->kind == MONO_LMFEXT_DEBUGGER_INVOKE) {
438 * This LMF entry is created by the soft debug code to mark transitions to
439 * managed code done during invokes.
441 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
442 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
443 } else if (ext->kind == MONO_LMFEXT_INTERP_EXIT || ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX) {
444 frame->type = FRAME_TYPE_INTERP_TO_MANAGED;
445 frame->interp_exit_data = ext->interp_exit_data;
446 if (ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX) {
447 frame->type = FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX;
448 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
450 } else {
451 g_assert_not_reached ();
454 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~3);
456 return TRUE;
460 return mono_arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
464 * find_jit_info:
466 * Translate between the mono_arch_unwind_frame function and the old API.
468 static MonoJitInfo *
469 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
470 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
472 StackFrameInfo frame;
473 MonoJitInfo *ji;
474 gboolean err;
475 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
477 /* Avoid costly table lookup during stack overflow */
478 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
479 ji = prev_ji;
480 else
481 ji = mini_jit_info_table_find (domain, ip, NULL);
483 if (managed)
484 *managed = FALSE;
486 err = arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
487 if (!err)
488 return (MonoJitInfo *)-1;
490 if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
492 * Remove any unused lmf.
493 * Mask out the lower bits which might be used to hold additional information.
495 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P -1));
498 /* Convert between the new and the old APIs */
499 switch (frame.type) {
500 case FRAME_TYPE_MANAGED:
501 if (managed)
502 *managed = TRUE;
503 return frame.ji;
504 case FRAME_TYPE_TRAMPOLINE:
505 return frame.ji;
506 case FRAME_TYPE_MANAGED_TO_NATIVE:
507 if (frame.ji)
508 return frame.ji;
509 else {
510 memset (res, 0, sizeof (MonoJitInfo));
511 res->d.method = frame.method;
512 return res;
514 case FRAME_TYPE_DEBUGGER_INVOKE: {
515 MonoContext tmp_ctx;
518 * The normal exception handling code can't handle this frame, so just
519 * skip it.
521 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
522 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
523 return ji;
525 default:
526 g_assert_not_reached ();
527 return NULL;
531 /* mono_find_jit_info:
533 * This function is used to gather information from @ctx. It return the
534 * MonoJitInfo of the corresponding function, unwinds one stack frame and
535 * stores the resulting context into @new_ctx. It also stores a string
536 * describing the stack location into @trace (if not NULL), and modifies
537 * the @lmf if necessary. @native_offset return the IP offset from the
538 * start of the function or -1 if that info is not available.
540 MonoJitInfo *
541 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
542 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
543 gboolean *managed)
545 gboolean managed2;
546 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
547 MonoJitInfo *ji;
548 MonoMethod *method = NULL;
550 if (trace)
551 *trace = NULL;
553 if (native_offset)
554 *native_offset = -1;
556 if (managed)
557 *managed = FALSE;
559 ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
561 if (ji == (gpointer)-1)
562 return ji;
564 if (ji && !ji->is_trampoline)
565 method = jinfo_get_method (ji);
567 if (managed2 || (method && method->wrapper_type)) {
568 const char *real_ip, *start;
569 gint32 offset;
571 start = (const char *)ji->code_start;
572 if (!managed2)
573 /* ctx->ip points into native code */
574 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
575 else
576 real_ip = (const char*)ip;
578 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
579 offset = real_ip - start;
580 else
581 offset = -1;
583 if (native_offset)
584 *native_offset = offset;
586 if (managed)
587 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
588 *managed = TRUE;
590 if (trace)
591 *trace = mono_debug_print_stack_frame (method, offset, domain);
592 } else {
593 if (trace) {
594 char *fname = mono_method_full_name (jinfo_get_method (res), TRUE);
595 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
596 g_free (fname);
600 return ji;
604 * mono_find_jit_info_ext:
606 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
607 * structure.
608 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
609 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
610 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
611 * to obtain the last managed frame.
612 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
613 * On return, it will be filled with the locations where callee saved registers are saved
614 * by the current frame. This is returned outside of StackFrameInfo because it can be
615 * quite large on some platforms.
616 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
617 * not be set.
619 gboolean
620 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
621 MonoJitInfo *prev_ji, MonoContext *ctx,
622 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
623 host_mgreg_t **save_locations,
624 StackFrameInfo *frame)
626 gboolean err;
627 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
628 MonoJitInfo *ji;
629 MonoDomain *target_domain = domain;
630 MonoMethod *method = NULL;
631 gboolean async = mono_thread_info_is_async_context ();
633 if (trace)
634 *trace = NULL;
636 /* Avoid costly table lookup during stack overflow */
637 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
638 ji = prev_ji;
639 else
640 ji = mini_jit_info_table_find_ext (domain, ip, TRUE, &target_domain);
642 if (!target_domain)
643 target_domain = domain;
645 if (save_locations)
646 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (host_mgreg_t*));
648 err = arch_unwind_frame (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
649 if (!err)
650 return FALSE;
652 gboolean not_i2m = frame->type != FRAME_TYPE_INTERP_TO_MANAGED && frame->type != FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX;
654 if (not_i2m && *lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
656 * Remove any unused lmf.
657 * Mask out the lower bits which might be used to hold additional information.
659 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P -1));
662 if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async)
663 method = jinfo_get_method (frame->ji);
665 if (frame->type == FRAME_TYPE_MANAGED && method) {
666 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
667 frame->managed = TRUE;
670 if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
672 * This type of frame is just a marker, the caller should unwind once more to get the
673 * last managed frame.
675 frame->ji = NULL;
676 frame->method = NULL;
679 frame->native_offset = -1;
680 frame->domain = target_domain;
681 frame->async_context = async;
682 frame->frame_addr = MONO_CONTEXT_GET_SP (ctx);
684 ji = frame->ji;
686 if (frame->type == FRAME_TYPE_MANAGED)
687 frame->method = method;
689 if (ji && (frame->managed || (method && method->wrapper_type))) {
690 const char *real_ip, *start;
692 start = (const char *)ji->code_start;
693 if (frame->type == FRAME_TYPE_MANAGED)
694 real_ip = (const char*)ip;
695 else
696 /* ctx->ip points into native code */
697 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
699 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
700 frame->native_offset = real_ip - start;
701 else {
702 frame->native_offset = -1;
705 if (trace)
706 *trace = mono_debug_print_stack_frame (method, frame->native_offset, domain);
707 } else {
708 if (trace && frame->method) {
709 char *fname = mono_method_full_name (frame->method, TRUE);
710 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
711 g_free (fname);
715 return TRUE;
718 typedef struct {
719 gboolean in_interp;
720 MonoInterpStackIter interp_iter;
721 gpointer last_frame_addr;
722 } Unwinder;
724 static void
725 unwinder_init (Unwinder *unwinder)
727 memset (unwinder, 0, sizeof (Unwinder));
730 #if defined(__GNUC__) && defined(TARGET_ARM64)
731 /* gcc 4.9.2 seems to miscompile this on arm64 */
732 static __attribute__((optimize("O0"))) gboolean
733 #else
734 static gboolean
735 #endif
736 unwinder_unwind_frame (Unwinder *unwinder,
737 MonoDomain *domain, MonoJitTlsData *jit_tls,
738 MonoJitInfo *prev_ji, MonoContext *ctx,
739 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
740 host_mgreg_t **save_locations,
741 StackFrameInfo *frame)
743 gpointer parent;
744 if (unwinder->in_interp) {
745 memcpy (new_ctx, ctx, sizeof (MonoContext));
747 /* Process debugger invokes */
748 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
749 if (unwinder->last_frame_addr < (gpointer)(*lmf)) {
750 if (((gsize)(*lmf)->previous_lmf) & 2) {
751 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
752 if (ext->kind == MONO_LMFEXT_DEBUGGER_INVOKE) {
753 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~7);
754 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
755 return TRUE;
760 unwinder->in_interp = mini_get_interp_callbacks ()->frame_iter_next (&unwinder->interp_iter, frame);
761 if (frame->type == FRAME_TYPE_INTERP) {
762 parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame);
763 unwinder->last_frame_addr = parent;
765 if (!unwinder->in_interp)
766 return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame);
767 return TRUE;
768 } else {
769 gboolean res = mono_find_jit_info_ext (domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf,
770 save_locations, frame);
771 if (!res)
772 return FALSE;
773 if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED || frame->type == FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX) {
774 unwinder->in_interp = TRUE;
775 mini_get_interp_callbacks ()->frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data);
777 unwinder->last_frame_addr = frame->frame_addr;
778 return TRUE;
783 * This function is async-safe.
785 static gpointer
786 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
788 MonoGenericJitInfo *gi;
789 MonoMethod *method;
790 gpointer info;
792 if (!ji->has_generic_jit_info)
793 return NULL;
794 gi = mono_jit_info_get_generic_jit_info (ji);
795 if (!gi->has_this)
796 return NULL;
798 info = NULL;
800 * Search location list if available, it contains the precise location of the
801 * argument for every pc offset, even if the method was interrupted while it was in
802 * its prolog.
804 if (gi->nlocs) {
805 int offset = (gsize)MONO_CONTEXT_GET_IP (ctx) - (gsize)ji->code_start;
806 int i;
808 for (i = 0; i < gi->nlocs; ++i) {
809 MonoDwarfLocListEntry *entry = &gi->locations [i];
811 if (offset >= entry->from && (offset < entry->to || entry->to == 0)) {
812 if (entry->is_reg)
813 info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg);
814 else
815 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset);
816 break;
819 g_assert (i < gi->nlocs);
820 } else {
821 if (gi->this_in_reg)
822 info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg);
823 else
824 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
825 gi->this_offset);
828 method = jinfo_get_method (ji);
829 if (mono_method_get_context (method)->method_inst) {
830 /* A MonoMethodRuntimeGenericContext* */
831 return info;
832 } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || m_class_is_valuetype (method->klass)) {
833 /* A MonoVTable* */
834 return info;
835 } else {
836 /* Avoid returning a managed object */
837 MonoObject *this_obj = (MonoObject *)info;
839 return this_obj->vtable;
844 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
846 static MonoGenericContext
847 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
849 MonoGenericContext context = { NULL, NULL };
850 MonoClass *klass, *method_container_class;
851 MonoMethod *method;
853 g_assert (generic_info);
855 method = jinfo_get_method (ji);
856 g_assert (method->is_inflated);
857 if (mono_method_get_context (method)->method_inst) {
858 MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext *)generic_info;
860 klass = mrgctx->class_vtable->klass;
861 context.method_inst = mrgctx->method_inst;
862 g_assert (context.method_inst);
863 } else {
864 MonoVTable *vtable = (MonoVTable *)generic_info;
866 klass = vtable->klass;
869 //g_assert (!mono_class_is_gtd (method->klass));
870 if (mono_class_is_ginst (method->klass))
871 method_container_class = mono_class_get_generic_class (method->klass)->container_class;
872 else
873 method_container_class = method->klass;
875 /* class might refer to a subclass of method's class */
876 while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) {
877 klass = m_class_get_parent (klass);
878 g_assert (klass);
881 if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass))
882 context.class_inst = mini_class_get_context (klass)->class_inst;
884 if (mono_class_is_ginst (klass))
885 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass)->container_class, method_container_class));
886 else
887 g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class));
889 return context;
892 static MonoMethod*
893 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
895 ERROR_DECL (error);
896 MonoGenericContext context;
897 MonoMethod *method;
899 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
900 return jinfo_get_method (ji);
901 context = get_generic_context_from_stack_frame (ji, generic_info);
903 method = jinfo_get_method (ji);
904 method = mono_method_get_declaring_generic_method (method);
905 method = mono_class_inflate_generic_method_checked (method, &context, error);
906 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
908 return method;
912 * mono_exception_walk_native_trace:
913 * \param ex The exception object whose frames should be walked
914 * \param func callback to call for each stack frame
915 * \param user_data data passed to the callback
916 * This function walks the stacktrace of an exception. For
917 * each frame the callback function is called with the relevant info.
918 * The walk ends when no more stack frames are found or when the callback
919 * returns a TRUE value.
922 gboolean
923 mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
925 gboolean res;
927 MONO_ENTER_GC_UNSAFE;
928 res = mono_exception_walk_trace_internal (ex, func, user_data);
929 MONO_EXIT_GC_UNSAFE;
930 return res;
933 static gboolean
934 mono_exception_stackframe_obj_walk (MonoStackFrame *captured_frame, MonoExceptionFrameWalk func, gpointer user_data)
936 if (!captured_frame)
937 return TRUE;
939 gpointer ip = (gpointer) (captured_frame->method_address + captured_frame->native_offset);
940 MonoJitInfo *ji = mono_jit_info_table_find_internal (mono_domain_get (), ip, TRUE, TRUE);
942 // Other domain maybe?
943 if (!ji)
944 return FALSE;
945 MonoMethod *method = jinfo_get_method (ji);
947 gboolean r = func (method, (gpointer) captured_frame->method_address, captured_frame->native_offset, TRUE, user_data);
948 if (r)
949 return TRUE;
951 return FALSE;
954 static gboolean
955 mono_exception_stacktrace_obj_walk (MonoStackTrace *st, MonoExceptionFrameWalk func, gpointer user_data)
957 int num_captured = st->captured_traces ? mono_array_length_internal (st->captured_traces) : 0;
958 for (int i=0; i < num_captured; i++) {
959 MonoStackTrace *curr_trace = mono_array_get_fast (st->captured_traces, MonoStackTrace *, i);
960 mono_exception_stacktrace_obj_walk (curr_trace, func, user_data);
963 int num_frames = st->frames ? mono_array_length_internal (st->frames) : 0;
964 for (int frame = 0; frame < num_frames; frame++) {
965 gboolean r = mono_exception_stackframe_obj_walk (mono_array_get_fast (st->frames, MonoStackFrame *, frame), func, user_data);
966 if (r)
967 return TRUE;
970 return TRUE;
973 gboolean
974 mono_exception_walk_trace_internal (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
976 MONO_REQ_GC_UNSAFE_MODE;
978 MonoDomain *domain = mono_domain_get ();
979 MonoArray *ta = ex->trace_ips;
981 /* Exception is not thrown yet */
982 if (ta == NULL)
983 return FALSE;
985 int len = mono_array_length_internal (ta) / TRACE_IP_ENTRY_SIZE;
986 gboolean otherwise_has_traces = len > 0;
988 for (int i = 0; i < len; i++) {
989 ExceptionTraceIp trace_ip;
991 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
992 gpointer ip = trace_ip.ip;
993 gpointer generic_info = trace_ip.generic_info;
995 MonoJitInfo *ji = NULL;
996 if (trace_ip.ji) {
997 ji = trace_ip.ji;
998 } else {
999 ji = mono_jit_info_table_find (domain, ip);
1002 if (ji == NULL) {
1003 gboolean r;
1004 MONO_ENTER_GC_SAFE;
1005 r = func (NULL, ip, 0, FALSE, user_data);
1006 MONO_EXIT_GC_SAFE;
1007 if (r)
1008 break;
1009 } else {
1010 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
1011 if (func (method, ji->code_start, (char *) ip - (char *) ji->code_start, TRUE, user_data))
1012 break;
1016 ta = (MonoArray *) ex->captured_traces;
1017 len = ta ? mono_array_length_internal (ta) : 0;
1018 gboolean captured_has_traces = len > 0;
1020 for (int i = 0; i < len; i++) {
1021 MonoStackTrace *captured_trace = mono_array_get_fast (ta, MonoStackTrace *, i);
1022 if (!captured_trace)
1023 break;
1025 mono_exception_stacktrace_obj_walk (captured_trace, func, user_data);
1028 return captured_has_traces || otherwise_has_traces;
1031 MonoArray *
1032 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
1034 ERROR_DECL (error);
1035 MonoDomain *domain = mono_domain_get ();
1036 MonoArray *res;
1037 MonoArray *ta = exc->trace_ips;
1038 MonoDebugSourceLocation *location;
1039 int i, len;
1041 if (ta == NULL) {
1042 /* Exception is not thrown yet */
1043 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, error);
1044 mono_error_set_pending_exception (error);
1045 return res;
1048 len = mono_array_length_internal (ta) / TRACE_IP_ENTRY_SIZE;
1050 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, error);
1051 if (mono_error_set_pending_exception (error))
1052 return NULL;
1054 for (i = skip; i < len; i++) {
1055 MonoJitInfo *ji;
1056 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
1057 if (!mono_error_ok (error)) {
1058 mono_error_set_pending_exception (error);
1059 return NULL;
1061 ExceptionTraceIp trace_ip;
1062 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
1063 gpointer ip = trace_ip.ip;
1064 gpointer generic_info = trace_ip.generic_info;
1065 MonoMethod *method;
1067 if (trace_ip.ji) {
1068 ji = trace_ip.ji;
1069 } else {
1070 ji = mono_jit_info_table_find (domain, ip);
1071 if (ji == NULL) {
1072 /* Unmanaged frame */
1073 mono_array_setref_internal (res, i, sf);
1074 continue;
1078 g_assert (ji != NULL);
1080 if (mono_llvm_only || !generic_info)
1081 /* Can't resolve actual method */
1082 method = jinfo_get_method (ji);
1083 else
1084 method = get_method_from_stack_frame (ji, generic_info);
1085 if (jinfo_get_method (ji)->wrapper_type) {
1086 char *s;
1088 sf->method = NULL;
1089 s = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION);
1090 MonoString *name = mono_string_new_checked (domain, s, error);
1091 g_free (s);
1092 if (!is_ok (error)) {
1093 mono_error_set_pending_exception (error);
1094 return NULL;
1096 MONO_OBJECT_SETREF_INTERNAL (sf, internal_method_name, name);
1098 else {
1099 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
1100 if (!mono_error_ok (error)) {
1101 mono_error_set_pending_exception (error);
1102 return NULL;
1104 MONO_OBJECT_SETREF_INTERNAL (sf, method, rm);
1107 sf->method_index = ji->from_aot ? mono_aot_find_method_index (method) : 0xffffff;
1108 sf->method_address = (gsize) ji->code_start;
1109 sf->native_offset = (char *)ip - (char *)ji->code_start;
1112 * mono_debug_lookup_source_location() returns both the file / line number information
1113 * and the IL offset. Note that computing the IL offset is already an expensive
1114 * operation, so we shouldn't call this method twice.
1116 location = mono_debug_lookup_source_location (jinfo_get_method (ji), sf->native_offset, domain);
1117 if (location) {
1118 sf->il_offset = location->il_offset;
1119 } else {
1120 SeqPoint sp;
1121 if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (ji), sf->native_offset, NULL, &sp))
1122 sf->il_offset = sp.il_offset;
1123 else
1124 sf->il_offset = -1;
1127 if (need_file_info) {
1128 if (location && location->source_file) {
1129 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1130 if (!is_ok (error)) {
1131 mono_error_set_pending_exception (error);
1132 return NULL;
1134 MONO_OBJECT_SETREF_INTERNAL (sf, filename, filename);
1135 sf->line = location->row;
1136 sf->column = location->column;
1137 } else {
1138 sf->line = sf->column = 0;
1139 sf->filename = NULL;
1143 mono_debug_free_source_location (location);
1144 mono_array_setref_internal (res, i, sf);
1147 return res;
1150 static void
1151 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1153 if (!start_ctx) {
1154 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1155 if (jit_tls && jit_tls->orig_ex_ctx_set)
1156 start_ctx = &jit_tls->orig_ex_ctx;
1158 mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
1161 * mono_walk_stack_with_ctx:
1162 * Unwind the current thread starting at \p start_ctx.
1163 * If \p start_ctx is null, we capture the current context.
1165 void
1166 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1168 MonoContext extra_ctx;
1169 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1170 MONO_ARCH_CONTEXT_DEF
1172 if (!thread || !thread->jit_data)
1173 return;
1175 if (!start_ctx) {
1176 mono_arch_flush_register_windows ();
1177 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
1178 start_ctx = &extra_ctx;
1181 mono_walk_stack_full (func, start_ctx, mono_domain_get (), thread->jit_data, mono_get_lmf (), unwind_options, user_data, FALSE);
1185 * mono_walk_stack_with_state:
1186 * Unwind a thread described by \p state.
1188 * State must be valid (state->valid == TRUE).
1190 * If you are using this function to unwind another thread, make sure it is suspended.
1192 * If \p state is null, we capture the current context.
1194 void
1195 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
1197 MonoThreadUnwindState extra_state;
1198 if (!state) {
1199 g_assert (!mono_thread_info_is_async_context ());
1200 if (!mono_thread_state_init_from_current (&extra_state))
1201 return;
1202 state = &extra_state;
1205 g_assert (state->valid);
1207 if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
1208 /* Not attached */
1209 return;
1211 mono_walk_stack_full (func,
1212 &state->ctx,
1213 (MonoDomain *)state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
1214 (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
1215 (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF],
1216 unwind_options, user_data, FALSE);
1219 void
1220 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
1222 MonoThreadUnwindState state;
1223 if (!mono_thread_state_init_from_current (&state))
1224 return;
1225 mono_walk_stack_with_state (func, &state, options, user_data);
1229 * mono_walk_stack_full:
1230 * \param func callback to call for each stack frame
1231 * \param domain starting appdomain, can be NULL to use the current domain
1232 * \param unwind_options what extra information the unwinder should gather
1233 * \param start_ctx starting state of the stack walk, can be NULL.
1234 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1235 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1236 * \param user_data data passed to the callback
1237 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1238 * This function walks the stack of a thread, starting from the state
1239 * represented by \p start_ctx. For each frame the callback
1240 * function is called with the relevant info. The walk ends when no more
1241 * managed stack frames are found or when the callback returns a TRUE value.
1243 static void
1244 mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data, gboolean crash_context)
1246 gint il_offset;
1247 MonoContext ctx, new_ctx;
1248 StackFrameInfo frame;
1249 gboolean res;
1250 host_mgreg_t *reg_locations [MONO_MAX_IREGS];
1251 host_mgreg_t *new_reg_locations [MONO_MAX_IREGS];
1252 gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
1253 gboolean async = mono_thread_info_is_async_context ();
1254 Unwinder unwinder;
1256 memset (&frame, 0, sizeof (StackFrameInfo));
1258 #ifndef TARGET_WASM
1259 if (mono_llvm_only) {
1260 GSList *l, *ips;
1262 if (async)
1263 return;
1265 ips = get_unwind_backtrace ();
1266 for (l = ips; l; l = l->next) {
1267 guint8 *ip = (guint8*)l->data;
1268 memset (&frame, 0, sizeof (StackFrameInfo));
1269 frame.ji = mini_jit_info_table_find (domain, ip, &frame.domain);
1270 if (!frame.ji || frame.ji->is_trampoline)
1271 continue;
1272 frame.type = FRAME_TYPE_MANAGED;
1273 frame.method = jinfo_get_method (frame.ji);
1274 // FIXME: Cannot lookup the actual method
1275 frame.actual_method = frame.method;
1276 if (frame.type == FRAME_TYPE_MANAGED) {
1277 if (!frame.method->wrapper_type || frame.method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
1278 frame.managed = TRUE;
1280 frame.native_offset = ip - (guint8*)frame.ji->code_start;
1281 frame.il_offset = -1;
1283 if (func (&frame, NULL, user_data))
1284 break;
1286 g_slist_free (ips);
1287 return;
1289 #endif
1291 if (!start_ctx) {
1292 g_warning ("start_ctx required for stack walk");
1293 return;
1296 if (!domain) {
1297 g_warning ("domain required for stack walk");
1298 return;
1301 if (!jit_tls) {
1302 g_warning ("jit_tls required for stack walk");
1303 return;
1306 /*The LMF will be null if the target have no managed frames.*/
1307 /* g_assert (lmf); */
1308 if (async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD)) {
1309 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1310 return;
1313 memcpy (&ctx, start_ctx, sizeof (MonoContext));
1314 memset (reg_locations, 0, sizeof (reg_locations));
1316 unwinder_init (&unwinder);
1318 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
1319 frame.lmf = lmf;
1320 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
1321 if (!res)
1322 return;
1324 if (frame.type == FRAME_TYPE_TRAMPOLINE)
1325 goto next;
1327 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) {
1328 MonoDebugSourceLocation *source = NULL;
1330 // Don't do this when we can be in a signal handler
1331 if (!crash_context)
1332 source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
1333 if (source) {
1334 il_offset = source->il_offset;
1335 } else {
1336 MonoSeqPointInfo *seq_points = NULL;
1338 // It's more reliable to look into the global cache if possible
1339 if (crash_context)
1340 seq_points = (MonoSeqPointInfo *) frame.ji->seq_points;
1341 else
1342 seq_points = mono_get_seq_points (domain, jinfo_get_method (frame.ji));
1344 SeqPoint sp;
1345 if (seq_points && mono_seq_point_find_prev_by_native_offset (seq_points, frame.native_offset, &sp))
1346 il_offset = sp.il_offset;
1347 else
1348 il_offset = -1;
1350 mono_debug_free_source_location (source);
1351 } else
1352 il_offset = -1;
1354 frame.il_offset = il_offset;
1356 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) {
1357 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
1358 } else {
1359 frame.actual_method = frame.method;
1362 if (get_reg_locations)
1363 frame.reg_locations = reg_locations;
1365 if (func (&frame, &ctx, user_data))
1366 return;
1368 next:
1369 if (get_reg_locations) {
1370 for (int i = 0; i < MONO_MAX_IREGS; ++i)
1371 if (new_reg_locations [i])
1372 reg_locations [i] = new_reg_locations [i];
1375 ctx = new_ctx;
1379 #ifdef DISABLE_CRASH_REPORTING
1381 static void
1382 mono_summarize_managed_stack (MonoThreadSummary *out)
1384 return;
1387 static void
1388 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1390 return;
1393 static void
1394 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1396 return;
1399 static void
1400 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1402 return;
1406 #else
1408 typedef struct {
1409 MonoFrameSummary *frames;
1410 int num_frames;
1411 int max_frames;
1412 MonoStackHash *hashes;
1413 const char *error;
1414 } MonoSummarizeUserData;
1416 static void
1417 copy_summary_string_safe (char *in, const char *out)
1419 for (int i=0; i < MONO_MAX_SUMMARY_NAME_LEN; i++) {
1420 in [i] = out [i];
1421 if (out [i] == '\0')
1422 return;
1425 // Overflowed
1426 in [MONO_MAX_SUMMARY_NAME_LEN] = '\0';
1427 return;
1430 typedef struct {
1431 char *suffix;
1432 char *exported_name;
1433 } MonoLibWhitelistEntry;
1435 static GList *native_library_whitelist;
1437 static void
1438 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1440 // Examples: libsystem_pthread.dylib -> "pthread"
1441 // Examples: libsystem_platform.dylib -> "platform"
1442 // Examples: mono-sgen -> "mono" from above line
1443 MonoLibWhitelistEntry *entry = g_new0 (MonoLibWhitelistEntry, 1);
1444 entry->suffix = g_strdup (module_path);
1445 entry->exported_name = g_strdup (module_name);
1446 native_library_whitelist = g_list_append (native_library_whitelist, entry);
1449 static gboolean
1450 check_whitelisted_module (const char *in_name, const char **out_module)
1452 #ifndef MONO_PRIVATE_CRASHES
1453 return TRUE;
1454 #else
1455 if (g_str_has_suffix (in_name, "mono-sgen")) {
1456 if (out_module)
1457 *out_module = "mono";
1458 return TRUE;
1461 for (GList *cursor = native_library_whitelist; cursor; cursor = cursor->next) {
1462 MonoLibWhitelistEntry *iter = (MonoLibWhitelistEntry *) cursor->data;
1463 if (!g_str_has_suffix (in_name, iter->suffix))
1464 continue;
1465 if (out_module)
1466 *out_module = iter->exported_name;
1467 return TRUE;
1470 return FALSE;
1471 #endif
1474 static intptr_t
1475 mono_make_portable_ip (intptr_t in_ip, intptr_t module_base)
1477 // FIXME: Make generalize away from llvm tools?
1478 // So lldb starts the pointer base at 0x100000000
1479 // and expects to get pointers as (offset + constant)
1481 // Quirk shared by:
1482 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1483 // *CoreSymbolicationDT.framework version: 63750*/
1484 intptr_t offset = in_ip - module_base;
1485 intptr_t magic_value = offset + 0x100000000;
1486 return magic_value;
1489 static gboolean
1490 mono_get_portable_ip (intptr_t in_ip, intptr_t *out_ip, gint32 *out_offset, const char **out_module, char *out_name)
1492 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1493 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1494 // non-recursive lock twice on this thread, and will deadlock.
1495 Dl_info info;
1496 gboolean success = dladdr ((void*)in_ip, &info);
1497 if (!success)
1498 return FALSE;
1500 if (!check_whitelisted_module (info.dli_fname, out_module))
1501 return FALSE;
1503 *out_ip = mono_make_portable_ip ((intptr_t) info.dli_saddr, (intptr_t) info.dli_fbase);
1504 *out_offset = in_ip - (intptr_t) info.dli_saddr;
1506 #ifndef MONO_PRIVATE_CRASHES
1507 if (info.dli_saddr && out_name)
1508 copy_summary_string_safe (out_name, info.dli_sname);
1509 #endif
1510 return TRUE;
1513 static guint64
1514 summarize_offset_free_hash (guint64 accum, MonoFrameSummary *frame)
1516 if (!frame->is_managed)
1517 return accum;
1519 // See: mono_ptrarray_hash
1520 guint64 hash_accum = accum;
1522 // The assembly and the method token, no offsets
1523 hash_accum += mono_metadata_str_hash (frame->str_descr);
1524 hash_accum += frame->managed_data.token;
1526 return hash_accum;
1529 static guint64
1530 summarize_offset_rich_hash (guint64 accum, MonoFrameSummary *frame)
1532 // See: mono_ptrarray_hash
1533 guint64 hash_accum = accum;
1535 if (!frame->is_managed) {
1536 hash_accum += frame->unmanaged_data.ip;
1537 } else {
1538 hash_accum += mono_metadata_str_hash (frame->str_descr);
1539 hash_accum += frame->managed_data.token;
1540 hash_accum += frame->managed_data.il_offset;
1543 return hash_accum;
1546 static gboolean
1547 summarize_frame_internal (MonoMethod *method, gpointer ip, size_t native_offset, int il_offset, gboolean managed, gpointer user_data)
1549 MonoSummarizeUserData *ud = (MonoSummarizeUserData *) user_data;
1551 gboolean valid_state = ud->num_frames + 1 < ud->max_frames;
1552 if (!valid_state) {
1553 ud->error = "Exceeded the maximum number of frames";
1554 return TRUE;
1557 MonoFrameSummary *dest = &ud->frames [ud->num_frames];
1559 dest->unmanaged_data.ip = (intptr_t) ip;
1560 dest->is_managed = managed;
1562 if (!managed && method && method->wrapper_type != MONO_WRAPPER_NONE && method->wrapper_type < MONO_WRAPPER_NUM) {
1563 dest->is_managed = FALSE;
1564 dest->unmanaged_data.has_name = TRUE;
1565 copy_summary_string_safe (dest->str_descr, mono_wrapper_type_to_str (method->wrapper_type));
1568 #ifndef MONO_PRIVATE_CRASHES
1569 if (method)
1570 dest->managed_data.name = (char *) method->name;
1571 #endif
1573 if (managed) {
1574 if (!method) {
1575 ud->error = "Managed method frame, but no provided managed method";
1576 return TRUE;
1579 MonoImage *image = mono_class_get_image (method->klass);
1580 // Used for hashing, more stable across rebuilds than using GUID
1581 copy_summary_string_safe (dest->str_descr, image->assembly_name);
1583 dest->managed_data.guid = image->guid;
1585 dest->managed_data.native_offset = native_offset;
1586 dest->managed_data.token = method->token;
1587 dest->managed_data.il_offset = il_offset;
1589 dest->managed_data.filename = image->module_name;
1591 MonoDotNetHeader *header = &image->image_info->cli_header;
1592 dest->managed_data.image_size = header->nt.pe_image_size;
1594 dest->managed_data.time_date_stamp = image->time_date_stamp;
1596 } else {
1597 dest->managed_data.token = -1;
1601 ud->hashes->offset_free_hash = summarize_offset_free_hash (ud->hashes->offset_free_hash, dest);
1602 ud->hashes->offset_rich_hash = summarize_offset_rich_hash (ud->hashes->offset_rich_hash, dest);
1604 // We return FALSE, so we're continuing walking
1605 // And we increment the pointer because we're done with this cell in the array
1606 ud->num_frames++;
1607 return FALSE;
1610 static gboolean
1611 summarize_frame_managed_walk (MonoMethod *method, gpointer ip, size_t frame_native_offset, gboolean managed, gpointer user_data)
1613 int il_offset = -1;
1615 if (managed && method) {
1616 MonoDebugSourceLocation *location = mono_debug_lookup_source_location (method, frame_native_offset, mono_domain_get ());
1617 if (location) {
1618 il_offset = location->il_offset;
1619 mono_debug_free_source_location (location);
1623 intptr_t portable_ip = 0;
1624 gint32 offset = 0;
1625 mono_get_portable_ip ((intptr_t) ip, &portable_ip, &offset, NULL, NULL);
1627 return summarize_frame_internal (method, (gpointer) portable_ip, frame_native_offset, il_offset, managed, user_data);
1631 static gboolean
1632 summarize_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
1634 // Don't record trampolines between managed frames
1635 if (frame->ji && frame->ji->is_trampoline)
1636 return TRUE;
1638 if (frame->ji && (frame->ji->is_trampoline || frame->ji->async))
1639 return FALSE; // Keep unwinding
1641 intptr_t ip = 0;
1642 gint32 offset = 0;
1643 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx), &ip, &offset, NULL, NULL);
1644 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1646 gboolean is_managed = (frame->type == FRAME_TYPE_MANAGED || frame->type == FRAME_TYPE_INTERP);
1647 MonoMethod *method = NULL;
1648 if (frame && frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
1649 method = jinfo_get_method (frame->ji);
1651 if (is_managed)
1652 method = jinfo_get_method (frame->ji);
1654 return summarize_frame_internal (method, (gpointer) ip, offset, frame->il_offset, is_managed, data);
1657 static void
1658 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1660 memset (out, 0, sizeof (MonoThreadSummary));
1662 MonoException *inner_exc = exc;
1663 int exc_index = 0;
1665 for (exc_index = 0; exc_index < MONO_MAX_SUMMARY_EXCEPTIONS; exc_index++) {
1666 if (inner_exc == NULL)
1667 break;
1669 // Set up state to walk this MonoException's stack
1670 MonoSummarizeUserData data;
1671 memset (&data, 0, sizeof (MonoSummarizeUserData));
1672 data.max_frames = MONO_MAX_SUMMARY_FRAMES;
1673 data.num_frames = 0;
1674 data.frames = out->exceptions [exc_index].managed_frames;
1676 // Accumulate all hashes from all exceptions in traveral order
1677 data.hashes = &out->hashes;
1679 mono_exception_walk_trace (inner_exc, summarize_frame_managed_walk, &data);
1681 // Save per-MonoException info
1682 out->exceptions [exc_index].managed_exc_type = inner_exc->object.vtable->klass;
1683 out->exceptions [exc_index].num_managed_frames = data.num_frames;
1685 // Continue to traverse nesting of exceptions
1686 inner_exc = (MonoException *) inner_exc->inner_ex;
1689 out->num_exceptions = exc_index;
1693 static void
1694 mono_summarize_managed_stack (MonoThreadSummary *out)
1696 MonoSummarizeUserData data;
1697 memset (&data, 0, sizeof (MonoSummarizeUserData));
1698 data.max_frames = MONO_MAX_SUMMARY_FRAMES;
1699 data.num_frames = 0;
1700 data.frames = out->managed_frames;
1701 data.hashes = &out->hashes;
1703 // FIXME: collect stack pointer for both and sort frames by SP
1704 // so people can see relative ordering of both managed and unmanaged frames.
1707 // Summarize managed stack
1709 mono_walk_stack_full (summarize_frame, out->ctx, out->domain, out->jit_tls, out->lmf, MONO_UNWIND_LOOKUP_IL_OFFSET, &data, TRUE);
1710 out->num_managed_frames = data.num_frames;
1712 if (data.error != NULL)
1713 out->error_msg = data.error;
1714 out->is_managed = (out->num_managed_frames != 0);
1717 // Always runs on the dumped thread
1718 static void
1719 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1721 MONO_ARCH_CONTEXT_DEF
1723 // Summarize unmanaged stack
1725 #ifdef HAVE_BACKTRACE_SYMBOLS
1726 intptr_t frame_ips [MONO_MAX_SUMMARY_FRAMES];
1728 out->num_unmanaged_frames = backtrace ((void **)frame_ips, MONO_MAX_SUMMARY_FRAMES);
1730 for (int i =0; i < out->num_unmanaged_frames; ++i) {
1731 intptr_t ip = frame_ips [i];
1732 MonoFrameSummary *frame = &out->unmanaged_frames [i];
1734 int success = mono_get_portable_ip (ip, &frame->unmanaged_data.ip, &frame->unmanaged_data.offset, &frame->unmanaged_data.module, (char *) frame->str_descr);
1735 if (!success)
1736 continue;
1738 if (out->unmanaged_frames [i].str_descr [0] != '\0')
1739 out->unmanaged_frames [i].unmanaged_data.has_name = TRUE;
1741 #endif
1743 out->lmf = mono_get_lmf ();
1745 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1746 out->info_addr = (intptr_t) thread;
1747 out->jit_tls = thread->jit_data;
1748 out->domain = mono_domain_get ();
1750 if (!out->ctx) {
1751 out->ctx = &out->ctx_mem;
1752 mono_arch_flush_register_windows ();
1753 MONO_INIT_CONTEXT_FROM_FUNC (out->ctx, mono_summarize_unmanaged_stack);
1756 return;
1758 #endif
1761 MonoBoolean
1762 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
1763 MonoReflectionMethod **method,
1764 gint32 *iloffset, gint32 *native_offset,
1765 MonoString **file, gint32 *line, gint32 *column)
1767 ERROR_DECL (error);
1768 MonoDomain *domain = mono_domain_get ();
1769 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1770 MonoLMF *lmf = mono_get_lmf ();
1771 MonoJitInfo *ji = NULL;
1772 MonoContext ctx, new_ctx;
1773 MonoDebugSourceLocation *location;
1774 MonoMethod *jmethod = NULL, *actual_method;
1775 StackFrameInfo frame;
1776 gboolean res;
1777 Unwinder unwinder;
1778 int il_offset = -1;
1780 MONO_ARCH_CONTEXT_DEF;
1782 g_assert (skip >= 0);
1784 if (mono_llvm_only) {
1785 GSList *l, *ips;
1786 MonoDomain *frame_domain;
1787 guint8 *frame_ip = NULL;
1789 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1790 jmethod = NULL;
1791 ips = get_unwind_backtrace ();
1792 for (l = ips; l && skip >= 0; l = l->next) {
1793 guint8 *ip = (guint8*)l->data;
1795 frame_ip = ip;
1797 ji = mini_jit_info_table_find (mono_domain_get (), ip, &frame_domain);
1798 if (!ji || ji->is_trampoline)
1799 continue;
1801 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1802 jmethod = jinfo_get_method (ji);
1803 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1804 continue;
1805 skip--;
1807 g_slist_free (ips);
1808 if (!jmethod || !l)
1809 return FALSE;
1810 /* No way to resolve generic instances */
1811 actual_method = jmethod;
1812 *native_offset = frame_ip - (guint8*)ji->code_start;
1813 } else {
1814 mono_arch_flush_register_windows ();
1815 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
1817 unwinder_init (&unwinder);
1819 new_ctx = ctx;
1820 do {
1821 ctx = new_ctx;
1822 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1823 if (!res)
1824 return FALSE;
1825 switch (frame.type) {
1826 case FRAME_TYPE_MANAGED_TO_NATIVE:
1827 case FRAME_TYPE_DEBUGGER_INVOKE:
1828 case FRAME_TYPE_TRAMPOLINE:
1829 case FRAME_TYPE_INTERP_TO_MANAGED:
1830 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
1831 continue;
1832 case FRAME_TYPE_INTERP:
1833 case FRAME_TYPE_MANAGED:
1834 ji = frame.ji;
1835 *native_offset = frame.native_offset;
1837 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1838 jmethod = jinfo_get_method (ji);
1839 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1840 continue;
1841 skip--;
1842 break;
1843 default:
1844 g_assert_not_reached ();
1846 } while (skip >= 0);
1848 if (frame.type == FRAME_TYPE_INTERP) {
1849 jmethod = frame.method;
1850 actual_method = frame.actual_method;
1851 } else {
1852 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
1856 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, error);
1857 if (!mono_error_ok (error)) {
1858 mono_error_set_pending_exception (error);
1859 return FALSE;
1861 mono_gc_wbarrier_generic_store_internal (method, (MonoObject*) rm);
1863 if (il_offset != -1) {
1864 location = mono_debug_lookup_source_location_by_il (jmethod, il_offset, domain);
1865 } else {
1866 location = mono_debug_lookup_source_location (jmethod, *native_offset, domain);
1868 if (location)
1869 *iloffset = location->il_offset;
1870 else
1871 *iloffset = 0;
1873 if (need_file_info) {
1874 if (location) {
1875 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1876 if (!is_ok (error)) {
1877 mono_error_set_pending_exception (error);
1878 return FALSE;
1880 mono_gc_wbarrier_generic_store_internal (file, (MonoObject*)filename);
1881 *line = location->row;
1882 *column = location->column;
1883 } else {
1884 *file = NULL;
1885 *line = *column = 0;
1889 mono_debug_free_source_location (location);
1891 return TRUE;
1894 static MonoClass*
1895 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1897 ERROR_DECL (error);
1898 MonoClass *catch_class = ei->data.catch_class;
1899 MonoType *inflated_type;
1900 MonoGenericContext context;
1902 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1903 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
1904 return NULL;
1906 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1907 return catch_class;
1908 context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1910 /* FIXME: we shouldn't inflate but instead put the
1911 type in the rgctx and fetch it from there. It
1912 might be a good idea to do this lazily, i.e. only
1913 when the exception is actually thrown, so as not to
1914 waste space for exception clauses which might never
1915 be encountered. */
1916 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
1917 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1919 catch_class = mono_class_from_mono_type_internal (inflated_type);
1920 mono_metadata_free_type (inflated_type);
1922 return catch_class;
1926 * mini_jit_info_table_find_ext:
1928 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1929 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1930 * OUT_DOMAIN if it is not NULL.
1932 MonoJitInfo*
1933 mini_jit_info_table_find_ext (MonoDomain *domain, gpointer addr, gboolean allow_trampolines, MonoDomain **out_domain)
1935 MonoJitInfo *ji;
1936 MonoInternalThread *t = mono_thread_internal_current ();
1937 gpointer *refs;
1939 if (out_domain)
1940 *out_domain = NULL;
1942 ji = mono_jit_info_table_find_internal (domain, addr, TRUE, allow_trampolines);
1943 if (ji) {
1944 if (out_domain)
1945 *out_domain = domain;
1946 return ji;
1949 /* maybe it is shared code, so we also search in the root domain */
1950 if (domain != mono_get_root_domain ()) {
1951 ji = mono_jit_info_table_find_internal (mono_get_root_domain (), addr, TRUE, allow_trampolines);
1952 if (ji) {
1953 if (out_domain)
1954 *out_domain = mono_get_root_domain ();
1955 return ji;
1959 if (!t)
1960 return NULL;
1962 refs = (gpointer *)((t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL);
1963 for (; refs && *refs; refs++) {
1964 if (*refs != domain && *refs != mono_get_root_domain ()) {
1965 ji = mono_jit_info_table_find_internal ((MonoDomain*) *refs, addr, TRUE, allow_trampolines);
1966 if (ji) {
1967 if (out_domain)
1968 *out_domain = (MonoDomain*) *refs;
1969 return ji;
1974 return NULL;
1977 MonoJitInfo*
1978 mini_jit_info_table_find (MonoDomain *domain, gpointer addr, MonoDomain **out_domain)
1980 return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain);
1983 /* Class lazy loading functions */
1984 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
1987 * wrap_non_exception_throws:
1989 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
1990 * WrapNonExceptionThrows flag set.
1992 static gboolean
1993 wrap_non_exception_throws (MonoMethod *m)
1995 ERROR_DECL (error);
1996 MonoAssembly *ass = m_class_get_image (m->klass)->assembly;
1997 MonoCustomAttrInfo* attrs;
1998 MonoClass *klass;
1999 int i;
2000 gboolean val = FALSE;
2002 if (m->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
2003 MonoDynamicMethod *dm = (MonoDynamicMethod *)m;
2004 if (dm->assembly)
2005 ass = dm->assembly;
2007 g_assert (ass);
2008 if (ass->wrap_non_exception_throws_inited)
2009 return ass->wrap_non_exception_throws;
2011 klass = mono_class_get_runtime_compat_attr_class ();
2013 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, error);
2014 mono_error_cleanup (error); /* FIXME don't swallow the error */
2015 if (attrs) {
2016 for (i = 0; i < attrs->num_attrs; ++i) {
2017 MonoCustomAttrEntry *attr = &attrs->attrs [i];
2018 const gchar *p;
2019 int num_named, named_type, name_len;
2020 char *name;
2022 if (!attr->ctor || attr->ctor->klass != klass)
2023 continue;
2024 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2025 p = (const char*)attr->data;
2026 g_assert (read16 (p) == 0x0001);
2027 p += 2;
2028 num_named = read16 (p);
2029 if (num_named != 1)
2030 continue;
2031 p += 2;
2032 named_type = *p;
2033 p ++;
2034 /* data_type = *p; */
2035 p ++;
2036 /* Property */
2037 if (named_type != 0x54)
2038 continue;
2039 name_len = mono_metadata_decode_blob_size (p, &p);
2040 name = (char *)g_malloc (name_len + 1);
2041 memcpy (name, p, name_len);
2042 name [name_len] = 0;
2043 p += name_len;
2044 g_assert (!strcmp (name, "WrapNonExceptionThrows"));
2045 g_free (name);
2046 /* The value is a BOOLEAN */
2047 val = *p;
2049 mono_custom_attrs_free (attrs);
2052 ass->wrap_non_exception_throws = val;
2053 mono_memory_barrier ();
2054 ass->wrap_non_exception_throws_inited = TRUE;
2056 return val;
2059 #define MAX_UNMANAGED_BACKTRACE 128
2060 static MonoArray*
2061 build_native_trace (MonoError *error)
2063 error_init (error);
2064 /* This puppy only makes sense on mobile, IOW, ARM. */
2065 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2066 MonoArray *res;
2067 void *native_trace [MAX_UNMANAGED_BACKTRACE];
2068 int size = -1;
2069 MONO_ENTER_GC_SAFE;
2070 size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE);
2071 MONO_EXIT_GC_SAFE;
2072 int i;
2074 if (!size)
2075 return NULL;
2076 res = mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, size, error);
2077 return_val_if_nok (error, NULL);
2079 for (i = 0; i < size; i++)
2080 mono_array_set_internal (res, gpointer, i, native_trace [i]);
2081 return res;
2082 #else
2083 return NULL;
2084 #endif
2087 static void
2088 remove_wrappers_from_trace (GList **trace_ips_p)
2090 GList *trace_ips = *trace_ips_p;
2091 GList *p = trace_ips;
2093 /* jit info, generic info, ip */
2094 while (p) {
2095 MonoJitInfo *jinfo = (MonoJitInfo*) p->data;
2096 GList *next_p = p->next->next->next;
2097 /* FIXME Maybe remove more wrapper types */
2098 if (jinfo->d.method->wrapper_type == MONO_WRAPPER_OTHER) {
2099 trace_ips = g_list_delete_link (trace_ips, p->next->next);
2100 trace_ips = g_list_delete_link (trace_ips, p->next);
2101 trace_ips = g_list_delete_link (trace_ips, p);
2103 p = next_p;
2106 *trace_ips_p = trace_ips;
2109 /* This can be called more than once on a MonoException. */
2110 static void
2111 setup_stack_trace (MonoException *mono_ex, GSList **dynamic_methods, GList *trace_ips, gboolean remove_wrappers)
2113 if (mono_ex) {
2114 GList *trace_ips_copy = g_list_copy (trace_ips);
2115 if (remove_wrappers)
2116 remove_wrappers_from_trace (&trace_ips_copy);
2117 trace_ips_copy = g_list_reverse (trace_ips_copy);
2118 ERROR_DECL (error);
2119 MonoArray *ips_arr = mono_glist_to_array (trace_ips_copy, mono_defaults.int_class, error);
2120 mono_error_assert_ok (error);
2121 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
2122 MONO_OBJECT_SETREF_INTERNAL (mono_ex, native_trace_ips, build_native_trace (error));
2123 mono_error_assert_ok (error);
2124 if (*dynamic_methods) {
2125 /* These methods could go away anytime, so save a reference to them in the exception object */
2126 GSList *l;
2127 MonoMList *list = (MonoMList*)mono_ex->dynamic_methods;
2129 for (l = *dynamic_methods; l; l = l->next) {
2130 guint32 dis_link;
2131 MonoDomain *domain = mono_domain_get ();
2133 if (domain->method_to_dyn_method) {
2134 mono_domain_lock (domain);
2135 dis_link = (guint32)(size_t)g_hash_table_lookup (domain->method_to_dyn_method, l->data);
2136 mono_domain_unlock (domain);
2137 if (dis_link) {
2138 MonoObject *o = mono_gchandle_get_target_internal (dis_link);
2139 if (o) {
2140 list = mono_mlist_prepend_checked (list, o, error);
2141 mono_error_assert_ok (error);
2147 MONO_OBJECT_SETREF_INTERNAL (mono_ex, dynamic_methods, list);
2149 g_slist_free (*dynamic_methods);
2150 *dynamic_methods = NULL;
2153 g_list_free (trace_ips_copy);
2157 typedef enum {
2158 MONO_FIRST_PASS_UNHANDLED,
2159 MONO_FIRST_PASS_CALLBACK_TO_NATIVE,
2160 MONO_FIRST_PASS_HANDLED,
2161 } MonoFirstPassResult;
2164 * handle_exception_first_pass:
2166 * The first pass of exception handling. Unwind the stack until a catch
2167 * clause which can catch OBJ is found. Store the index of the filter clause
2168 * which caught the exception into OUT_FILTER_IDX. Return
2169 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2170 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2171 * wrapper and an exception handling callback is installed (in which case
2172 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2174 static MonoFirstPassResult
2175 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)
2177 ERROR_DECL (error);
2178 MonoDomain *domain = mono_domain_get ();
2179 MonoJitInfo *ji = NULL;
2180 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2181 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2182 MonoLMF *lmf = mono_get_lmf ();
2183 GList *trace_ips = NULL;
2184 GSList *dynamic_methods = NULL;
2185 MonoException *mono_ex;
2186 gboolean stack_overflow = FALSE;
2187 MonoContext initial_ctx;
2188 MonoMethod *method;
2189 int frame_count = 0;
2190 gint32 filter_idx;
2191 int i;
2192 MonoObject *ex_obj;
2193 Unwinder unwinder;
2194 gboolean in_interp;
2196 MonoFirstPassResult result = MONO_FIRST_PASS_UNHANDLED;
2198 g_assert (ctx != NULL);
2200 if (obj == (MonoObject *)domain->stack_overflow_ex)
2201 stack_overflow = TRUE;
2203 mono_ex = (MonoException*)obj;
2204 MonoArray *initial_trace_ips = mono_ex->trace_ips;
2205 if (initial_trace_ips) {
2206 int len = mono_array_length_internal (initial_trace_ips) / TRACE_IP_ENTRY_SIZE;
2208 // If we catch in managed/non-wrapper, we don't save the catching frame
2209 if (!mono_ex->caught_in_unmanaged)
2210 len -= 1;
2212 for (i = 0; i < len; i++) {
2213 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
2214 gpointer p = mono_array_get_internal (initial_trace_ips, gpointer, (i * TRACE_IP_ENTRY_SIZE) + j);
2215 trace_ips = g_list_prepend (trace_ips, p);
2220 // Reset the state because we're making it be caught somewhere
2221 if (mono_ex->caught_in_unmanaged)
2222 MONO_OBJECT_SETREF_INTERNAL (mono_ex, caught_in_unmanaged, 0);
2224 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2225 mono_error_assert_ok (error);
2226 mono_ex = NULL;
2229 if (!call_filter)
2230 call_filter = (int (*) (MonoContext *, void *))mono_get_call_filter ();
2232 g_assert (jit_tls->end_of_stack);
2233 g_assert (jit_tls->abort_func);
2235 if (out_filter_idx)
2236 *out_filter_idx = -1;
2237 if (out_ji)
2238 *out_ji = NULL;
2239 if (out_prev_ji)
2240 *out_prev_ji = NULL;
2241 filter_idx = 0;
2242 initial_ctx = *ctx;
2244 unwinder_init (&unwinder);
2246 while (1) {
2247 MonoContext new_ctx;
2248 guint32 free_stack;
2249 int clause_index_start = 0;
2250 gboolean unwind_res = TRUE;
2252 StackFrameInfo frame;
2254 if (out_prev_ji)
2255 *out_prev_ji = ji;
2257 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2258 if (!unwind_res) {
2259 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, FALSE);
2260 g_list_free (trace_ips);
2261 return result;
2264 switch (frame.type) {
2265 case FRAME_TYPE_DEBUGGER_INVOKE:
2266 case FRAME_TYPE_MANAGED_TO_NATIVE:
2267 case FRAME_TYPE_TRAMPOLINE:
2268 case FRAME_TYPE_INTERP_TO_MANAGED:
2269 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2270 *ctx = new_ctx;
2271 continue;
2272 case FRAME_TYPE_INTERP:
2273 case FRAME_TYPE_MANAGED:
2274 break;
2275 default:
2276 g_assert_not_reached ();
2277 break;
2280 in_interp = frame.type == FRAME_TYPE_INTERP;
2281 ji = frame.ji;
2283 gpointer ip;
2284 if (in_interp)
2285 ip = (guint8*)ji->code_start + frame.native_offset;
2286 else
2287 ip = MONO_CONTEXT_GET_IP (ctx);
2289 frame_count ++;
2290 method = jinfo_get_method (ji);
2291 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2293 if (mini_get_debug_options ()->reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2294 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2295 "The native frame called the managed method:\n%s\n",
2296 mono_method_full_name (method, TRUE));
2299 if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
2300 // avoid giant stack traces during a stack overflow
2301 if (frame_count < 1000) {
2302 trace_ips = g_list_prepend (trace_ips, ip);
2303 trace_ips = g_list_prepend (trace_ips, get_generic_info_from_stack_frame (ji, ctx));
2304 trace_ips = g_list_prepend (trace_ips, ji);
2308 if (method->dynamic)
2309 dynamic_methods = g_slist_prepend (dynamic_methods, method);
2311 if (stack_overflow) {
2312 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2313 } else {
2314 free_stack = 0xffffff;
2317 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && ftnptr_eh_callback) {
2318 result = MONO_FIRST_PASS_CALLBACK_TO_NATIVE;
2322 for (i = clause_index_start; i < ji->num_clauses; i++) {
2323 MonoJitExceptionInfo *ei = &ji->clauses [i];
2324 gboolean filtered = FALSE;
2327 * During stack overflow, wait till the unwinding frees some stack
2328 * space before running handlers/finalizers.
2330 if (free_stack <= (64 * 1024))
2331 continue;
2333 if (is_address_protected (ji, ei, ip)) {
2334 /* catch block */
2335 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2338 * Have to unwrap RuntimeWrappedExceptions if the
2339 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2341 if (non_exception && !wrap_non_exception_throws (method))
2342 ex_obj = non_exception;
2343 else
2344 ex_obj = obj;
2346 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2347 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, FALSE);
2349 #ifndef DISABLE_PERFCOUNTERS
2350 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_filters);
2351 #endif
2353 if (!ji->is_interp) {
2354 #ifndef MONO_CROSS_COMPILE
2355 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2356 if (ji->from_llvm)
2357 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2358 else
2359 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2360 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2361 #else
2362 g_assert (!ji->from_llvm);
2363 /* store the exception object in bp + ei->exvar_offset */
2364 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2365 #endif
2366 #endif
2368 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2370 * Pass the original il clause index to the landing pad so it can
2371 * branch to the landing pad associated with the il clause.
2372 * This is needed because llvm compiled code assumes that the EH
2373 * code always branches to the innermost landing pad.
2375 if (ji->from_llvm)
2376 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2377 #endif
2380 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex, ctx, &initial_ctx);
2382 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2383 jit_tls->orig_ex_ctx_set = TRUE;
2384 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2385 jit_tls->orig_ex_ctx_set = FALSE;
2388 if (ji->is_interp) {
2389 /* The filter ends where the exception handler starts */
2390 filtered = mini_get_interp_callbacks ()->run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter, ei->handler_start);
2391 } else {
2392 filtered = call_filter (ctx, ei->data.filter);
2394 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex, ctx, &initial_ctx);
2395 if (filtered && out_filter_idx)
2396 *out_filter_idx = filter_idx;
2397 if (out_ji)
2398 *out_ji = ji;
2399 filter_idx ++;
2401 if (filtered) {
2402 g_list_free (trace_ips);
2403 /* mono_debugger_agent_handle_exception () needs this */
2404 mini_set_abort_threshold (&frame);
2405 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2406 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
2407 *catch_frame = frame;
2408 result = MONO_FIRST_PASS_HANDLED;
2409 return result;
2413 ERROR_DECL (isinst_error); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2414 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, error)) {
2415 /* runtime invokes catch even unhandled exceptions */
2416 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE);
2417 g_list_free (trace_ips);
2419 if (out_ji)
2420 *out_ji = ji;
2422 /* mono_debugger_agent_handle_exception () needs this */
2423 if (!in_interp)
2424 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2425 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
2426 *catch_frame = frame;
2427 result = MONO_FIRST_PASS_HANDLED;
2428 return result;
2430 mono_error_cleanup (isinst_error);
2434 *ctx = new_ctx;
2437 g_assert_not_reached ();
2441 * We implement delaying of aborts when in finally blocks by reusing the
2442 * abort protected block mechanism. The problem is that when throwing an
2443 * exception in a finally block we don't get to exit the protected block.
2444 * We exit it here when unwinding. Given that the order of the clauses
2445 * in the jit info is from inner clauses to the outer clauses, when we
2446 * want to exit the finally blocks inner to the clause that handles the
2447 * exception, we need to search up to its index.
2449 * FIXME We should do this inside interp, but with mixed mode we can
2450 * resume directly, without giving control back to the interp.
2452 static void
2453 interp_exit_finally_abort_blocks (MonoJitInfo *ji, int start_clause, int end_clause, gpointer ip)
2455 int i;
2456 for (i = start_clause; i < end_clause; i++) {
2457 MonoJitExceptionInfo *ei = &ji->clauses [i];
2458 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY &&
2459 ip >= ei->handler_start &&
2460 ip < ei->data.handler_end) {
2461 mono_threads_end_abort_protected_block ();
2466 static MonoException *
2467 mono_get_exception_runtime_wrapped_checked (MonoObject *wrapped_exception_raw, MonoError *error)
2469 HANDLE_FUNCTION_ENTER ();
2470 MONO_HANDLE_DCL (MonoObject, wrapped_exception);
2471 MonoExceptionHandle ret = mono_get_exception_runtime_wrapped_handle (wrapped_exception, error);
2472 HANDLE_FUNCTION_RETURN_OBJ (ret);
2476 * mono_handle_exception_internal:
2477 * \param ctx saved processor state
2478 * \param obj the exception object
2479 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2481 static gboolean
2482 mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji)
2484 ERROR_DECL (error);
2485 MonoDomain *domain = mono_domain_get ();
2486 MonoJitInfo *ji, *prev_ji;
2487 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2488 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2489 MonoLMF *lmf = mono_get_lmf ();
2490 MonoException *mono_ex;
2491 gboolean stack_overflow = FALSE;
2492 MonoContext initial_ctx;
2493 MonoMethod *method;
2494 int frame_count = 0;
2495 gint32 filter_idx, first_filter_idx = 0;
2496 int i;
2497 MonoObject *ex_obj = NULL;
2498 MonoObject *non_exception = NULL;
2499 Unwinder unwinder;
2500 gboolean in_interp;
2502 g_assert (ctx != NULL);
2503 if (!obj) {
2504 MonoException *ex = mono_get_exception_null_reference ();
2505 MonoString *msg = mono_string_new_checked (domain, "Object reference not set to an instance of an object", error);
2506 mono_error_assert_ok (error);
2507 MONO_OBJECT_SETREF_INTERNAL (ex, message, msg);
2508 obj = (MonoObject *)ex;
2512 * Allocate a new exception object instead of the preconstructed ones.
2514 if (obj == (MonoObject *)domain->stack_overflow_ex) {
2516 * It is not a good idea to try and put even more pressure on the little stack available.
2517 * obj = mono_get_exception_stack_overflow ();
2519 stack_overflow = TRUE;
2521 else if (obj == (MonoObject *)domain->null_reference_ex) {
2522 obj = (MonoObject *)mono_get_exception_null_reference ();
2525 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2526 mono_error_assert_ok (error);
2527 non_exception = obj;
2528 obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, error);
2529 mono_error_assert_ok (error);
2532 mono_ex = (MonoException*)obj;
2534 if (mini_get_debug_options ()->suspend_on_exception) {
2535 mono_runtime_printf_err ("Exception thrown, suspending...");
2536 while (1)
2540 if (mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2541 mono_ex = (MonoException*)obj;
2542 } else {
2543 mono_error_assert_ok (error);
2544 mono_ex = NULL;
2547 if (mono_ex && jit_tls->class_cast_from) {
2548 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "InvalidCastException")) {
2549 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
2550 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
2551 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
2552 mono_ex->message = mono_string_new_checked (domain, msg, error);
2553 g_free (from_name);
2554 g_free (to_name);
2555 if (!is_ok (error)) {
2556 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg);
2557 mono_error_assert_ok (error);
2559 g_free (msg);
2561 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "ArrayTypeMismatchException")) {
2562 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
2563 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
2564 char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
2565 mono_ex->message = mono_string_new_checked (domain, msg, error);
2566 g_free (from_name);
2567 g_free (to_name);
2568 if (!is_ok (error)) {
2569 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg);
2570 mono_error_assert_ok (error);
2572 g_free (msg);
2576 if (!call_filter)
2577 call_filter = (int (*)(MonoContext *, void*))mono_get_call_filter ();
2579 g_assert (jit_tls->end_of_stack);
2580 g_assert (jit_tls->abort_func);
2583 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2584 * end up being TRUE on any code path.
2586 memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
2588 if (!resume) {
2589 MonoContext ctx_cp = *ctx;
2590 if (mono_trace_is_enabled ()) {
2591 ERROR_DECL (error);
2592 MonoMethod *system_exception_get_message = mono_class_get_method_from_name_checked (mono_defaults.exception_class, "get_Message", 0, 0, error);
2593 mono_error_cleanup (error);
2594 error_init (error);
2595 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method_internal (obj, system_exception_get_message);
2596 MonoObject *message;
2597 const char *type_name = m_class_get_name (mono_object_class (mono_ex));
2598 char *msg = NULL;
2599 if (get_message == NULL) {
2600 message = NULL;
2601 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
2602 message = NULL;
2603 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
2604 } else {
2605 MonoObject *exc = NULL;
2606 message = mono_runtime_try_invoke (get_message, obj, NULL, &exc, error);
2607 g_assert (exc == NULL);
2608 mono_error_assert_ok (error);
2610 if (msg == NULL) {
2611 if (message) {
2612 msg = mono_string_to_utf8_checked_internal ((MonoString *) message, error);
2613 if (!is_ok (error)) {
2614 mono_error_cleanup (error);
2615 msg = g_strdup ("(error while display System.Exception.Message property)");
2617 } else {
2618 msg = g_strdup ("(System.Exception.Message property not available)");
2621 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);
2622 g_free (msg);
2623 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
2624 mono_print_thread_dump_from_ctx (ctx);
2626 jit_tls->orig_ex_ctx_set = TRUE;
2627 MONO_PROFILER_RAISE (exception_throw, (obj));
2628 jit_tls->orig_ex_ctx_set = FALSE;
2630 StackFrameInfo catch_frame;
2631 MonoFirstPassResult res;
2632 res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame);
2634 if (res == MONO_FIRST_PASS_UNHANDLED) {
2635 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2636 /* Reached the top interpreted frames, but there might be native frames above us */
2637 throw_exception (obj, TRUE);
2638 g_assert_not_reached ();
2640 if (mini_get_debug_options ()->break_on_exc)
2641 G_BREAKPOINT ();
2642 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2644 if (mini_get_debug_options ()->suspend_on_unhandled) {
2645 mono_runtime_printf_err ("Unhandled exception, suspending...");
2646 while (1)
2650 // FIXME: This runs managed code so it might cause another stack overflow when
2651 // we are handling a stack overflow
2652 mini_set_abort_threshold (&catch_frame);
2653 mono_unhandled_exception_internal (obj);
2654 } else {
2655 gboolean unhandled = FALSE;
2658 * The exceptions caught by the mono_runtime_invoke_checked () calls
2659 * in the threadpool needs to be treated as unhandled (#669836).
2661 * FIXME: The check below is hackish, but its hard to distinguish
2662 * these runtime invoke calls from others in the runtime.
2664 if (ji && jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2665 if (prev_ji && jinfo_get_method (prev_ji) == mono_defaults.threadpool_perform_wait_callback_method)
2666 unhandled = TRUE;
2669 if (unhandled)
2670 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2671 else if (jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2672 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2673 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2675 else if (res != MONO_FIRST_PASS_CALLBACK_TO_NATIVE)
2676 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2680 if (out_ji)
2681 *out_ji = NULL;
2682 filter_idx = 0;
2683 initial_ctx = *ctx;
2685 unwinder_init (&unwinder);
2687 while (1) {
2688 MonoContext new_ctx;
2689 guint32 free_stack;
2690 int clause_index_start = 0;
2691 gboolean unwind_res = TRUE;
2692 StackFrameInfo frame;
2693 gpointer ip;
2695 if (resume) {
2696 resume = FALSE;
2697 ji = jit_tls->resume_state.ji;
2698 new_ctx = jit_tls->resume_state.new_ctx;
2699 clause_index_start = jit_tls->resume_state.clause_index;
2700 lmf = jit_tls->resume_state.lmf;
2701 first_filter_idx = jit_tls->resume_state.first_filter_idx;
2702 filter_idx = jit_tls->resume_state.filter_idx;
2703 in_interp = FALSE;
2704 } else {
2705 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2706 if (!unwind_res) {
2707 *(mono_get_lmf_addr ()) = lmf;
2709 jit_tls->abort_func (obj);
2710 g_assert_not_reached ();
2712 switch (frame.type) {
2713 case FRAME_TYPE_DEBUGGER_INVOKE:
2714 case FRAME_TYPE_MANAGED_TO_NATIVE:
2715 case FRAME_TYPE_TRAMPOLINE:
2716 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2717 *ctx = new_ctx;
2718 continue;
2719 case FRAME_TYPE_INTERP_TO_MANAGED:
2720 continue;
2721 case FRAME_TYPE_INTERP:
2722 case FRAME_TYPE_MANAGED:
2723 break;
2724 default:
2725 g_assert_not_reached ();
2726 break;
2728 in_interp = frame.type == FRAME_TYPE_INTERP;
2729 ji = frame.ji;
2732 if (in_interp)
2733 ip = (guint8*)ji->code_start + frame.native_offset;
2734 else
2735 ip = MONO_CONTEXT_GET_IP (ctx);
2737 method = jinfo_get_method (ji);
2738 frame_count ++;
2739 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2741 if (stack_overflow) {
2742 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2743 } else {
2744 free_stack = 0xffffff;
2747 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && ftnptr_eh_callback) {
2748 guint32 handle = mono_gchandle_new_internal (obj, FALSE);
2749 MONO_STACKDATA (stackptr);
2751 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr);
2752 mono_set_lmf (lmf);
2753 ftnptr_eh_callback (handle);
2754 g_error ("Did not expect ftnptr_eh_callback to return.");
2757 for (i = clause_index_start; i < ji->num_clauses; i++) {
2758 MonoJitExceptionInfo *ei = &ji->clauses [i];
2759 gboolean filtered = FALSE;
2762 * During stack overflow, wait till the unwinding frees some stack
2763 * space before running handlers/finalizers.
2765 if (free_stack <= (64 * 1024))
2766 continue;
2768 if (is_address_protected (ji, ei, ip)) {
2769 /* catch block */
2770 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2773 * Have to unwrap RuntimeWrappedExceptions if the
2774 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2776 if (non_exception && !wrap_non_exception_throws (method))
2777 ex_obj = non_exception;
2778 else
2779 ex_obj = obj;
2781 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
2782 #ifndef MONO_CROSS_COMPILE
2783 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2784 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2785 #else
2786 g_assert (!ji->from_llvm);
2787 /* store the exception object in bp + ei->exvar_offset */
2788 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2789 #endif
2790 #endif
2793 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2794 if (ji->from_llvm)
2795 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2796 #endif
2798 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2800 * Filter clauses should only be run in the
2801 * first pass of exception handling.
2803 filtered = (filter_idx == first_filter_idx);
2804 filter_idx ++;
2807 error_init (error);
2808 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
2809 mono_object_isinst_checked (ex_obj, catch_class, error)) || filtered) {
2811 * This guards against the situation that we abort a thread that is executing a finally clause
2812 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2813 * check for this situation here and resume interruption if we are below the guarded block.
2815 if (G_UNLIKELY (jit_tls->handler_block)) {
2816 gboolean is_outside = FALSE;
2817 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
2818 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
2819 //FIXME make this stack direction aware
2821 if (catch_bp > prot_bp) {
2822 is_outside = TRUE;
2823 } else if (catch_bp == prot_bp) {
2824 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2825 * So we check if the catch handler_start is protected by the guarded handler protected region
2827 * Assumptions:
2828 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2829 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2830 * There aren't any further finally/fault handler blocks down the stack over this exception.
2831 * This must be ensured by the code that installs the guard trampoline.
2833 g_assert (ji == mini_jit_info_table_find (domain, (char *)MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
2835 if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
2836 is_outside = TRUE;
2839 if (is_outside) {
2840 jit_tls->handler_block = NULL;
2841 mono_thread_resume_interruption (TRUE); /*We ignore the exception here, it will be raised later*/
2845 if (mono_trace_is_enabled () && mono_trace_eval (method))
2846 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2849 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2850 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2851 * clause. Since we specifically want to indicate that we're executing the
2852 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2853 * instead of ei->flags.
2855 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2856 jit_tls->orig_ex_ctx_set = TRUE;
2857 MONO_PROFILER_RAISE (exception_clause, (method, i, MONO_EXCEPTION_CLAUSE_NONE, ex_obj));
2858 jit_tls->orig_ex_ctx_set = FALSE;
2861 mini_set_abort_threshold (&frame);
2863 if (in_interp) {
2864 interp_exit_finally_abort_blocks (ji, clause_index_start, i, ip);
2866 * ctx->pc points into the interpreter, after the call which transitioned to
2867 * JITted code. Store the unwind state into the
2868 * interpeter state, then resume, the interpreter will unwind itself until
2869 * it reaches the target frame and will continue execution from there.
2870 * The resuming is kinda hackish, from the native code standpoint, it looks
2871 * like the call which transitioned to JITted code has succeeded, but the
2872 * return value register etc. is not set, so we have to be careful.
2874 mini_get_interp_callbacks ()->set_resume_state (jit_tls, mono_ex, ei, frame.interp_frame, ei->handler_start);
2875 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2876 /* ip == 0 means an interpreter frame */
2877 if (MONO_CONTEXT_GET_IP (ctx) != 0)
2878 mono_arch_undo_ip_adjustment (ctx);
2879 } else {
2880 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2882 mono_set_lmf (lmf);
2883 #ifndef DISABLE_PERFCOUNTERS
2884 mono_atomic_fetch_add_i32 (&mono_perfcounters->exceptions_depth, frame_count);
2885 #endif
2886 if (obj == (MonoObject *)domain->stack_overflow_ex)
2887 jit_tls->handling_stack_ovf = FALSE;
2889 return 0;
2891 mono_error_cleanup (error);
2892 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
2893 if (mono_trace_is_enabled () && mono_trace_eval (method))
2894 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2896 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2897 jit_tls->orig_ex_ctx_set = TRUE;
2898 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2899 jit_tls->orig_ex_ctx_set = FALSE;
2902 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2903 if (mono_trace_is_enabled () && mono_trace_eval (method))
2904 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2906 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2907 jit_tls->orig_ex_ctx_set = TRUE;
2908 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2909 jit_tls->orig_ex_ctx_set = FALSE;
2912 #ifndef DISABLE_PERFCOUNTERS
2913 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_finallys);
2914 #endif
2916 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2917 mono_set_lmf (lmf);
2918 if (ji->from_llvm) {
2920 * LLVM compiled finally handlers follow the design
2921 * of the c++ ehabi, i.e. they call a resume function
2922 * at the end instead of returning to the caller.
2923 * So save the exception handling state,
2924 * mono_resume_unwind () will call us again to continue
2925 * the unwinding.
2927 jit_tls->resume_state.ex_obj = obj;
2928 jit_tls->resume_state.ji = ji;
2929 jit_tls->resume_state.clause_index = i + 1;
2930 jit_tls->resume_state.ctx = *ctx;
2931 jit_tls->resume_state.new_ctx = new_ctx;
2932 jit_tls->resume_state.lmf = lmf;
2933 jit_tls->resume_state.first_filter_idx = first_filter_idx;
2934 jit_tls->resume_state.filter_idx = filter_idx;
2935 mini_set_abort_threshold (&frame);
2936 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2937 return 0;
2938 } else {
2939 mini_set_abort_threshold (&frame);
2940 if (in_interp) {
2941 gboolean has_ex = mini_get_interp_callbacks ()->run_finally (&frame, i, ei->handler_start, ei->data.handler_end);
2942 if (has_ex) {
2944 * If run_finally didn't resume to a context, it means that the handler frame
2945 * is linked to the frame calling finally through interpreter frames. This
2946 * means that we will reach the handler frame by resuming the current context.
2948 if (MONO_CONTEXT_GET_IP (ctx) != 0)
2949 mono_arch_undo_ip_adjustment (ctx);
2950 return 0;
2952 } else {
2953 call_filter (ctx, ei->handler_start);
2960 if (in_interp)
2961 interp_exit_finally_abort_blocks (ji, clause_index_start, ji->num_clauses, ip);
2963 if (MONO_PROFILER_ENABLED (method_exception_leave) &&
2964 mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) {
2965 jit_tls->orig_ex_ctx_set = TRUE;
2966 MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
2967 jit_tls->orig_ex_ctx_set = FALSE;
2970 *ctx = new_ctx;
2973 g_assert_not_reached ();
2977 * mono_debugger_run_finally:
2978 * \param start_ctx saved processor state
2979 * This method is called by the Mono Debugger to call all \c finally clauses of the
2980 * current stack frame. It's used when the user issues a \c return command to make
2981 * the current stack frame return. After returning from this method, the debugger
2982 * unwinds the stack one frame and gives control back to the user.
2983 * NOTE: This method is only used when running inside the Mono Debugger.
2985 void
2986 mono_debugger_run_finally (MonoContext *start_ctx)
2988 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2989 MonoDomain *domain = mono_domain_get ();
2990 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2991 MonoLMF *lmf = mono_get_lmf ();
2992 MonoContext ctx, new_ctx;
2993 MonoJitInfo *ji, rji;
2994 int i;
2996 ctx = *start_ctx;
2998 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
2999 if (!ji || ji == (gpointer)-1)
3000 return;
3002 if (!call_filter)
3003 call_filter = (int (*)(MonoContext *, void *))mono_get_call_filter ();
3005 for (i = 0; i < ji->num_clauses; i++) {
3006 MonoJitExceptionInfo *ei = &ji->clauses [i];
3008 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
3009 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
3010 call_filter (&ctx, ei->handler_start);
3016 * mono_handle_exception:
3017 * \param ctx saved processor state
3018 * \param obj the exception object
3020 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3021 * return TRUE.
3023 gboolean
3024 mono_handle_exception (MonoContext *ctx, gpointer void_obj)
3026 MonoObject *obj = (MonoObject*)void_obj;
3028 MONO_REQ_GC_UNSAFE_MODE;
3030 #ifndef DISABLE_PERFCOUNTERS
3031 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_thrown);
3032 #endif
3034 return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
3037 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3039 #ifndef MONO_ARCH_USE_SIGACTION
3040 #error "Can't use sigaltstack without sigaction"
3041 #endif
3043 void
3044 mono_setup_altstack (MonoJitTlsData *tls)
3046 size_t stsize = 0;
3047 stack_t sa;
3048 guint8 *staddr = NULL;
3049 #ifdef TARGET_OSX
3051 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3052 * stack pages. Stack overflow on main thread will kill the app.
3054 gboolean disable_stack_guard = mono_threads_platform_is_main_thread ();
3055 #else
3056 gboolean disable_stack_guard = FALSE;
3057 #endif
3059 if (mono_running_on_valgrind ())
3060 return;
3062 mono_thread_info_get_stack_bounds (&staddr, &stsize);
3064 g_assert (staddr);
3066 tls->end_of_stack = staddr + stsize;
3067 tls->stack_size = stsize;
3069 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3071 if (!disable_stack_guard) {
3072 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
3073 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
3075 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
3077 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
3078 /* mprotect can fail for the main thread stack */
3079 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);
3080 if (gaddr) {
3081 g_assert (gaddr == tls->stack_ovf_guard_base);
3082 tls->stack_ovf_valloced = TRUE;
3083 } else {
3084 g_warning ("couldn't allocate guard page, continue without it");
3085 tls->stack_ovf_guard_base = NULL;
3086 tls->stack_ovf_guard_size = 0;
3091 /* Setup an alternate signal stack */
3092 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);
3093 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3095 g_assert (tls->signal_stack);
3097 sa.ss_sp = tls->signal_stack;
3098 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3099 sa.ss_flags = 0;
3100 g_assert (sigaltstack (&sa, NULL) == 0);
3102 if (tls->stack_ovf_guard_base)
3103 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);
3104 else
3105 mono_gc_register_altstack (staddr, stsize, tls->signal_stack, tls->signal_stack_size);
3109 void
3110 mono_free_altstack (MonoJitTlsData *tls)
3112 stack_t sa;
3113 int err;
3115 sa.ss_sp = tls->signal_stack;
3116 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3117 sa.ss_flags = SS_DISABLE;
3118 err = sigaltstack (&sa, NULL);
3119 g_assert (err == 0);
3121 if (tls->signal_stack)
3122 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MEM_ACCOUNT_EXCEPTIONS);
3124 if (!tls->stack_ovf_guard_base)
3125 return;
3126 if (tls->stack_ovf_valloced)
3127 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MEM_ACCOUNT_EXCEPTIONS);
3128 else
3129 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3132 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3134 void
3135 mono_setup_altstack (MonoJitTlsData *tls)
3139 void
3140 mono_free_altstack (MonoJitTlsData *tls)
3144 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3146 gboolean
3147 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
3149 if (!jit_tls)
3150 return FALSE;
3152 if (mono_llvm_only)
3153 return FALSE;
3155 /* we got a stack overflow in the soft-guard pages
3156 * There are two cases:
3157 * 1) managed code caused the overflow: we unprotect the soft-guard page
3158 * and let the arch-specific code trigger the exception handling mechanism
3159 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3160 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3161 * and hope we can continue with those enabled, at least until the hard-guard page
3162 * is hit. The alternative to continuing here is to just print a message and abort.
3163 * We may add in the future the code to protect the pages again in the codepath
3164 * when we return from unmanaged to managed code.
3166 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
3167 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
3168 gboolean handled = FALSE;
3170 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3171 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3172 if (ji) {
3173 mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE);
3174 handled = TRUE;
3176 #endif
3177 if (!handled) {
3178 /* We print a message: after this even managed stack overflows
3179 * may crash the runtime
3181 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
3182 if (!jit_tls->handling_stack_ovf) {
3183 jit_tls->handling_stack_ovf = 1;
3184 } else {
3185 /*fprintf (stderr, "Already handling stack overflow\n");*/
3188 return TRUE;
3190 return FALSE;
3193 typedef struct {
3194 MonoMethod *omethod;
3195 int count;
3196 } PrintOverflowUserData;
3198 static gboolean
3199 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3201 MonoMethod *method = NULL;
3202 PrintOverflowUserData *user_data = (PrintOverflowUserData *)data;
3203 gchar *location;
3205 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3206 method = jinfo_get_method (frame->ji);
3208 if (method) {
3209 if (user_data->count == 0) {
3210 /* The first frame is in its prolog, so a line number cannot be computed */
3211 user_data->count ++;
3212 return FALSE;
3215 /* If this is a one method overflow, skip the other instances */
3216 if (method == user_data->omethod)
3217 return FALSE;
3219 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
3220 mono_runtime_printf_err (" %s", location);
3221 g_free (location);
3223 if (user_data->count == 1) {
3224 mono_runtime_printf_err (" <...>");
3225 user_data->omethod = method;
3226 } else {
3227 user_data->omethod = NULL;
3230 user_data->count ++;
3231 } else
3232 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame->native_offset);
3234 return FALSE;
3237 void
3238 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *mctx, guint8* fault_addr)
3240 PrintOverflowUserData ud;
3242 /* we don't do much now, but we can warn the user with a useful message */
3243 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx), fault_addr);
3245 mono_runtime_printf_err ("Stacktrace:");
3247 memset (&ud, 0, sizeof (ud));
3249 mono_walk_stack_with_ctx (print_overflow_stack_frame, mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
3251 _exit (1);
3254 static gboolean
3255 print_stack_frame_signal_safe (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3257 MonoMethod *method = NULL;
3259 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3260 method = jinfo_get_method (frame->ji);
3262 if (method) {
3263 const char *name_space = m_class_get_name_space (method->klass);
3264 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);
3265 } else {
3266 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame->native_offset);
3269 return FALSE;
3272 static G_GNUC_UNUSED gboolean
3273 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3275 GString *p = (GString*)data;
3276 MonoMethod *method = NULL;
3278 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3279 method = jinfo_get_method (frame->ji);
3281 if (method && frame->domain) {
3282 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3283 g_string_append_printf (p, " %s\n", location);
3284 g_free (location);
3285 } else
3286 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3288 return FALSE;
3291 #ifndef MONO_CROSS_COMPILE
3292 static gboolean handle_crash_loop = FALSE;
3295 * mono_handle_native_crash:
3297 * Handle a native crash (e.g. SIGSEGV) while in native code by
3298 * printing diagnostic information and aborting.
3300 void
3301 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3303 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3305 if (handle_crash_loop)
3306 return;
3308 if (mini_get_debug_options ()->suspend_on_native_crash) {
3309 g_async_safe_printf ("Received %s, suspending...\n", signal);
3310 while (1) {
3311 // Sleep for 1 second.
3312 g_usleep (1000 * 1000);
3316 /* prevent infinite loops in crash handling */
3317 handle_crash_loop = TRUE;
3320 * A SIGSEGV indicates something went very wrong so we can no longer depend
3321 * on anything working. So try to print out lots of diagnostics, starting
3322 * with ones which have a greater chance of working.
3325 g_async_safe_printf("\n=================================================================\n");
3326 g_async_safe_printf("\tNative Crash Reporting\n");
3327 g_async_safe_printf("=================================================================\n");
3328 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal);
3329 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3330 g_async_safe_printf("used by your application.\n");
3331 g_async_safe_printf("=================================================================\n");
3332 mono_dump_native_crash_info (signal, mctx, info);
3334 /* !jit_tls means the thread was not registered with the runtime */
3335 // This must be below the native crash dump, because we can't safely
3336 // do runtime state probing after we have walked the managed stack here.
3337 if (jit_tls && mono_thread_internal_current () && mctx) {
3338 g_async_safe_printf ("\n=================================================================\n");
3339 g_async_safe_printf ("\tManaged Stacktrace:\n");
3340 g_async_safe_printf ("=================================================================\n");
3342 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);
3343 g_async_safe_printf ("=================================================================\n");
3346 #ifdef MONO_ARCH_USE_SIGACTION
3347 struct sigaction sa;
3348 sa.sa_handler = SIG_DFL;
3349 sigemptyset (&sa.sa_mask);
3350 sa.sa_flags = 0;
3352 /* Remove our SIGABRT handler */
3353 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
3355 /* On some systems we get a SIGILL when calling abort (), because it might
3356 * fail to raise SIGABRT */
3357 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
3358 #endif
3360 mono_post_native_crash_handler (signal, mctx, info, mono_do_crash_chaining);
3363 #else
3365 void
3366 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3368 g_assert_not_reached ();
3371 #endif /* !MONO_CROSS_COMPILE */
3373 static void
3374 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
3376 MonoInternalThread *thread = mono_thread_internal_current ();
3377 MonoContext ctx;
3378 GString* text;
3379 char *name;
3380 GError *gerror = NULL;
3382 if (!thread)
3383 return;
3385 text = g_string_new (0);
3386 if (thread->name) {
3387 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &gerror);
3388 g_assert (!gerror);
3389 g_string_append_printf (text, "\n\"%s\"", name);
3390 g_free (name);
3392 else if (thread->threadpool_thread)
3393 g_string_append (text, "\n\"<threadpool thread>\"");
3394 else
3395 g_string_append (text, "\n\"<unnamed thread>\"");
3397 g_string_append_printf (text, " tid=%p this=%p ", (gpointer)(gsize)thread->tid, thread);
3398 mono_thread_internal_describe (thread, text);
3399 g_string_append (text, "\n");
3401 if (start_ctx) {
3402 memcpy (&ctx, start_ctx, sizeof (MonoContext));
3403 } else if (!sigctx)
3404 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
3405 else
3406 mono_sigctx_to_monoctx (sigctx, &ctx);
3408 mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
3410 mono_runtime_printf ("%s", text->str);
3412 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3413 OutputDebugStringA(text->str);
3414 #endif
3416 g_string_free (text, TRUE);
3417 mono_runtime_stdout_fflush ();
3421 * mono_print_thread_dump:
3423 * Print information about the current thread to stdout.
3424 * \p sigctx can be NULL, allowing this to be called from gdb.
3426 void
3427 mono_print_thread_dump (void *sigctx)
3429 mono_print_thread_dump_internal (sigctx, NULL);
3432 void
3433 mono_print_thread_dump_from_ctx (MonoContext *ctx)
3435 mono_print_thread_dump_internal (NULL, ctx);
3439 * mono_resume_unwind:
3441 * This is called by a trampoline from LLVM compiled finally clauses to continue
3442 * unwinding.
3444 void
3445 mono_resume_unwind (MonoContext *ctx)
3447 MONO_REQ_GC_UNSAFE_MODE;
3449 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3450 MonoContext new_ctx;
3452 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
3453 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
3454 new_ctx = *ctx;
3456 mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL);
3458 mono_restore_context (&new_ctx);
3461 typedef struct {
3462 MonoJitInfo *ji;
3463 MonoContext ctx;
3464 MonoJitExceptionInfo *ei;
3465 } FindHandlerBlockData;
3467 static gboolean
3468 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3470 int i;
3471 gpointer ip;
3472 FindHandlerBlockData *pdata = (FindHandlerBlockData *)data;
3473 MonoJitInfo *ji = frame->ji;
3475 if (!ji)
3476 return FALSE;
3478 ip = MONO_CONTEXT_GET_IP (ctx);
3480 for (i = 0; i < ji->num_clauses; ++i) {
3481 MonoJitExceptionInfo *ei = ji->clauses + i;
3482 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3483 continue;
3484 /*If ip points to the first instruction it means the handler block didn't start
3485 so we can leave its execution to the EH machinery*/
3486 if (ei->handler_start <= ip && ip < ei->data.handler_end) {
3487 pdata->ji = ji;
3488 pdata->ei = ei;
3489 pdata->ctx = *ctx;
3490 break;
3493 return FALSE;
3497 static void
3498 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
3500 int i;
3501 MonoJitExceptionInfo *clause = NULL;
3502 gpointer ip;
3503 guint8 *bp;
3505 ip = MONO_CONTEXT_GET_IP (ctx);
3507 for (i = 0; i < ji->num_clauses; ++i) {
3508 clause = &ji->clauses [i];
3509 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3510 continue;
3511 if (clause->handler_start <= ip && clause->data.handler_end > ip)
3512 break;
3515 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3516 g_assert (i < ji->num_clauses);
3518 /*Load the spvar*/
3519 bp = (guint8*)MONO_CONTEXT_GET_BP (ctx);
3520 *(bp + clause->exvar_offset) = 1;
3524 * Finds the bottom handler block running and install a block guard if needed.
3526 static gboolean
3527 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
3529 FindHandlerBlockData data = { 0 };
3530 MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
3532 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3533 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3535 if (!jit_tls || jit_tls->handler_block)
3536 return FALSE;
3538 /* Do an async safe stack walk */
3539 mono_thread_info_set_is_async_context (TRUE);
3540 mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data);
3541 mono_thread_info_set_is_async_context (FALSE);
3543 if (!data.ji)
3544 return FALSE;
3546 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
3548 install_handler_block_guard (data.ji, &data.ctx);
3550 jit_tls->handler_block = data.ei;
3552 return TRUE;
3555 static void
3556 mono_uninstall_current_handler_block_guard (void)
3558 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3559 if (jit_tls)
3560 jit_tls->handler_block = NULL;
3564 static gboolean
3565 mono_current_thread_has_handle_block_guard (void)
3567 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3568 return jit_tls && jit_tls->handler_block != NULL;
3571 void
3572 mono_set_cast_details (MonoClass *from, MonoClass *to)
3574 MonoJitTlsData *jit_tls = NULL;
3576 if (mini_get_debug_options ()->better_cast_details) {
3577 jit_tls = mono_tls_get_jit_tls ();
3578 jit_tls->class_cast_from = from;
3579 jit_tls->class_cast_to = to;
3584 /*returns false if the thread is not attached*/
3585 gboolean
3586 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
3588 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3589 if (!thread) {
3590 ctx->valid = FALSE;
3591 return FALSE;
3594 if (sigctx) {
3595 mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
3597 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3598 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3599 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3601 else {
3602 mono_thread_state_init (ctx);
3605 if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
3606 return FALSE;
3608 ctx->valid = TRUE;
3609 return TRUE;
3612 void
3613 mono_thread_state_init (MonoThreadUnwindState *ctx)
3615 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3617 #if defined(MONO_CROSS_COMPILE)
3618 ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
3619 #elif MONO_ARCH_HAS_MONO_CONTEXT
3620 MONO_CONTEXT_GET_CURRENT (ctx->ctx);
3621 #else
3622 g_error ("Use a null sigctx requires a working mono-context");
3623 #endif
3625 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3626 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3627 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
3628 ctx->valid = TRUE;
3632 gboolean
3633 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
3635 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3636 if (!thread) {
3637 ctx->valid = FALSE;
3638 return FALSE;
3641 ctx->ctx = *mctx;
3642 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3643 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3644 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3645 ctx->valid = TRUE;
3646 return TRUE;
3649 /*returns false if the thread is not attached*/
3650 gboolean
3651 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
3653 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3654 MONO_ARCH_CONTEXT_DEF
3656 mono_arch_flush_register_windows ();
3658 if (!thread || !thread->jit_data) {
3659 ctx->valid = FALSE;
3660 return FALSE;
3662 MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
3664 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3665 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3666 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3667 ctx->valid = TRUE;
3668 return TRUE;
3671 static void
3672 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
3674 mono_handle_exception (ctx, (MonoObject *)exc);
3675 mono_restore_context (ctx);
3678 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3679 void
3680 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
3682 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3683 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3684 jit_tls->ex_ctx = *ctx;
3686 mono_arch_setup_async_callback (ctx, async_cb, user_data);
3687 #else
3688 g_error ("This target doesn't support mono_arch_setup_async_callback");
3689 #endif
3693 * mono_restore_context:
3695 * Call the architecture specific restore context function.
3697 void
3698 mono_restore_context (MonoContext *ctx)
3700 static void (*restore_context) (MonoContext *);
3702 if (!restore_context)
3703 restore_context = (void (*)(MonoContext *))mono_get_restore_context ();
3704 restore_context (ctx);
3705 g_assert_not_reached ();
3709 * mono_jinfo_get_unwind_info:
3711 * Return the unwind info for JI.
3713 guint8*
3714 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
3716 if (ji->has_unwind_info) {
3717 /* The address/length in the MonoJitInfo structure itself */
3718 MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji);
3719 *unwind_info_len = info->unw_info_len;
3720 return info->unw_info;
3721 } else if (ji->from_aot)
3722 return mono_aot_get_unwind_info (ji, unwind_info_len);
3723 else
3724 return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
3728 mono_jinfo_get_epilog_size (MonoJitInfo *ji)
3730 MonoArchEHJitInfo *info;
3732 info = mono_jit_info_get_arch_eh_info (ji);
3733 g_assert (info);
3735 return info->epilog_size;
3739 * mono_install_ftnptr_eh_callback:
3741 * Install a callback that should be called when there is a managed exception
3742 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3743 * managed exception to a native exception, to properly unwind the native
3744 * stack; this native exception will then be converted back to a managed
3745 * exception in their managed-to-native wrapper.
3747 void
3748 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
3750 ftnptr_eh_callback = callback;
3754 * LLVM/Bitcode exception handling.
3757 static void
3758 throw_exception (MonoObject *ex, gboolean rethrow)
3760 MONO_REQ_GC_UNSAFE_MODE;
3762 ERROR_DECL (error);
3763 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3764 MonoException *mono_ex;
3766 if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, error)) {
3767 mono_error_assert_ok (error);
3768 mono_ex = mono_get_exception_runtime_wrapped_checked (ex, error);
3769 mono_error_assert_ok (error);
3770 jit_tls->thrown_non_exc = mono_gchandle_new_internal (ex, FALSE);
3772 else
3773 mono_ex = (MonoException*)ex;
3775 // Note: Not pinned
3776 jit_tls->thrown_exc = mono_gchandle_new_internal ((MonoObject*)mono_ex, FALSE);
3778 if (!rethrow) {
3779 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3780 GList *l, *ips = NULL;
3781 GList *trace;
3783 _Unwind_Backtrace (build_stack_trace, &ips);
3784 /* The list contains ip-gshared info pairs */
3785 trace = NULL;
3786 ips = g_list_reverse (ips);
3787 for (l = ips; l; l = l->next) {
3788 trace = g_list_append (trace, l->data);
3789 trace = g_list_append (trace, NULL);
3790 trace = g_list_append (trace, NULL);
3792 MonoArray *ips_arr = mono_glist_to_array (trace, mono_defaults.int_class, error);
3793 mono_error_assert_ok (error);
3794 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3795 g_list_free (l);
3796 g_list_free (trace);
3797 #endif
3800 mono_llvm_cpp_throw_exception ();
3803 void
3804 mono_llvm_throw_exception (MonoObject *ex)
3806 throw_exception (ex, FALSE);
3809 void
3810 mono_llvm_rethrow_exception (MonoObject *ex)
3812 throw_exception (ex, TRUE);
3815 void
3816 mono_llvm_raise_exception (MonoException *e)
3818 mono_llvm_throw_exception ((MonoObject*)e);
3821 void
3822 mono_llvm_reraise_exception (MonoException *e)
3824 mono_llvm_rethrow_exception ((MonoObject*)e);
3827 void
3828 mono_llvm_throw_corlib_exception (guint32 ex_token_index)
3830 guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
3831 MonoException *ex;
3833 ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token);
3835 mono_llvm_throw_exception ((MonoObject*)ex);
3839 * mono_llvm_resume_exception:
3841 * Resume exception propagation.
3843 void
3844 mono_llvm_resume_exception (void)
3846 mono_llvm_cpp_throw_exception ();
3850 * mono_llvm_load_exception:
3852 * Return the currently thrown exception.
3854 MonoObject *
3855 mono_llvm_load_exception (void)
3857 ERROR_DECL (error);
3858 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3860 MonoException *mono_ex = (MonoException*)mono_gchandle_get_target_internal (jit_tls->thrown_exc);
3862 MonoArray *ta = mono_ex->trace_ips;
3864 if (ta) {
3865 GList *trace_ips = NULL;
3866 gpointer ip = MONO_RETURN_ADDRESS ();
3868 size_t upper = mono_array_length_internal (ta);
3870 for (int i = 0; i < upper; i += TRACE_IP_ENTRY_SIZE) {
3871 gpointer curr_ip = mono_array_get_internal (ta, gpointer, i);
3872 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
3873 gpointer p = mono_array_get_internal (ta, gpointer, i + j);
3874 trace_ips = g_list_append (trace_ips, p);
3876 if (ip == curr_ip)
3877 break;
3880 // FIXME: Does this work correctly for rethrows?
3881 // We may be discarding useful information
3882 // when this gets GC'ed
3883 MonoArray *ips_arr = mono_glist_to_array (trace_ips, mono_defaults.int_class, error);
3884 mono_error_assert_ok (error);
3885 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3886 g_list_free (trace_ips);
3888 // FIXME:
3889 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3890 } else {
3891 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, 0, error));
3892 mono_error_assert_ok (error);
3893 MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, mono_array_new_checked (mono_domain_get (), mono_defaults.stack_frame_class, 0, error));
3894 mono_error_assert_ok (error);
3897 return &mono_ex->object;
3901 * mono_llvm_clear_exception:
3903 * Mark the currently thrown exception as handled.
3905 void
3906 mono_llvm_clear_exception (void)
3908 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3909 mono_gchandle_free_internal (jit_tls->thrown_exc);
3910 jit_tls->thrown_exc = 0;
3911 if (jit_tls->thrown_non_exc)
3912 mono_gchandle_free_internal (jit_tls->thrown_non_exc);
3913 jit_tls->thrown_non_exc = 0;
3915 mono_memory_barrier ();
3919 * mono_llvm_match_exception:
3921 * Return the innermost clause containing REGION_START-REGION_END which can handle
3922 * the current exception.
3924 gint32
3925 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
3927 ERROR_DECL (error);
3928 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3929 MonoObject *exc;
3930 gint32 index = -1;
3932 g_assert (jit_tls->thrown_exc);
3933 exc = mono_gchandle_get_target_internal (jit_tls->thrown_exc);
3934 if (jit_tls->thrown_non_exc) {
3936 * Have to unwrap RuntimeWrappedExceptions if the
3937 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
3939 if (!wrap_non_exception_throws (jinfo_get_method (jinfo)))
3940 exc = mono_gchandle_get_target_internal (jit_tls->thrown_non_exc);
3943 for (int i = 0; i < jinfo->num_clauses; i++) {
3944 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
3945 MonoClass *catch_class;
3947 if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
3948 continue;
3950 catch_class = ei->data.catch_class;
3951 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class))) {
3952 MonoGenericContext context;
3953 MonoType *inflated_type;
3955 g_assert (rgctx || this_obj);
3956 context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
3957 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
3958 mono_error_assert_ok (error); /* FIXME don't swallow the error */
3960 catch_class = mono_class_from_mono_type_internal (inflated_type);
3961 mono_metadata_free_type (inflated_type);
3964 // FIXME: Handle edge cases handled in get_exception_catch_class
3965 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, error)) {
3966 index = ei->clause_index;
3967 break;
3968 } else
3969 mono_error_assert_ok (error);
3971 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3972 g_assert_not_reached ();
3976 return index;
3979 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
3980 G_EXTERN_C _Unwind_Reason_Code mono_debug_personality (int a, _Unwind_Action b,
3981 uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
3983 g_assert_not_reached ();
3985 #else
3986 G_EXTERN_C void mono_debug_personality (void);
3988 void
3989 mono_debug_personality (void)
3991 g_assert_not_reached ();
3993 #endif