Factor copy/pasted code into mono_gstring_append_thread_name. (#15920)
[mono-project.git] / mono / mini / mini-exceptions.c
blob9c51fe9e057764a2c474409e541765e47c9af7bf
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 - skip, sf);
1147 return res;
1150 static void
1151 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1153 if (!start_ctx) {
1154 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1155 if (jit_tls && jit_tls->orig_ex_ctx_set)
1156 start_ctx = &jit_tls->orig_ex_ctx;
1158 mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
1161 * mono_walk_stack_with_ctx:
1162 * Unwind the current thread starting at \p start_ctx.
1163 * If \p start_ctx is null, we capture the current context.
1165 void
1166 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1168 MonoContext extra_ctx;
1169 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1170 MONO_ARCH_CONTEXT_DEF
1172 if (!thread || !thread->jit_data)
1173 return;
1175 if (!start_ctx) {
1176 mono_arch_flush_register_windows ();
1177 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
1178 start_ctx = &extra_ctx;
1181 mono_walk_stack_full (func, start_ctx, mono_domain_get (), thread->jit_data, mono_get_lmf (), unwind_options, user_data, FALSE);
1185 * mono_walk_stack_with_state:
1186 * Unwind a thread described by \p state.
1188 * State must be valid (state->valid == TRUE).
1190 * If you are using this function to unwind another thread, make sure it is suspended.
1192 * If \p state is null, we capture the current context.
1194 void
1195 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
1197 MonoThreadUnwindState extra_state;
1198 if (!state) {
1199 g_assert (!mono_thread_info_is_async_context ());
1200 if (!mono_thread_state_init_from_current (&extra_state))
1201 return;
1202 state = &extra_state;
1205 g_assert (state->valid);
1207 if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
1208 /* Not attached */
1209 return;
1211 mono_walk_stack_full (func,
1212 &state->ctx,
1213 (MonoDomain *)state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
1214 (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
1215 (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF],
1216 unwind_options, user_data, FALSE);
1219 void
1220 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
1222 MonoThreadUnwindState state;
1223 if (!mono_thread_state_init_from_current (&state))
1224 return;
1225 mono_walk_stack_with_state (func, &state, options, user_data);
1229 * mono_walk_stack_full:
1230 * \param func callback to call for each stack frame
1231 * \param domain starting appdomain, can be NULL to use the current domain
1232 * \param unwind_options what extra information the unwinder should gather
1233 * \param start_ctx starting state of the stack walk, can be NULL.
1234 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1235 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1236 * \param user_data data passed to the callback
1237 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1238 * This function walks the stack of a thread, starting from the state
1239 * represented by \p start_ctx. For each frame the callback
1240 * function is called with the relevant info. The walk ends when no more
1241 * managed stack frames are found or when the callback returns a TRUE value.
1243 static void
1244 mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data, gboolean crash_context)
1246 gint il_offset;
1247 MonoContext ctx, new_ctx;
1248 StackFrameInfo frame;
1249 gboolean res;
1250 host_mgreg_t *reg_locations [MONO_MAX_IREGS];
1251 host_mgreg_t *new_reg_locations [MONO_MAX_IREGS];
1252 gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
1253 gboolean async = mono_thread_info_is_async_context ();
1254 Unwinder unwinder;
1256 memset (&frame, 0, sizeof (StackFrameInfo));
1258 #ifndef TARGET_WASM
1259 if (mono_llvm_only) {
1260 GSList *l, *ips;
1262 if (async)
1263 return;
1265 ips = get_unwind_backtrace ();
1266 for (l = ips; l; l = l->next) {
1267 guint8 *ip = (guint8*)l->data;
1268 memset (&frame, 0, sizeof (StackFrameInfo));
1269 frame.ji = mini_jit_info_table_find (domain, ip, &frame.domain);
1270 if (!frame.ji || frame.ji->is_trampoline)
1271 continue;
1272 frame.type = FRAME_TYPE_MANAGED;
1273 frame.method = jinfo_get_method (frame.ji);
1274 // FIXME: Cannot lookup the actual method
1275 frame.actual_method = frame.method;
1276 if (frame.type == FRAME_TYPE_MANAGED) {
1277 if (!frame.method->wrapper_type || frame.method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
1278 frame.managed = TRUE;
1280 frame.native_offset = ip - (guint8*)frame.ji->code_start;
1281 frame.il_offset = -1;
1283 if (func (&frame, NULL, user_data))
1284 break;
1286 g_slist_free (ips);
1287 return;
1289 #endif
1291 if (!start_ctx) {
1292 g_warning ("start_ctx required for stack walk");
1293 return;
1296 if (!domain) {
1297 g_warning ("domain required for stack walk");
1298 return;
1301 if (!jit_tls) {
1302 g_warning ("jit_tls required for stack walk");
1303 return;
1306 /*The LMF will be null if the target have no managed frames.*/
1307 /* g_assert (lmf); */
1308 if (async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD)) {
1309 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1310 return;
1313 memcpy (&ctx, start_ctx, sizeof (MonoContext));
1314 memset (reg_locations, 0, sizeof (reg_locations));
1316 unwinder_init (&unwinder);
1318 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
1319 frame.lmf = lmf;
1320 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
1321 if (!res)
1322 return;
1324 if (frame.type == FRAME_TYPE_TRAMPOLINE)
1325 goto next;
1327 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) {
1328 MonoDebugSourceLocation *source = NULL;
1330 // Don't do this when we can be in a signal handler
1331 if (!crash_context)
1332 source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
1333 if (source) {
1334 il_offset = source->il_offset;
1335 } else {
1336 MonoSeqPointInfo *seq_points = NULL;
1338 // It's more reliable to look into the global cache if possible
1339 if (crash_context)
1340 seq_points = (MonoSeqPointInfo *) frame.ji->seq_points;
1341 else
1342 seq_points = mono_get_seq_points (domain, jinfo_get_method (frame.ji));
1344 SeqPoint sp;
1345 if (seq_points && mono_seq_point_find_prev_by_native_offset (seq_points, frame.native_offset, &sp))
1346 il_offset = sp.il_offset;
1347 else
1348 il_offset = -1;
1350 mono_debug_free_source_location (source);
1351 } else
1352 il_offset = -1;
1354 frame.il_offset = il_offset;
1356 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) {
1357 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
1358 } else {
1359 frame.actual_method = frame.method;
1362 if (get_reg_locations)
1363 frame.reg_locations = reg_locations;
1365 if (func (&frame, &ctx, user_data))
1366 return;
1368 next:
1369 if (get_reg_locations) {
1370 for (int i = 0; i < MONO_MAX_IREGS; ++i)
1371 if (new_reg_locations [i])
1372 reg_locations [i] = new_reg_locations [i];
1375 ctx = new_ctx;
1379 #ifdef DISABLE_CRASH_REPORTING
1381 static void
1382 mono_summarize_managed_stack (MonoThreadSummary *out)
1384 return;
1387 static void
1388 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1390 return;
1393 static void
1394 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1396 return;
1399 static void
1400 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1402 return;
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_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_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_debug_options.break_on_exc)
2641 G_BREAKPOINT ();
2642 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2644 if (mini_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 #if defined(TARGET_OSX) || defined(_AIX)
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 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3055 * do this for thread 1 with its stack at the top of memory. Other threads seem
3056 * fine for the altstack guard page, though.
3058 gboolean disable_stack_guard = mono_threads_platform_is_main_thread ();
3059 #else
3060 gboolean disable_stack_guard = FALSE;
3061 #endif
3063 if (mono_running_on_valgrind ())
3064 return;
3066 mono_thread_info_get_stack_bounds (&staddr, &stsize);
3068 g_assert (staddr);
3070 tls->end_of_stack = staddr + stsize;
3071 tls->stack_size = stsize;
3073 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3075 if (!disable_stack_guard) {
3076 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
3077 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
3079 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
3081 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
3082 /* mprotect can fail for the main thread stack */
3083 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);
3084 if (gaddr) {
3085 g_assert (gaddr == tls->stack_ovf_guard_base);
3086 tls->stack_ovf_valloced = TRUE;
3087 } else {
3088 g_warning ("couldn't allocate guard page, continue without it");
3089 tls->stack_ovf_guard_base = NULL;
3090 tls->stack_ovf_guard_size = 0;
3095 /* Setup an alternate signal stack */
3096 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);
3097 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3099 g_assert (tls->signal_stack);
3101 sa.ss_sp = tls->signal_stack;
3102 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3103 sa.ss_flags = 0;
3104 g_assert (sigaltstack (&sa, NULL) == 0);
3106 if (tls->stack_ovf_guard_base)
3107 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);
3108 else
3109 mono_gc_register_altstack (staddr, stsize, tls->signal_stack, tls->signal_stack_size);
3113 void
3114 mono_free_altstack (MonoJitTlsData *tls)
3116 stack_t sa;
3117 int err;
3119 sa.ss_sp = tls->signal_stack;
3120 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3121 sa.ss_flags = SS_DISABLE;
3122 err = sigaltstack (&sa, NULL);
3123 g_assert (err == 0);
3125 if (tls->signal_stack)
3126 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MEM_ACCOUNT_EXCEPTIONS);
3128 if (!tls->stack_ovf_guard_base)
3129 return;
3130 if (tls->stack_ovf_valloced)
3131 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MEM_ACCOUNT_EXCEPTIONS);
3132 else
3133 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3136 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3138 void
3139 mono_setup_altstack (MonoJitTlsData *tls)
3143 void
3144 mono_free_altstack (MonoJitTlsData *tls)
3148 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3150 gboolean
3151 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
3153 if (!jit_tls)
3154 return FALSE;
3156 if (mono_llvm_only)
3157 return FALSE;
3159 /* we got a stack overflow in the soft-guard pages
3160 * There are two cases:
3161 * 1) managed code caused the overflow: we unprotect the soft-guard page
3162 * and let the arch-specific code trigger the exception handling mechanism
3163 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3164 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3165 * and hope we can continue with those enabled, at least until the hard-guard page
3166 * is hit. The alternative to continuing here is to just print a message and abort.
3167 * We may add in the future the code to protect the pages again in the codepath
3168 * when we return from unmanaged to managed code.
3170 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
3171 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
3172 gboolean handled = FALSE;
3174 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3175 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3176 if (ji) {
3177 mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE);
3178 handled = TRUE;
3180 #endif
3181 if (!handled) {
3182 /* We print a message: after this even managed stack overflows
3183 * may crash the runtime
3185 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
3186 if (!jit_tls->handling_stack_ovf) {
3187 jit_tls->handling_stack_ovf = 1;
3188 } else {
3189 /*fprintf (stderr, "Already handling stack overflow\n");*/
3192 return TRUE;
3194 return FALSE;
3197 typedef struct {
3198 MonoMethod *omethod;
3199 int count;
3200 } PrintOverflowUserData;
3202 static gboolean
3203 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3205 MonoMethod *method = NULL;
3206 PrintOverflowUserData *user_data = (PrintOverflowUserData *)data;
3207 gchar *location;
3209 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3210 method = jinfo_get_method (frame->ji);
3212 if (method) {
3213 if (user_data->count == 0) {
3214 /* The first frame is in its prolog, so a line number cannot be computed */
3215 user_data->count ++;
3216 return FALSE;
3219 /* If this is a one method overflow, skip the other instances */
3220 if (method == user_data->omethod)
3221 return FALSE;
3223 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
3224 mono_runtime_printf_err (" %s", location);
3225 g_free (location);
3227 if (user_data->count == 1) {
3228 mono_runtime_printf_err (" <...>");
3229 user_data->omethod = method;
3230 } else {
3231 user_data->omethod = NULL;
3234 user_data->count ++;
3235 } else
3236 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame->native_offset);
3238 return FALSE;
3241 void
3242 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *mctx, guint8* fault_addr)
3244 PrintOverflowUserData ud;
3246 /* we don't do much now, but we can warn the user with a useful message */
3247 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx), fault_addr);
3249 mono_runtime_printf_err ("Stacktrace:");
3251 memset (&ud, 0, sizeof (ud));
3253 mono_walk_stack_with_ctx (print_overflow_stack_frame, mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
3255 _exit (1);
3258 static gboolean
3259 print_stack_frame_signal_safe (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3261 MonoMethod *method = NULL;
3263 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3264 method = jinfo_get_method (frame->ji);
3266 if (method) {
3267 const char *name_space = m_class_get_name_space (method->klass);
3268 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);
3269 } else {
3270 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame->native_offset);
3273 return FALSE;
3276 static G_GNUC_UNUSED gboolean
3277 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3279 GString *p = (GString*)data;
3280 MonoMethod *method = NULL;
3282 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3283 method = jinfo_get_method (frame->ji);
3285 if (method && frame->domain) {
3286 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3287 g_string_append_printf (p, " %s\n", location);
3288 g_free (location);
3289 } else
3290 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3292 return FALSE;
3295 #ifndef MONO_CROSS_COMPILE
3296 static gboolean handle_crash_loop = FALSE;
3299 * mono_handle_native_crash:
3301 * Handle a native crash (e.g. SIGSEGV) while in native code by
3302 * printing diagnostic information and aborting.
3304 void
3305 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3307 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3309 if (handle_crash_loop)
3310 return;
3312 if (mini_debug_options.suspend_on_native_crash) {
3313 g_async_safe_printf ("Received %s, suspending...\n", signal);
3314 while (1) {
3315 // Sleep for 1 second.
3316 g_usleep (1000 * 1000);
3320 /* prevent infinite loops in crash handling */
3321 handle_crash_loop = TRUE;
3324 * A SIGSEGV indicates something went very wrong so we can no longer depend
3325 * on anything working. So try to print out lots of diagnostics, starting
3326 * with ones which have a greater chance of working.
3329 g_async_safe_printf("\n=================================================================\n");
3330 g_async_safe_printf("\tNative Crash Reporting\n");
3331 g_async_safe_printf("=================================================================\n");
3332 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal);
3333 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3334 g_async_safe_printf("used by your application.\n");
3335 g_async_safe_printf("=================================================================\n");
3336 mono_dump_native_crash_info (signal, mctx, info);
3338 /* !jit_tls means the thread was not registered with the runtime */
3339 // This must be below the native crash dump, because we can't safely
3340 // do runtime state probing after we have walked the managed stack here.
3341 if (jit_tls && mono_thread_internal_current () && mctx) {
3342 g_async_safe_printf ("\n=================================================================\n");
3343 g_async_safe_printf ("\tManaged Stacktrace:\n");
3344 g_async_safe_printf ("=================================================================\n");
3346 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);
3347 g_async_safe_printf ("=================================================================\n");
3350 #ifdef MONO_ARCH_USE_SIGACTION
3351 struct sigaction sa;
3352 sa.sa_handler = SIG_DFL;
3353 sigemptyset (&sa.sa_mask);
3354 sa.sa_flags = 0;
3356 /* Remove our SIGABRT handler */
3357 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
3359 /* On some systems we get a SIGILL when calling abort (), because it might
3360 * fail to raise SIGABRT */
3361 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
3362 #endif
3364 mono_post_native_crash_handler (signal, mctx, info, mono_do_crash_chaining);
3367 #else
3369 void
3370 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3372 g_assert_not_reached ();
3375 #endif /* !MONO_CROSS_COMPILE */
3377 static void
3378 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
3380 MonoInternalThread *thread = mono_thread_internal_current ();
3381 MonoContext ctx;
3382 GString* text;
3383 char *name;
3384 GError *gerror = NULL;
3386 if (!thread)
3387 return;
3389 text = g_string_new (0);
3391 mono_gstring_append_thread_name (text, thread);
3393 g_string_append_printf (text, " tid=%p this=%p ", (gpointer)(gsize)thread->tid, thread);
3394 mono_thread_internal_describe (thread, text);
3395 g_string_append (text, "\n");
3397 if (start_ctx) {
3398 memcpy (&ctx, start_ctx, sizeof (MonoContext));
3399 } else if (!sigctx)
3400 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
3401 else
3402 mono_sigctx_to_monoctx (sigctx, &ctx);
3404 mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
3406 mono_runtime_printf ("%s", text->str);
3408 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3409 OutputDebugStringA(text->str);
3410 #endif
3412 g_string_free (text, TRUE);
3413 mono_runtime_stdout_fflush ();
3417 * mono_print_thread_dump:
3419 * Print information about the current thread to stdout.
3420 * \p sigctx can be NULL, allowing this to be called from gdb.
3422 void
3423 mono_print_thread_dump (void *sigctx)
3425 mono_print_thread_dump_internal (sigctx, NULL);
3428 void
3429 mono_print_thread_dump_from_ctx (MonoContext *ctx)
3431 mono_print_thread_dump_internal (NULL, ctx);
3435 * mono_resume_unwind:
3437 * This is called by a trampoline from LLVM compiled finally clauses to continue
3438 * unwinding.
3440 void
3441 mono_resume_unwind (MonoContext *ctx)
3443 MONO_REQ_GC_UNSAFE_MODE;
3445 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3446 MonoContext new_ctx;
3448 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
3449 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
3450 new_ctx = *ctx;
3452 mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL);
3454 mono_restore_context (&new_ctx);
3457 typedef struct {
3458 MonoJitInfo *ji;
3459 MonoContext ctx;
3460 MonoJitExceptionInfo *ei;
3461 } FindHandlerBlockData;
3463 static gboolean
3464 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3466 int i;
3467 gpointer ip;
3468 FindHandlerBlockData *pdata = (FindHandlerBlockData *)data;
3469 MonoJitInfo *ji = frame->ji;
3471 if (!ji)
3472 return FALSE;
3474 ip = MONO_CONTEXT_GET_IP (ctx);
3476 for (i = 0; i < ji->num_clauses; ++i) {
3477 MonoJitExceptionInfo *ei = ji->clauses + i;
3478 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3479 continue;
3480 /*If ip points to the first instruction it means the handler block didn't start
3481 so we can leave its execution to the EH machinery*/
3482 if (ei->handler_start <= ip && ip < ei->data.handler_end) {
3483 pdata->ji = ji;
3484 pdata->ei = ei;
3485 pdata->ctx = *ctx;
3486 break;
3489 return FALSE;
3493 static void
3494 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
3496 int i;
3497 MonoJitExceptionInfo *clause = NULL;
3498 gpointer ip;
3499 guint8 *bp;
3501 ip = MONO_CONTEXT_GET_IP (ctx);
3503 for (i = 0; i < ji->num_clauses; ++i) {
3504 clause = &ji->clauses [i];
3505 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3506 continue;
3507 if (clause->handler_start <= ip && clause->data.handler_end > ip)
3508 break;
3511 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3512 g_assert (i < ji->num_clauses);
3514 /*Load the spvar*/
3515 bp = (guint8*)MONO_CONTEXT_GET_BP (ctx);
3516 *(bp + clause->exvar_offset) = 1;
3520 * Finds the bottom handler block running and install a block guard if needed.
3522 static gboolean
3523 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
3525 FindHandlerBlockData data = { 0 };
3526 MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
3528 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3529 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3531 if (!jit_tls || jit_tls->handler_block)
3532 return FALSE;
3534 /* Do an async safe stack walk */
3535 mono_thread_info_set_is_async_context (TRUE);
3536 mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data);
3537 mono_thread_info_set_is_async_context (FALSE);
3539 if (!data.ji)
3540 return FALSE;
3542 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
3544 install_handler_block_guard (data.ji, &data.ctx);
3546 jit_tls->handler_block = data.ei;
3548 return TRUE;
3551 static void
3552 mono_uninstall_current_handler_block_guard (void)
3554 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3555 if (jit_tls)
3556 jit_tls->handler_block = NULL;
3560 static gboolean
3561 mono_current_thread_has_handle_block_guard (void)
3563 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3564 return jit_tls && jit_tls->handler_block != NULL;
3567 void
3568 mono_set_cast_details (MonoClass *from, MonoClass *to)
3570 MonoJitTlsData *jit_tls = NULL;
3572 if (mini_debug_options.better_cast_details) {
3573 jit_tls = mono_tls_get_jit_tls ();
3574 jit_tls->class_cast_from = from;
3575 jit_tls->class_cast_to = to;
3580 /*returns false if the thread is not attached*/
3581 gboolean
3582 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
3584 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3585 if (!thread) {
3586 ctx->valid = FALSE;
3587 return FALSE;
3590 if (sigctx) {
3591 mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
3593 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3594 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3595 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3597 else {
3598 mono_thread_state_init (ctx);
3601 if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
3602 return FALSE;
3604 ctx->valid = TRUE;
3605 return TRUE;
3608 void
3609 mono_thread_state_init (MonoThreadUnwindState *ctx)
3611 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3613 #if defined(MONO_CROSS_COMPILE)
3614 ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
3615 #elif MONO_ARCH_HAS_MONO_CONTEXT
3616 MONO_CONTEXT_GET_CURRENT (ctx->ctx);
3617 #else
3618 g_error ("Use a null sigctx requires a working mono-context");
3619 #endif
3621 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3622 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3623 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
3624 ctx->valid = TRUE;
3628 gboolean
3629 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
3631 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3632 if (!thread) {
3633 ctx->valid = FALSE;
3634 return FALSE;
3637 ctx->ctx = *mctx;
3638 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3639 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3640 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3641 ctx->valid = TRUE;
3642 return TRUE;
3645 /*returns false if the thread is not attached*/
3646 gboolean
3647 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
3649 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3650 MONO_ARCH_CONTEXT_DEF
3652 mono_arch_flush_register_windows ();
3654 if (!thread || !thread->jit_data) {
3655 ctx->valid = FALSE;
3656 return FALSE;
3658 MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
3660 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3661 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3662 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3663 ctx->valid = TRUE;
3664 return TRUE;
3667 static void
3668 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
3670 mono_handle_exception (ctx, (MonoObject *)exc);
3671 mono_restore_context (ctx);
3674 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3675 void
3676 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
3678 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3679 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3680 jit_tls->ex_ctx = *ctx;
3682 mono_arch_setup_async_callback (ctx, async_cb, user_data);
3683 #else
3684 g_error ("This target doesn't support mono_arch_setup_async_callback");
3685 #endif
3689 * mono_restore_context:
3691 * Call the architecture specific restore context function.
3693 void
3694 mono_restore_context (MonoContext *ctx)
3696 static void (*restore_context) (MonoContext *);
3698 if (!restore_context)
3699 restore_context = (void (*)(MonoContext *))mono_get_restore_context ();
3700 restore_context (ctx);
3701 g_assert_not_reached ();
3705 * mono_jinfo_get_unwind_info:
3707 * Return the unwind info for JI.
3709 guint8*
3710 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
3712 if (ji->has_unwind_info) {
3713 /* The address/length in the MonoJitInfo structure itself */
3714 MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji);
3715 *unwind_info_len = info->unw_info_len;
3716 return info->unw_info;
3717 } else if (ji->from_aot)
3718 return mono_aot_get_unwind_info (ji, unwind_info_len);
3719 else
3720 return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
3724 mono_jinfo_get_epilog_size (MonoJitInfo *ji)
3726 MonoArchEHJitInfo *info;
3728 info = mono_jit_info_get_arch_eh_info (ji);
3729 g_assert (info);
3731 return info->epilog_size;
3735 * mono_install_ftnptr_eh_callback:
3737 * Install a callback that should be called when there is a managed exception
3738 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3739 * managed exception to a native exception, to properly unwind the native
3740 * stack; this native exception will then be converted back to a managed
3741 * exception in their managed-to-native wrapper.
3743 void
3744 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
3746 ftnptr_eh_callback = callback;
3750 * LLVM/Bitcode exception handling.
3753 static void
3754 throw_exception (MonoObject *ex, gboolean rethrow)
3756 MONO_REQ_GC_UNSAFE_MODE;
3758 ERROR_DECL (error);
3759 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3760 MonoException *mono_ex;
3762 if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, error)) {
3763 mono_error_assert_ok (error);
3764 mono_ex = mono_get_exception_runtime_wrapped_checked (ex, error);
3765 mono_error_assert_ok (error);
3766 jit_tls->thrown_non_exc = mono_gchandle_new_internal (ex, FALSE);
3768 else
3769 mono_ex = (MonoException*)ex;
3771 // Note: Not pinned
3772 jit_tls->thrown_exc = mono_gchandle_new_internal ((MonoObject*)mono_ex, FALSE);
3774 if (!rethrow) {
3775 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3776 GList *l, *ips = NULL;
3777 GList *trace;
3779 _Unwind_Backtrace (build_stack_trace, &ips);
3780 /* The list contains ip-gshared info pairs */
3781 trace = NULL;
3782 ips = g_list_reverse (ips);
3783 for (l = ips; l; l = l->next) {
3784 trace = g_list_append (trace, l->data);
3785 trace = g_list_append (trace, NULL);
3786 trace = g_list_append (trace, NULL);
3788 MonoArray *ips_arr = mono_glist_to_array (trace, mono_defaults.int_class, error);
3789 mono_error_assert_ok (error);
3790 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3791 g_list_free (l);
3792 g_list_free (trace);
3793 #endif
3796 mono_llvm_cpp_throw_exception ();
3799 void
3800 mono_llvm_throw_exception (MonoObject *ex)
3802 throw_exception (ex, FALSE);
3805 void
3806 mono_llvm_rethrow_exception (MonoObject *ex)
3808 throw_exception (ex, TRUE);
3811 void
3812 mono_llvm_raise_exception (MonoException *e)
3814 mono_llvm_throw_exception ((MonoObject*)e);
3817 void
3818 mono_llvm_reraise_exception (MonoException *e)
3820 mono_llvm_rethrow_exception ((MonoObject*)e);
3823 void
3824 mono_llvm_throw_corlib_exception (guint32 ex_token_index)
3826 guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
3827 MonoException *ex;
3829 ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token);
3831 mono_llvm_throw_exception ((MonoObject*)ex);
3835 * mono_llvm_resume_exception:
3837 * Resume exception propagation.
3839 void
3840 mono_llvm_resume_exception (void)
3842 mono_llvm_cpp_throw_exception ();
3846 * mono_llvm_load_exception:
3848 * Return the currently thrown exception.
3850 MonoObject *
3851 mono_llvm_load_exception (void)
3853 ERROR_DECL (error);
3854 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3856 MonoException *mono_ex = (MonoException*)mono_gchandle_get_target_internal (jit_tls->thrown_exc);
3858 MonoArray *ta = mono_ex->trace_ips;
3860 if (ta) {
3861 GList *trace_ips = NULL;
3862 gpointer ip = MONO_RETURN_ADDRESS ();
3864 size_t upper = mono_array_length_internal (ta);
3866 for (int i = 0; i < upper; i += TRACE_IP_ENTRY_SIZE) {
3867 gpointer curr_ip = mono_array_get_internal (ta, gpointer, i);
3868 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
3869 gpointer p = mono_array_get_internal (ta, gpointer, i + j);
3870 trace_ips = g_list_append (trace_ips, p);
3872 if (ip == curr_ip)
3873 break;
3876 // FIXME: Does this work correctly for rethrows?
3877 // We may be discarding useful information
3878 // when this gets GC'ed
3879 MonoArray *ips_arr = mono_glist_to_array (trace_ips, mono_defaults.int_class, error);
3880 mono_error_assert_ok (error);
3881 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3882 g_list_free (trace_ips);
3884 // FIXME:
3885 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3886 } else {
3887 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, 0, error));
3888 mono_error_assert_ok (error);
3889 MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, mono_array_new_checked (mono_domain_get (), mono_defaults.stack_frame_class, 0, error));
3890 mono_error_assert_ok (error);
3893 return &mono_ex->object;
3897 * mono_llvm_clear_exception:
3899 * Mark the currently thrown exception as handled.
3901 void
3902 mono_llvm_clear_exception (void)
3904 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3905 mono_gchandle_free_internal (jit_tls->thrown_exc);
3906 jit_tls->thrown_exc = 0;
3907 if (jit_tls->thrown_non_exc)
3908 mono_gchandle_free_internal (jit_tls->thrown_non_exc);
3909 jit_tls->thrown_non_exc = 0;
3911 mono_memory_barrier ();
3915 * mono_llvm_match_exception:
3917 * Return the innermost clause containing REGION_START-REGION_END which can handle
3918 * the current exception.
3920 gint32
3921 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
3923 ERROR_DECL (error);
3924 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3925 MonoObject *exc;
3926 gint32 index = -1;
3928 g_assert (jit_tls->thrown_exc);
3929 exc = mono_gchandle_get_target_internal (jit_tls->thrown_exc);
3930 if (jit_tls->thrown_non_exc) {
3932 * Have to unwrap RuntimeWrappedExceptions if the
3933 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
3935 if (!wrap_non_exception_throws (jinfo_get_method (jinfo)))
3936 exc = mono_gchandle_get_target_internal (jit_tls->thrown_non_exc);
3939 for (int i = 0; i < jinfo->num_clauses; i++) {
3940 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
3941 MonoClass *catch_class;
3943 if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
3944 continue;
3946 catch_class = ei->data.catch_class;
3947 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class))) {
3948 MonoGenericContext context;
3949 MonoType *inflated_type;
3951 g_assert (rgctx || this_obj);
3952 context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
3953 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
3954 mono_error_assert_ok (error); /* FIXME don't swallow the error */
3956 catch_class = mono_class_from_mono_type_internal (inflated_type);
3957 mono_metadata_free_type (inflated_type);
3960 // FIXME: Handle edge cases handled in get_exception_catch_class
3961 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, error)) {
3962 index = ei->clause_index;
3963 break;
3964 } else
3965 mono_error_assert_ok (error);
3967 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3968 g_assert_not_reached ();
3972 return index;
3975 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
3976 G_EXTERN_C _Unwind_Reason_Code mono_debug_personality (int a, _Unwind_Action b,
3977 uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
3979 g_assert_not_reached ();
3981 #else
3982 G_EXTERN_C void mono_debug_personality (void);
3984 void
3985 mono_debug_personality (void)
3987 g_assert_not_reached ();
3989 #endif