[llvm] Mark Vector128/Vector256 types as SIMD.
[mono-project.git] / mono / mini / mini-exceptions.c
blobe1d4c37fc973ea1d4f6981acdea7231ddf73d1f9
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);
136 static void mono_crash_reporting_allow_all_native_libraries (void);
138 static gboolean
139 first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
141 gpointer *data = (gpointer *)addr;
143 if (!frame->managed)
144 return FALSE;
146 if (!ctx) {
147 // FIXME: Happens with llvm_only
148 *data = NULL;
149 return TRUE;
152 *data = frame->frame_addr;
153 g_assert (*data);
154 return TRUE;
157 static gpointer
158 mono_thread_get_managed_sp (void)
160 gpointer addr = NULL;
161 mono_walk_stack (first_managed, MONO_UNWIND_SIGNAL_SAFE, &addr);
162 return addr;
165 static void
166 mini_clear_abort_threshold (void)
168 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
169 jit_tls->abort_exc_stack_threshold = NULL;
172 static void
173 mini_set_abort_threshold (StackFrameInfo *frame)
175 gpointer sp = frame->frame_addr;
176 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
177 // Only move it up, to avoid thrown/caught
178 // exceptions lower in the stack from triggering
179 // a rethrow
180 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
181 if (!jit_tls->abort_exc_stack_threshold || above_threshold) {
182 jit_tls->abort_exc_stack_threshold = sp;
186 // Note: In the case that the frame is above where the thread abort
187 // was set we bump the threshold so that functions called from the new,
188 // higher threshold don't trigger the thread abort exception
189 static gboolean
190 mini_above_abort_threshold (void)
192 gpointer sp = mono_thread_get_managed_sp ();
193 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
195 if (!sp)
196 return TRUE;
198 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
200 if (above_threshold)
201 jit_tls->abort_exc_stack_threshold = sp;
203 return above_threshold;
206 static int
207 mono_get_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
209 SeqPoint sp;
210 if (mono_find_prev_seq_point_for_native_offset (domain, method, native_offset, NULL, &sp))
211 return sp.il_offset;
212 return -1;
215 void
216 mono_exceptions_init (void)
218 MonoRuntimeExceptionHandlingCallbacks cbs;
219 if (mono_ee_features.use_aot_trampolines) {
220 restore_context_func = mono_aot_get_trampoline ("restore_context");
221 call_filter_func = mono_aot_get_trampoline ("call_filter");
222 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
223 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
224 rethrow_preserve_exception_func = mono_aot_get_trampoline ("rethrow_preserve_exception");
225 } else if (!mono_llvm_only) {
226 MonoTrampInfo *info;
228 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
229 mono_tramp_info_register (info, NULL);
230 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
231 mono_tramp_info_register (info, NULL);
232 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
233 mono_tramp_info_register (info, NULL);
234 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
235 mono_tramp_info_register (info, NULL);
236 rethrow_preserve_exception_func = mono_arch_get_rethrow_preserve_exception (&info, FALSE);
237 mono_tramp_info_register (info, NULL);
240 mono_arch_exceptions_init ();
242 cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
243 cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
244 cbs.mono_summarize_managed_stack = mono_summarize_managed_stack;
245 cbs.mono_summarize_unmanaged_stack = mono_summarize_unmanaged_stack;
246 cbs.mono_summarize_exception = mono_summarize_exception;
247 cbs.mono_register_native_library = mono_crash_reporting_register_native_library;
248 cbs.mono_allow_all_native_libraries = mono_crash_reporting_allow_all_native_libraries;
250 if (mono_llvm_only) {
251 cbs.mono_raise_exception = mono_llvm_raise_exception;
252 cbs.mono_reraise_exception = mono_llvm_reraise_exception;
253 } else {
254 cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception ();
255 cbs.mono_reraise_exception = (void (*)(MonoException *))mono_get_rethrow_exception ();
257 cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
258 cbs.mono_exception_walk_trace = mono_exception_walk_trace;
259 cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
260 cbs.mono_uninstall_current_handler_block_guard = mono_uninstall_current_handler_block_guard;
261 cbs.mono_current_thread_has_handle_block_guard = mono_current_thread_has_handle_block_guard;
262 cbs.mono_clear_abort_threshold = mini_clear_abort_threshold;
263 cbs.mono_above_abort_threshold = mini_above_abort_threshold;
264 mono_install_eh_callbacks (&cbs);
265 mono_install_get_seq_point (mono_get_seq_point_for_native_offset);
268 gpointer
269 mono_get_throw_exception (void)
271 g_assert (throw_exception_func);
272 return throw_exception_func;
275 gpointer
276 mono_get_rethrow_exception (void)
278 g_assert (rethrow_exception_func);
279 return rethrow_exception_func;
282 gpointer
283 mono_get_rethrow_preserve_exception (void)
285 g_assert (rethrow_preserve_exception_func);
286 return rethrow_preserve_exception_func;
289 static void
290 no_call_filter (void)
292 g_assert_not_reached ();
295 gpointer
296 mono_get_call_filter (void)
298 /* This is called even in llvmonly mode etc. */
299 if (!call_filter_func)
300 return (gpointer)no_call_filter;
301 return call_filter_func;
304 gpointer
305 mono_get_restore_context (void)
307 g_assert (restore_context_func);
308 return restore_context_func;
311 gpointer
312 mono_get_throw_corlib_exception (void)
314 gpointer code = NULL;
315 MonoTrampInfo *info;
317 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
318 if (throw_corlib_exception_func)
319 return throw_corlib_exception_func;
321 if (mono_ee_features.use_aot_trampolines)
322 code = mono_aot_get_trampoline ("throw_corlib_exception");
323 else {
324 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
325 mono_tramp_info_register (info, NULL);
328 mono_memory_barrier ();
330 throw_corlib_exception_func = code;
332 return throw_corlib_exception_func;
336 * mono_get_throw_exception_addr:
338 * Return an address which stores the result of
339 * mono_get_throw_exception.
341 gpointer
342 mono_get_throw_exception_addr (void)
344 return &throw_exception_func;
347 gpointer
348 mono_get_rethrow_preserve_exception_addr (void)
350 return &rethrow_preserve_exception_func;
353 static gboolean
354 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
356 MonoTryBlockHoleTableJitInfo *table;
357 int i;
358 guint32 offset;
359 guint16 clause;
361 if (ei->try_start > ip || ip >= ei->try_end)
362 return FALSE;
364 if (!ji->has_try_block_holes)
365 return TRUE;
367 table = mono_jit_info_get_try_block_hole_table_info (ji);
368 offset = (guint32)((char*)ip - (char*)ji->code_start);
369 clause = (guint16)(ei - ji->clauses);
370 g_assert (clause < ji->num_clauses);
372 for (i = 0; i < table->num_holes; ++i) {
373 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
374 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
375 return FALSE;
377 return TRUE;
380 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
382 #if 0
383 static gboolean show_native_addresses = TRUE;
384 #else
385 static gboolean show_native_addresses = FALSE;
386 #endif
388 static _Unwind_Reason_Code
389 build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
391 MonoDomain *domain = mono_domain_get ();
392 uintptr_t ip = _Unwind_GetIP (frame_ctx);
394 if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
395 GList **trace_ips = (GList **)state;
396 *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
399 return _URC_NO_REASON;
402 static GSList*
403 get_unwind_backtrace (void)
405 GSList *ips = NULL;
407 _Unwind_Backtrace (build_stack_trace, &ips);
409 return g_slist_reverse (ips);
412 #else
414 static GSList*
415 get_unwind_backtrace (void)
417 return NULL;
420 #endif
422 static gboolean
423 arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
424 MonoJitInfo *ji, MonoContext *ctx,
425 MonoContext *new_ctx, MonoLMF **lmf,
426 host_mgreg_t **save_locations,
427 StackFrameInfo *frame)
429 if (!ji && *lmf) {
430 if (((gsize)(*lmf)->previous_lmf) & 2) {
431 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
433 memset (frame, 0, sizeof (StackFrameInfo));
434 frame->ji = ji;
436 *new_ctx = *ctx;
438 if (ext->kind == MONO_LMFEXT_DEBUGGER_INVOKE) {
440 * This LMF entry is created by the soft debug code to mark transitions to
441 * managed code done during invokes.
443 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
444 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
445 } else if (ext->kind == MONO_LMFEXT_INTERP_EXIT || ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX) {
446 frame->type = FRAME_TYPE_INTERP_TO_MANAGED;
447 frame->interp_exit_data = ext->interp_exit_data;
448 if (ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX) {
449 frame->type = FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX;
450 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
452 } else {
453 g_assert_not_reached ();
456 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~3);
458 return TRUE;
462 return mono_arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
466 * find_jit_info:
468 * Translate between the mono_arch_unwind_frame function and the old API.
470 static MonoJitInfo *
471 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
472 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
474 StackFrameInfo frame;
475 MonoJitInfo *ji;
476 gboolean err;
477 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
479 /* Avoid costly table lookup during stack overflow */
480 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
481 ji = prev_ji;
482 else
483 ji = mini_jit_info_table_find (domain, ip, NULL);
485 if (managed)
486 *managed = FALSE;
488 err = arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
489 if (!err)
490 return (MonoJitInfo *)-1;
492 if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
494 * Remove any unused lmf.
495 * Mask out the lower bits which might be used to hold additional information.
497 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P -1));
500 /* Convert between the new and the old APIs */
501 switch (frame.type) {
502 case FRAME_TYPE_MANAGED:
503 if (managed)
504 *managed = TRUE;
505 return frame.ji;
506 case FRAME_TYPE_TRAMPOLINE:
507 return frame.ji;
508 case FRAME_TYPE_MANAGED_TO_NATIVE:
509 if (frame.ji)
510 return frame.ji;
511 else {
512 memset (res, 0, sizeof (MonoJitInfo));
513 res->d.method = frame.method;
514 return res;
516 case FRAME_TYPE_DEBUGGER_INVOKE: {
517 MonoContext tmp_ctx;
520 * The normal exception handling code can't handle this frame, so just
521 * skip it.
523 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
524 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
525 return ji;
527 default:
528 g_assert_not_reached ();
529 return NULL;
533 /* mono_find_jit_info:
535 * This function is used to gather information from @ctx. It return the
536 * MonoJitInfo of the corresponding function, unwinds one stack frame and
537 * stores the resulting context into @new_ctx. It also stores a string
538 * describing the stack location into @trace (if not NULL), and modifies
539 * the @lmf if necessary. @native_offset return the IP offset from the
540 * start of the function or -1 if that info is not available.
542 MonoJitInfo *
543 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
544 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
545 gboolean *managed)
547 gboolean managed2;
548 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
549 MonoJitInfo *ji;
550 MonoMethod *method = NULL;
552 if (trace)
553 *trace = NULL;
555 if (native_offset)
556 *native_offset = -1;
558 if (managed)
559 *managed = FALSE;
561 ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
563 if (ji == (gpointer)-1)
564 return ji;
566 if (ji && !ji->is_trampoline)
567 method = jinfo_get_method (ji);
569 if (managed2 || (method && method->wrapper_type)) {
570 const char *real_ip, *start;
571 gint32 offset;
573 start = (const char *)ji->code_start;
574 if (!managed2)
575 /* ctx->ip points into native code */
576 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
577 else
578 real_ip = (const char*)ip;
580 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
581 offset = real_ip - start;
582 else
583 offset = -1;
585 if (native_offset)
586 *native_offset = offset;
588 if (managed)
589 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
590 *managed = TRUE;
592 if (trace)
593 *trace = mono_debug_print_stack_frame (method, offset, domain);
594 } else {
595 if (trace) {
596 char *fname = mono_method_full_name (jinfo_get_method (res), TRUE);
597 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
598 g_free (fname);
602 return ji;
606 * mono_find_jit_info_ext:
608 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
609 * structure.
610 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
611 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
612 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
613 * to obtain the last managed frame.
614 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
615 * On return, it will be filled with the locations where callee saved registers are saved
616 * by the current frame. This is returned outside of StackFrameInfo because it can be
617 * quite large on some platforms.
618 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
619 * not be set.
621 gboolean
622 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
623 MonoJitInfo *prev_ji, MonoContext *ctx,
624 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
625 host_mgreg_t **save_locations,
626 StackFrameInfo *frame)
628 gboolean err;
629 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
630 MonoJitInfo *ji;
631 MonoDomain *target_domain = domain;
632 MonoMethod *method = NULL;
633 gboolean async = mono_thread_info_is_async_context ();
635 if (trace)
636 *trace = NULL;
638 /* Avoid costly table lookup during stack overflow */
639 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
640 ji = prev_ji;
641 else
642 ji = mini_jit_info_table_find_ext (domain, ip, TRUE, &target_domain);
644 if (!target_domain)
645 target_domain = domain;
647 if (save_locations)
648 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (host_mgreg_t*));
650 err = arch_unwind_frame (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
651 if (!err)
652 return FALSE;
654 gboolean not_i2m = frame->type != FRAME_TYPE_INTERP_TO_MANAGED && frame->type != FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX;
656 if (not_i2m && *lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
658 * Remove any unused lmf.
659 * Mask out the lower bits which might be used to hold additional information.
661 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P -1));
664 if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async)
665 method = jinfo_get_method (frame->ji);
667 if (frame->type == FRAME_TYPE_MANAGED && method) {
668 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
669 frame->managed = TRUE;
672 if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
674 * This type of frame is just a marker, the caller should unwind once more to get the
675 * last managed frame.
677 frame->ji = NULL;
678 frame->method = NULL;
681 frame->native_offset = -1;
682 frame->domain = target_domain;
683 frame->async_context = async;
684 frame->frame_addr = MONO_CONTEXT_GET_SP (ctx);
686 ji = frame->ji;
688 if (frame->type == FRAME_TYPE_MANAGED)
689 frame->method = method;
691 if (ji && (frame->managed || (method && method->wrapper_type))) {
692 const char *real_ip, *start;
694 start = (const char *)ji->code_start;
695 if (frame->type == FRAME_TYPE_MANAGED)
696 real_ip = (const char*)ip;
697 else
698 /* ctx->ip points into native code */
699 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
701 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
702 frame->native_offset = real_ip - start;
703 else {
704 frame->native_offset = -1;
707 if (trace)
708 *trace = mono_debug_print_stack_frame (method, frame->native_offset, domain);
709 } else {
710 if (trace && frame->method) {
711 char *fname = mono_method_full_name (frame->method, TRUE);
712 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
713 g_free (fname);
717 return TRUE;
720 typedef struct {
721 gboolean in_interp;
722 MonoInterpStackIter interp_iter;
723 gpointer last_frame_addr;
724 } Unwinder;
726 static void
727 unwinder_init (Unwinder *unwinder)
729 memset (unwinder, 0, sizeof (Unwinder));
732 #if defined(__GNUC__) && defined(TARGET_ARM64)
733 /* gcc 4.9.2 seems to miscompile this on arm64 */
734 static __attribute__((optimize("O0"))) gboolean
735 #else
736 static gboolean
737 #endif
738 unwinder_unwind_frame (Unwinder *unwinder,
739 MonoDomain *domain, MonoJitTlsData *jit_tls,
740 MonoJitInfo *prev_ji, MonoContext *ctx,
741 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
742 host_mgreg_t **save_locations,
743 StackFrameInfo *frame)
745 gpointer parent;
746 if (unwinder->in_interp) {
747 memcpy (new_ctx, ctx, sizeof (MonoContext));
749 /* Process debugger invokes */
750 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
751 if (unwinder->last_frame_addr < (gpointer)(*lmf)) {
752 if (((gsize)(*lmf)->previous_lmf) & 2) {
753 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
754 if (ext->kind == MONO_LMFEXT_DEBUGGER_INVOKE) {
755 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~7);
756 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
757 return TRUE;
762 unwinder->in_interp = mini_get_interp_callbacks ()->frame_iter_next (&unwinder->interp_iter, frame);
763 if (frame->type == FRAME_TYPE_INTERP) {
764 parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame);
765 unwinder->last_frame_addr = parent;
767 if (!unwinder->in_interp)
768 return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame);
769 return TRUE;
770 } else {
771 gboolean res = mono_find_jit_info_ext (domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf,
772 save_locations, frame);
773 if (!res)
774 return FALSE;
775 if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED || frame->type == FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX) {
776 unwinder->in_interp = TRUE;
777 mini_get_interp_callbacks ()->frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data);
779 unwinder->last_frame_addr = frame->frame_addr;
780 return TRUE;
785 * This function is async-safe.
787 static gpointer
788 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
790 MonoGenericJitInfo *gi;
791 MonoMethod *method;
792 gpointer info;
794 if (!ji->has_generic_jit_info)
795 return NULL;
796 gi = mono_jit_info_get_generic_jit_info (ji);
797 if (!gi->has_this)
798 return NULL;
800 info = NULL;
802 * Search location list if available, it contains the precise location of the
803 * argument for every pc offset, even if the method was interrupted while it was in
804 * its prolog.
806 if (gi->nlocs) {
807 int offset = (gsize)MONO_CONTEXT_GET_IP (ctx) - (gsize)ji->code_start;
808 int i;
810 for (i = 0; i < gi->nlocs; ++i) {
811 MonoDwarfLocListEntry *entry = &gi->locations [i];
813 if (offset >= entry->from && (offset < entry->to || entry->to == 0)) {
814 if (entry->is_reg)
815 info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg);
816 else
817 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset);
818 break;
821 g_assert (i < gi->nlocs);
822 } else {
823 if (gi->this_in_reg)
824 info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg);
825 else
826 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
827 gi->this_offset);
830 method = jinfo_get_method (ji);
831 if (mono_method_get_context (method)->method_inst) {
832 /* A MonoMethodRuntimeGenericContext* */
833 return info;
834 } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || m_class_is_valuetype (method->klass)) {
835 /* A MonoVTable* */
836 return info;
837 } else {
838 /* Avoid returning a managed object */
839 MonoObject *this_obj = (MonoObject *)info;
841 return this_obj->vtable;
846 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
848 static MonoGenericContext
849 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
851 MonoGenericContext context = { NULL, NULL };
852 MonoClass *klass, *method_container_class;
853 MonoMethod *method;
855 g_assert (generic_info);
857 method = jinfo_get_method (ji);
858 g_assert (method->is_inflated);
859 if (mono_method_get_context (method)->method_inst) {
860 MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext *)generic_info;
862 klass = mrgctx->class_vtable->klass;
863 context.method_inst = mrgctx->method_inst;
864 g_assert (context.method_inst);
865 } else {
866 MonoVTable *vtable = (MonoVTable *)generic_info;
868 klass = vtable->klass;
871 //g_assert (!mono_class_is_gtd (method->klass));
872 if (mono_class_is_ginst (method->klass))
873 method_container_class = mono_class_get_generic_class (method->klass)->container_class;
874 else
875 method_container_class = method->klass;
877 /* class might refer to a subclass of method's class */
878 while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) {
879 klass = m_class_get_parent (klass);
880 g_assert (klass);
883 if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass))
884 context.class_inst = mini_class_get_context (klass)->class_inst;
886 if (mono_class_is_ginst (klass))
887 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass)->container_class, method_container_class));
888 else
889 g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class));
891 return context;
894 static MonoMethod*
895 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
897 ERROR_DECL (error);
898 MonoGenericContext context;
899 MonoMethod *method;
901 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
902 return jinfo_get_method (ji);
903 context = get_generic_context_from_stack_frame (ji, generic_info);
905 method = jinfo_get_method (ji);
906 method = mono_method_get_declaring_generic_method (method);
907 method = mono_class_inflate_generic_method_checked (method, &context, error);
908 g_assert (is_ok (error)); /* FIXME don't swallow the error */
910 return method;
914 * mono_exception_walk_native_trace:
915 * \param ex The exception object whose frames should be walked
916 * \param func callback to call for each stack frame
917 * \param user_data data passed to the callback
918 * This function walks the stacktrace of an exception. For
919 * each frame the callback function is called with the relevant info.
920 * The walk ends when no more stack frames are found or when the callback
921 * returns a TRUE value.
924 gboolean
925 mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
927 gboolean res;
929 MONO_ENTER_GC_UNSAFE;
930 res = mono_exception_walk_trace_internal (ex, func, user_data);
931 MONO_EXIT_GC_UNSAFE;
932 return res;
935 static gboolean
936 mono_exception_stackframe_obj_walk (MonoStackFrame *captured_frame, MonoExceptionFrameWalk func, gpointer user_data)
938 if (!captured_frame)
939 return TRUE;
941 gpointer ip = (gpointer) (captured_frame->method_address + captured_frame->native_offset);
942 MonoJitInfo *ji = mono_jit_info_table_find_internal (mono_domain_get (), ip, TRUE, TRUE);
944 // Other domain maybe?
945 if (!ji)
946 return FALSE;
947 MonoMethod *method = jinfo_get_method (ji);
949 gboolean r = func (method, (gpointer) captured_frame->method_address, captured_frame->native_offset, TRUE, user_data);
950 if (r)
951 return TRUE;
953 return FALSE;
956 static gboolean
957 mono_exception_stacktrace_obj_walk (MonoStackTrace *st, MonoExceptionFrameWalk func, gpointer user_data)
959 int num_captured = st->captured_traces ? mono_array_length_internal (st->captured_traces) : 0;
960 for (int i=0; i < num_captured; i++) {
961 MonoStackTrace *curr_trace = mono_array_get_fast (st->captured_traces, MonoStackTrace *, i);
962 mono_exception_stacktrace_obj_walk (curr_trace, func, user_data);
965 int num_frames = st->frames ? mono_array_length_internal (st->frames) : 0;
966 for (int frame = 0; frame < num_frames; frame++) {
967 gboolean r = mono_exception_stackframe_obj_walk (mono_array_get_fast (st->frames, MonoStackFrame *, frame), func, user_data);
968 if (r)
969 return TRUE;
972 return TRUE;
975 gboolean
976 mono_exception_walk_trace_internal (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
978 MONO_REQ_GC_UNSAFE_MODE;
980 MonoDomain *domain = mono_domain_get ();
981 MonoArray *ta = ex->trace_ips;
983 /* Exception is not thrown yet */
984 if (ta == NULL)
985 return FALSE;
987 int len = mono_array_length_internal (ta) / TRACE_IP_ENTRY_SIZE;
988 gboolean otherwise_has_traces = len > 0;
990 for (int i = 0; i < len; i++) {
991 ExceptionTraceIp trace_ip;
993 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
994 gpointer ip = trace_ip.ip;
995 gpointer generic_info = trace_ip.generic_info;
997 MonoJitInfo *ji = NULL;
998 if (trace_ip.ji) {
999 ji = trace_ip.ji;
1000 } else {
1001 ji = mono_jit_info_table_find (domain, ip);
1004 if (ji == NULL) {
1005 gboolean r;
1006 MONO_ENTER_GC_SAFE;
1007 r = func (NULL, ip, 0, FALSE, user_data);
1008 MONO_EXIT_GC_SAFE;
1009 if (r)
1010 break;
1011 } else {
1012 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
1013 if (func (method, ji->code_start, (char *) ip - (char *) ji->code_start, TRUE, user_data))
1014 break;
1018 ta = (MonoArray *) ex->captured_traces;
1019 len = ta ? mono_array_length_internal (ta) : 0;
1020 gboolean captured_has_traces = len > 0;
1022 for (int i = 0; i < len; i++) {
1023 MonoStackTrace *captured_trace = mono_array_get_fast (ta, MonoStackTrace *, i);
1024 if (!captured_trace)
1025 break;
1027 mono_exception_stacktrace_obj_walk (captured_trace, func, user_data);
1030 return captured_has_traces || otherwise_has_traces;
1033 MonoArray *
1034 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
1036 ERROR_DECL (error);
1037 MonoDomain *domain = mono_domain_get ();
1038 MonoArray *res;
1039 MonoArray *ta = exc->trace_ips;
1040 MonoDebugSourceLocation *location;
1041 int i, len;
1043 if (ta == NULL) {
1044 /* Exception is not thrown yet */
1045 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, error);
1046 mono_error_set_pending_exception (error);
1047 return res;
1050 len = mono_array_length_internal (ta) / TRACE_IP_ENTRY_SIZE;
1052 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, error);
1053 if (mono_error_set_pending_exception (error))
1054 return NULL;
1056 for (i = skip; i < len; i++) {
1057 MonoJitInfo *ji;
1058 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
1059 if (!is_ok (error)) {
1060 mono_error_set_pending_exception (error);
1061 return NULL;
1063 ExceptionTraceIp trace_ip;
1064 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
1065 gpointer ip = trace_ip.ip;
1066 gpointer generic_info = trace_ip.generic_info;
1067 MonoMethod *method;
1069 if (trace_ip.ji) {
1070 ji = trace_ip.ji;
1071 } else {
1072 ji = mono_jit_info_table_find (domain, ip);
1073 if (ji == NULL) {
1074 /* Unmanaged frame */
1075 mono_array_setref_internal (res, i, sf);
1076 continue;
1080 g_assert (ji != NULL);
1082 if (mono_llvm_only || !generic_info)
1083 /* Can't resolve actual method */
1084 method = jinfo_get_method (ji);
1085 else
1086 method = get_method_from_stack_frame (ji, generic_info);
1087 if (jinfo_get_method (ji)->wrapper_type) {
1088 char *s;
1090 sf->method = NULL;
1091 s = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION);
1092 MonoString *name = mono_string_new_checked (domain, s, error);
1093 g_free (s);
1094 if (!is_ok (error)) {
1095 mono_error_set_pending_exception (error);
1096 return NULL;
1098 MONO_OBJECT_SETREF_INTERNAL (sf, internal_method_name, name);
1100 else {
1101 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
1102 if (!is_ok (error)) {
1103 mono_error_set_pending_exception (error);
1104 return NULL;
1106 MONO_OBJECT_SETREF_INTERNAL (sf, method, rm);
1109 sf->method_index = ji->from_aot ? mono_aot_find_method_index (method) : 0xffffff;
1110 sf->method_address = (gsize) ji->code_start;
1111 sf->native_offset = (char *)ip - (char *)ji->code_start;
1114 * mono_debug_lookup_source_location() returns both the file / line number information
1115 * and the IL offset. Note that computing the IL offset is already an expensive
1116 * operation, so we shouldn't call this method twice.
1118 location = mono_debug_lookup_source_location (jinfo_get_method (ji), sf->native_offset, domain);
1119 if (location) {
1120 sf->il_offset = location->il_offset;
1121 } else {
1122 SeqPoint sp;
1123 if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (ji), sf->native_offset, NULL, &sp))
1124 sf->il_offset = sp.il_offset;
1125 else
1126 sf->il_offset = -1;
1129 if (need_file_info) {
1130 if (location && location->source_file) {
1131 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1132 if (!is_ok (error)) {
1133 mono_error_set_pending_exception (error);
1134 return NULL;
1136 MONO_OBJECT_SETREF_INTERNAL (sf, filename, filename);
1137 sf->line = location->row;
1138 sf->column = location->column;
1139 } else {
1140 sf->line = sf->column = 0;
1141 sf->filename = NULL;
1145 mono_debug_free_source_location (location);
1146 mono_array_setref_internal (res, i - skip, sf);
1149 return res;
1152 static void
1153 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1155 if (!start_ctx) {
1156 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1157 if (jit_tls && jit_tls->orig_ex_ctx_set)
1158 start_ctx = &jit_tls->orig_ex_ctx;
1160 mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
1163 * mono_walk_stack_with_ctx:
1164 * Unwind the current thread starting at \p start_ctx.
1165 * If \p start_ctx is null, we capture the current context.
1167 void
1168 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1170 MonoContext extra_ctx;
1171 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1172 MONO_ARCH_CONTEXT_DEF
1174 if (!thread || !thread->jit_data)
1175 return;
1177 if (!start_ctx) {
1178 mono_arch_flush_register_windows ();
1179 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
1180 start_ctx = &extra_ctx;
1183 mono_walk_stack_full (func, start_ctx, mono_domain_get (), thread->jit_data, mono_get_lmf (), unwind_options, user_data, FALSE);
1187 * mono_walk_stack_with_state:
1188 * Unwind a thread described by \p state.
1190 * State must be valid (state->valid == TRUE).
1192 * If you are using this function to unwind another thread, make sure it is suspended.
1194 * If \p state is null, we capture the current context.
1196 void
1197 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
1199 MonoThreadUnwindState extra_state;
1200 if (!state) {
1201 g_assert (!mono_thread_info_is_async_context ());
1202 if (!mono_thread_state_init_from_current (&extra_state))
1203 return;
1204 state = &extra_state;
1207 g_assert (state->valid);
1209 if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
1210 /* Not attached */
1211 return;
1213 mono_walk_stack_full (func,
1214 &state->ctx,
1215 (MonoDomain *)state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
1216 (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
1217 (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF],
1218 unwind_options, user_data, FALSE);
1221 void
1222 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
1224 MonoThreadUnwindState state;
1225 if (!mono_thread_state_init_from_current (&state))
1226 return;
1227 mono_walk_stack_with_state (func, &state, options, user_data);
1231 * mono_walk_stack_full:
1232 * \param func callback to call for each stack frame
1233 * \param domain starting appdomain, can be NULL to use the current domain
1234 * \param unwind_options what extra information the unwinder should gather
1235 * \param start_ctx starting state of the stack walk, can be NULL.
1236 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1237 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1238 * \param user_data data passed to the callback
1239 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1240 * This function walks the stack of a thread, starting from the state
1241 * represented by \p start_ctx. For each frame the callback
1242 * function is called with the relevant info. The walk ends when no more
1243 * managed stack frames are found or when the callback returns a TRUE value.
1245 static void
1246 mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data, gboolean crash_context)
1248 gint il_offset;
1249 MonoContext ctx, new_ctx;
1250 StackFrameInfo frame;
1251 gboolean res;
1252 host_mgreg_t *reg_locations [MONO_MAX_IREGS];
1253 host_mgreg_t *new_reg_locations [MONO_MAX_IREGS];
1254 gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
1255 gboolean async = mono_thread_info_is_async_context ();
1256 Unwinder unwinder;
1258 memset (&frame, 0, sizeof (StackFrameInfo));
1260 #ifndef TARGET_WASM
1261 if (mono_llvm_only) {
1262 GSList *l, *ips;
1264 if (async)
1265 return;
1267 ips = get_unwind_backtrace ();
1268 for (l = ips; l; l = l->next) {
1269 guint8 *ip = (guint8*)l->data;
1270 memset (&frame, 0, sizeof (StackFrameInfo));
1271 frame.ji = mini_jit_info_table_find (domain, ip, &frame.domain);
1272 if (!frame.ji || frame.ji->is_trampoline)
1273 continue;
1274 frame.type = FRAME_TYPE_MANAGED;
1275 frame.method = jinfo_get_method (frame.ji);
1276 // FIXME: Cannot lookup the actual method
1277 frame.actual_method = frame.method;
1278 if (frame.type == FRAME_TYPE_MANAGED) {
1279 if (!frame.method->wrapper_type || frame.method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
1280 frame.managed = TRUE;
1282 frame.native_offset = ip - (guint8*)frame.ji->code_start;
1283 frame.il_offset = -1;
1285 if (func (&frame, NULL, user_data))
1286 break;
1288 g_slist_free (ips);
1289 return;
1291 #endif
1293 if (!start_ctx) {
1294 g_warning ("start_ctx required for stack walk");
1295 return;
1298 if (!domain) {
1299 g_warning ("domain required for stack walk");
1300 return;
1303 if (!jit_tls) {
1304 g_warning ("jit_tls required for stack walk");
1305 return;
1308 /*The LMF will be null if the target have no managed frames.*/
1309 /* g_assert (lmf); */
1310 if (async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD)) {
1311 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1312 return;
1315 memcpy (&ctx, start_ctx, sizeof (MonoContext));
1316 memset (reg_locations, 0, sizeof (reg_locations));
1318 unwinder_init (&unwinder);
1320 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
1321 frame.lmf = lmf;
1322 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
1323 if (!res)
1324 return;
1326 if (frame.type == FRAME_TYPE_TRAMPOLINE)
1327 goto next;
1329 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) {
1330 MonoDebugSourceLocation *source = NULL;
1332 // Don't do this when we can be in a signal handler
1333 if (!crash_context)
1334 source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
1335 if (source) {
1336 il_offset = source->il_offset;
1337 } else {
1338 MonoSeqPointInfo *seq_points = NULL;
1340 // It's more reliable to look into the global cache if possible
1341 if (crash_context)
1342 seq_points = (MonoSeqPointInfo *) frame.ji->seq_points;
1343 else
1344 seq_points = mono_get_seq_points (domain, jinfo_get_method (frame.ji));
1346 SeqPoint sp;
1347 if (seq_points && mono_seq_point_find_prev_by_native_offset (seq_points, frame.native_offset, &sp))
1348 il_offset = sp.il_offset;
1349 else
1350 il_offset = -1;
1352 mono_debug_free_source_location (source);
1353 } else
1354 il_offset = -1;
1356 frame.il_offset = il_offset;
1358 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) {
1359 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
1360 } else {
1361 frame.actual_method = frame.method;
1364 if (get_reg_locations)
1365 frame.reg_locations = reg_locations;
1367 if (func (&frame, &ctx, user_data))
1368 return;
1370 next:
1371 if (get_reg_locations) {
1372 for (int i = 0; i < MONO_MAX_IREGS; ++i)
1373 if (new_reg_locations [i])
1374 reg_locations [i] = new_reg_locations [i];
1377 ctx = new_ctx;
1381 #ifdef DISABLE_CRASH_REPORTING
1383 static void
1384 mono_summarize_managed_stack (MonoThreadSummary *out)
1386 return;
1389 static void
1390 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1392 return;
1395 static void
1396 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1398 return;
1401 static void
1402 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1404 return;
1407 static void
1408 mono_crash_reporting_allow_all_native_libraries ()
1410 return;
1414 #else
1416 typedef struct {
1417 MonoFrameSummary *frames;
1418 int num_frames;
1419 int max_frames;
1420 MonoStackHash *hashes;
1421 const char *error;
1422 } MonoSummarizeUserData;
1424 static void
1425 copy_summary_string_safe (char *in, const char *out)
1427 for (int i=0; i < MONO_MAX_SUMMARY_NAME_LEN; i++) {
1428 in [i] = out [i];
1429 if (out [i] == '\0')
1430 return;
1433 // Overflowed
1434 in [MONO_MAX_SUMMARY_NAME_LEN] = '\0';
1435 return;
1438 typedef struct {
1439 char *suffix;
1440 char *exported_name;
1441 } MonoLibWhitelistEntry;
1443 static GList *native_library_whitelist;
1444 static gboolean allow_all_native_libraries = FALSE;
1446 static void
1447 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1449 // Examples: libsystem_pthread.dylib -> "pthread"
1450 // Examples: libsystem_platform.dylib -> "platform"
1451 // Examples: mono-sgen -> "mono" from above line
1452 MonoLibWhitelistEntry *entry = g_new0 (MonoLibWhitelistEntry, 1);
1453 entry->suffix = g_strdup (module_path);
1454 entry->exported_name = g_strdup (module_name);
1455 native_library_whitelist = g_list_append (native_library_whitelist, entry);
1458 static void
1459 mono_crash_reporting_allow_all_native_libraries ()
1461 allow_all_native_libraries = TRUE;
1464 static gboolean
1465 check_whitelisted_module (const char *in_name, const char **out_module)
1467 #ifndef MONO_PRIVATE_CRASHES
1468 return TRUE;
1469 #else
1470 if (allow_all_native_libraries) {
1471 if (out_module)
1472 *out_module = "<external module>";
1473 return TRUE;
1475 if (g_str_has_suffix (in_name, "mono-sgen")) {
1476 if (out_module)
1477 *out_module = "mono";
1478 return TRUE;
1481 for (GList *cursor = native_library_whitelist; cursor; cursor = cursor->next) {
1482 MonoLibWhitelistEntry *iter = (MonoLibWhitelistEntry *) cursor->data;
1483 if (!g_str_has_suffix (in_name, iter->suffix))
1484 continue;
1485 if (out_module)
1486 *out_module = iter->exported_name;
1487 return TRUE;
1490 return FALSE;
1491 #endif
1494 static intptr_t
1495 mono_make_portable_ip (intptr_t in_ip, intptr_t module_base)
1497 // FIXME: Make generalize away from llvm tools?
1498 // So lldb starts the pointer base at 0x100000000
1499 // and expects to get pointers as (offset + constant)
1501 // Quirk shared by:
1502 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1503 // *CoreSymbolicationDT.framework version: 63750*/
1504 intptr_t offset = in_ip - module_base;
1505 intptr_t magic_value = offset + 0x100000000;
1506 return magic_value;
1509 static gboolean
1510 mono_get_portable_ip (intptr_t in_ip, intptr_t *out_ip, gint32 *out_offset, const char **out_module, char *out_name)
1512 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1513 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1514 // non-recursive lock twice on this thread, and will deadlock.
1515 Dl_info info;
1516 gboolean success = dladdr ((void*)in_ip, &info);
1517 if (!success)
1518 return FALSE;
1520 if (!check_whitelisted_module (info.dli_fname, out_module))
1521 return FALSE;
1523 *out_ip = mono_make_portable_ip ((intptr_t) info.dli_saddr, (intptr_t) info.dli_fbase);
1524 *out_offset = in_ip - (intptr_t) info.dli_saddr;
1526 #ifndef MONO_PRIVATE_CRASHES
1527 if (info.dli_saddr && out_name)
1528 copy_summary_string_safe (out_name, info.dli_sname);
1529 #endif
1530 return TRUE;
1533 static guint64
1534 summarize_offset_free_hash (guint64 accum, MonoFrameSummary *frame)
1536 if (!frame->is_managed)
1537 return accum;
1539 // See: mono_ptrarray_hash
1540 guint64 hash_accum = accum;
1542 // The assembly and the method token, no offsets
1543 hash_accum += mono_metadata_str_hash (frame->str_descr);
1544 hash_accum += frame->managed_data.token;
1546 return hash_accum;
1549 static guint64
1550 summarize_offset_rich_hash (guint64 accum, MonoFrameSummary *frame)
1552 // See: mono_ptrarray_hash
1553 guint64 hash_accum = accum;
1555 if (!frame->is_managed) {
1556 hash_accum += frame->unmanaged_data.ip;
1557 } else {
1558 hash_accum += mono_metadata_str_hash (frame->str_descr);
1559 hash_accum += frame->managed_data.token;
1560 hash_accum += frame->managed_data.il_offset;
1563 return hash_accum;
1566 static gboolean
1567 summarize_frame_internal (MonoMethod *method, gpointer ip, size_t native_offset, int il_offset, gboolean managed, gpointer user_data)
1569 MonoSummarizeUserData *ud = (MonoSummarizeUserData *) user_data;
1571 gboolean valid_state = ud->num_frames + 1 < ud->max_frames;
1572 if (!valid_state) {
1573 ud->error = "Exceeded the maximum number of frames";
1574 return TRUE;
1577 MonoFrameSummary *dest = &ud->frames [ud->num_frames];
1579 dest->unmanaged_data.ip = (intptr_t) ip;
1580 dest->is_managed = managed;
1582 if (!managed && method && method->wrapper_type != MONO_WRAPPER_NONE && method->wrapper_type < MONO_WRAPPER_NUM) {
1583 dest->is_managed = FALSE;
1584 dest->unmanaged_data.has_name = TRUE;
1585 copy_summary_string_safe (dest->str_descr, mono_wrapper_type_to_str (method->wrapper_type));
1588 #ifndef MONO_PRIVATE_CRASHES
1589 if (method)
1590 dest->managed_data.name = (char *) method->name;
1591 #endif
1593 if (managed) {
1594 if (!method) {
1595 ud->error = "Managed method frame, but no provided managed method";
1596 return TRUE;
1599 MonoImage *image = mono_class_get_image (method->klass);
1600 // Used for hashing, more stable across rebuilds than using GUID
1601 copy_summary_string_safe (dest->str_descr, image->assembly_name);
1603 dest->managed_data.guid = image->guid;
1605 dest->managed_data.native_offset = native_offset;
1606 dest->managed_data.token = method->token;
1607 dest->managed_data.il_offset = il_offset;
1609 dest->managed_data.filename = image->module_name;
1611 MonoDotNetHeader *header = &image->image_info->cli_header;
1612 dest->managed_data.image_size = header->nt.pe_image_size;
1614 dest->managed_data.time_date_stamp = image->time_date_stamp;
1616 } else {
1617 dest->managed_data.token = -1;
1621 ud->hashes->offset_free_hash = summarize_offset_free_hash (ud->hashes->offset_free_hash, dest);
1622 ud->hashes->offset_rich_hash = summarize_offset_rich_hash (ud->hashes->offset_rich_hash, dest);
1624 // We return FALSE, so we're continuing walking
1625 // And we increment the pointer because we're done with this cell in the array
1626 ud->num_frames++;
1627 return FALSE;
1630 static gboolean
1631 summarize_frame_managed_walk (MonoMethod *method, gpointer ip, size_t frame_native_offset, gboolean managed, gpointer user_data)
1633 int il_offset = -1;
1635 if (managed && method) {
1636 MonoDebugSourceLocation *location = mono_debug_lookup_source_location (method, frame_native_offset, mono_domain_get ());
1637 if (location) {
1638 il_offset = location->il_offset;
1639 mono_debug_free_source_location (location);
1643 intptr_t portable_ip = 0;
1644 gint32 offset = 0;
1645 mono_get_portable_ip ((intptr_t) ip, &portable_ip, &offset, NULL, NULL);
1647 return summarize_frame_internal (method, (gpointer) portable_ip, frame_native_offset, il_offset, managed, user_data);
1651 static gboolean
1652 summarize_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
1654 // Don't record trampolines between managed frames
1655 if (frame->ji && frame->ji->is_trampoline)
1656 return TRUE;
1658 if (frame->ji && (frame->ji->is_trampoline || frame->ji->async))
1659 return FALSE; // Keep unwinding
1661 intptr_t ip = 0;
1662 gint32 offset = 0;
1663 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx), &ip, &offset, NULL, NULL);
1664 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1666 gboolean is_managed = (frame->type == FRAME_TYPE_MANAGED || frame->type == FRAME_TYPE_INTERP);
1667 MonoMethod *method = NULL;
1668 if (frame && frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
1669 method = jinfo_get_method (frame->ji);
1671 if (is_managed)
1672 method = jinfo_get_method (frame->ji);
1674 return summarize_frame_internal (method, (gpointer) ip, offset, frame->il_offset, is_managed, data);
1677 static void
1678 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1680 memset (out, 0, sizeof (MonoThreadSummary));
1682 MonoException *inner_exc = exc;
1683 int exc_index = 0;
1685 for (exc_index = 0; exc_index < MONO_MAX_SUMMARY_EXCEPTIONS; exc_index++) {
1686 if (inner_exc == NULL)
1687 break;
1689 // Set up state to walk this MonoException's stack
1690 MonoSummarizeUserData data;
1691 memset (&data, 0, sizeof (MonoSummarizeUserData));
1692 data.max_frames = MONO_MAX_SUMMARY_FRAMES;
1693 data.num_frames = 0;
1694 data.frames = out->exceptions [exc_index].managed_frames;
1696 // Accumulate all hashes from all exceptions in traveral order
1697 data.hashes = &out->hashes;
1699 mono_exception_walk_trace (inner_exc, summarize_frame_managed_walk, &data);
1701 // Save per-MonoException info
1702 out->exceptions [exc_index].managed_exc_type = inner_exc->object.vtable->klass;
1703 out->exceptions [exc_index].num_managed_frames = data.num_frames;
1705 // Continue to traverse nesting of exceptions
1706 inner_exc = (MonoException *) inner_exc->inner_ex;
1709 out->num_exceptions = exc_index;
1713 static void
1714 mono_summarize_managed_stack (MonoThreadSummary *out)
1716 MonoSummarizeUserData data;
1717 memset (&data, 0, sizeof (MonoSummarizeUserData));
1718 data.max_frames = MONO_MAX_SUMMARY_FRAMES;
1719 data.num_frames = 0;
1720 data.frames = out->managed_frames;
1721 data.hashes = &out->hashes;
1723 // FIXME: collect stack pointer for both and sort frames by SP
1724 // so people can see relative ordering of both managed and unmanaged frames.
1727 // Summarize managed stack
1729 mono_walk_stack_full (summarize_frame, out->ctx, out->domain, out->jit_tls, out->lmf, MONO_UNWIND_LOOKUP_IL_OFFSET, &data, TRUE);
1730 out->num_managed_frames = data.num_frames;
1732 if (data.error != NULL)
1733 out->error_msg = data.error;
1734 out->is_managed = (out->num_managed_frames != 0);
1737 // Always runs on the dumped thread
1738 static void
1739 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1741 MONO_ARCH_CONTEXT_DEF
1743 // Summarize unmanaged stack
1745 #ifdef HAVE_BACKTRACE_SYMBOLS
1746 intptr_t frame_ips [MONO_MAX_SUMMARY_FRAMES];
1748 out->num_unmanaged_frames = backtrace ((void **)frame_ips, MONO_MAX_SUMMARY_FRAMES);
1750 for (int i =0; i < out->num_unmanaged_frames; ++i) {
1751 intptr_t ip = frame_ips [i];
1752 MonoFrameSummary *frame = &out->unmanaged_frames [i];
1754 int success = mono_get_portable_ip (ip, &frame->unmanaged_data.ip, &frame->unmanaged_data.offset, &frame->unmanaged_data.module, (char *) frame->str_descr);
1755 if (!success)
1756 continue;
1758 if (out->unmanaged_frames [i].str_descr [0] != '\0')
1759 out->unmanaged_frames [i].unmanaged_data.has_name = TRUE;
1761 #endif
1763 out->lmf = mono_get_lmf ();
1765 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1766 out->info_addr = (intptr_t) thread;
1767 out->jit_tls = thread->jit_data;
1768 out->domain = mono_domain_get ();
1770 if (!out->ctx) {
1771 out->ctx = &out->ctx_mem;
1772 mono_arch_flush_register_windows ();
1773 MONO_INIT_CONTEXT_FROM_FUNC (out->ctx, mono_summarize_unmanaged_stack);
1776 return;
1778 #endif
1781 MonoBoolean
1782 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
1783 MonoReflectionMethod **method,
1784 gint32 *iloffset, gint32 *native_offset,
1785 MonoString **file, gint32 *line, gint32 *column)
1787 ERROR_DECL (error);
1788 MonoDomain *domain = mono_domain_get ();
1789 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1790 MonoLMF *lmf = mono_get_lmf ();
1791 MonoJitInfo *ji = NULL;
1792 MonoContext ctx, new_ctx;
1793 MonoDebugSourceLocation *location;
1794 MonoMethod *jmethod = NULL, *actual_method;
1795 StackFrameInfo frame;
1796 gboolean res;
1797 Unwinder unwinder;
1798 int il_offset = -1;
1800 MONO_ARCH_CONTEXT_DEF;
1802 g_assert (skip >= 0);
1804 if (mono_llvm_only) {
1805 GSList *l, *ips;
1806 MonoDomain *frame_domain;
1807 guint8 *frame_ip = NULL;
1809 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1810 jmethod = NULL;
1811 ips = get_unwind_backtrace ();
1812 for (l = ips; l && skip >= 0; l = l->next) {
1813 guint8 *ip = (guint8*)l->data;
1815 frame_ip = ip;
1817 ji = mini_jit_info_table_find (mono_domain_get (), ip, &frame_domain);
1818 if (!ji || ji->is_trampoline)
1819 continue;
1821 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1822 jmethod = jinfo_get_method (ji);
1823 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1824 continue;
1825 skip--;
1827 g_slist_free (ips);
1828 if (!jmethod || !l)
1829 return FALSE;
1830 /* No way to resolve generic instances */
1831 actual_method = jmethod;
1832 *native_offset = frame_ip - (guint8*)ji->code_start;
1833 } else {
1834 mono_arch_flush_register_windows ();
1835 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
1837 unwinder_init (&unwinder);
1839 new_ctx = ctx;
1840 do {
1841 ctx = new_ctx;
1842 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1843 if (!res)
1844 return FALSE;
1845 switch (frame.type) {
1846 case FRAME_TYPE_MANAGED_TO_NATIVE:
1847 case FRAME_TYPE_DEBUGGER_INVOKE:
1848 case FRAME_TYPE_TRAMPOLINE:
1849 case FRAME_TYPE_INTERP_TO_MANAGED:
1850 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
1851 continue;
1852 case FRAME_TYPE_INTERP:
1853 case FRAME_TYPE_MANAGED:
1854 ji = frame.ji;
1855 *native_offset = frame.native_offset;
1857 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1858 jmethod = jinfo_get_method (ji);
1859 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1860 continue;
1861 skip--;
1862 break;
1863 default:
1864 g_assert_not_reached ();
1866 } while (skip >= 0);
1868 if (frame.type == FRAME_TYPE_INTERP) {
1869 jmethod = frame.method;
1870 actual_method = frame.actual_method;
1871 } else {
1872 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
1876 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, error);
1877 if (!is_ok (error)) {
1878 mono_error_set_pending_exception (error);
1879 return FALSE;
1881 mono_gc_wbarrier_generic_store_internal (method, (MonoObject*) rm);
1883 if (il_offset != -1) {
1884 location = mono_debug_lookup_source_location_by_il (jmethod, il_offset, domain);
1885 } else {
1886 location = mono_debug_lookup_source_location (jmethod, *native_offset, domain);
1888 if (location)
1889 *iloffset = location->il_offset;
1890 else
1891 *iloffset = 0;
1893 if (need_file_info) {
1894 if (location) {
1895 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1896 if (!is_ok (error)) {
1897 mono_error_set_pending_exception (error);
1898 return FALSE;
1900 mono_gc_wbarrier_generic_store_internal (file, (MonoObject*)filename);
1901 *line = location->row;
1902 *column = location->column;
1903 } else {
1904 *file = NULL;
1905 *line = *column = 0;
1909 mono_debug_free_source_location (location);
1911 return TRUE;
1914 static MonoClass*
1915 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1917 ERROR_DECL (error);
1918 MonoClass *catch_class = ei->data.catch_class;
1919 MonoType *inflated_type;
1920 MonoGenericContext context;
1922 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1923 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
1924 return NULL;
1926 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1927 return catch_class;
1928 context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1930 /* FIXME: we shouldn't inflate but instead put the
1931 type in the rgctx and fetch it from there. It
1932 might be a good idea to do this lazily, i.e. only
1933 when the exception is actually thrown, so as not to
1934 waste space for exception clauses which might never
1935 be encountered. */
1936 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
1937 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1939 catch_class = mono_class_from_mono_type_internal (inflated_type);
1940 mono_metadata_free_type (inflated_type);
1942 return catch_class;
1946 * mini_jit_info_table_find_ext:
1948 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1949 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1950 * OUT_DOMAIN if it is not NULL.
1952 MonoJitInfo*
1953 mini_jit_info_table_find_ext (MonoDomain *domain, gpointer addr, gboolean allow_trampolines, MonoDomain **out_domain)
1955 MonoJitInfo *ji;
1956 MonoInternalThread *t = mono_thread_internal_current ();
1957 gpointer *refs;
1959 if (out_domain)
1960 *out_domain = NULL;
1962 ji = mono_jit_info_table_find_internal (domain, addr, TRUE, allow_trampolines);
1963 if (ji) {
1964 if (out_domain)
1965 *out_domain = domain;
1966 return ji;
1969 /* maybe it is shared code, so we also search in the root domain */
1970 if (domain != mono_get_root_domain ()) {
1971 ji = mono_jit_info_table_find_internal (mono_get_root_domain (), addr, TRUE, allow_trampolines);
1972 if (ji) {
1973 if (out_domain)
1974 *out_domain = mono_get_root_domain ();
1975 return ji;
1979 if (!t)
1980 return NULL;
1982 refs = (gpointer *)((t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL);
1983 for (; refs && *refs; refs++) {
1984 if (*refs != domain && *refs != mono_get_root_domain ()) {
1985 ji = mono_jit_info_table_find_internal ((MonoDomain*) *refs, addr, TRUE, allow_trampolines);
1986 if (ji) {
1987 if (out_domain)
1988 *out_domain = (MonoDomain*) *refs;
1989 return ji;
1994 return NULL;
1997 MonoJitInfo*
1998 mini_jit_info_table_find (MonoDomain *domain, gpointer addr, MonoDomain **out_domain)
2000 return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain);
2003 /* Class lazy loading functions */
2004 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
2007 * wrap_non_exception_throws:
2009 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
2010 * WrapNonExceptionThrows flag set.
2012 static gboolean
2013 wrap_non_exception_throws (MonoMethod *m)
2015 ERROR_DECL (error);
2016 MonoAssembly *ass = m_class_get_image (m->klass)->assembly;
2017 MonoCustomAttrInfo* attrs;
2018 MonoClass *klass;
2019 int i;
2020 gboolean val = FALSE;
2022 if (m->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
2023 MonoDynamicMethod *dm = (MonoDynamicMethod *)m;
2024 if (dm->assembly)
2025 ass = dm->assembly;
2027 g_assert (ass);
2028 if (ass->wrap_non_exception_throws_inited)
2029 return ass->wrap_non_exception_throws;
2031 klass = mono_class_get_runtime_compat_attr_class ();
2033 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, error);
2034 mono_error_cleanup (error); /* FIXME don't swallow the error */
2035 if (attrs) {
2036 for (i = 0; i < attrs->num_attrs; ++i) {
2037 MonoCustomAttrEntry *attr = &attrs->attrs [i];
2038 const gchar *p;
2039 int num_named, named_type, name_len;
2040 char *name;
2042 if (!attr->ctor || attr->ctor->klass != klass)
2043 continue;
2044 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2045 p = (const char*)attr->data;
2046 g_assert (read16 (p) == 0x0001);
2047 p += 2;
2048 num_named = read16 (p);
2049 if (num_named != 1)
2050 continue;
2051 p += 2;
2052 named_type = *p;
2053 p ++;
2054 /* data_type = *p; */
2055 p ++;
2056 /* Property */
2057 if (named_type != 0x54)
2058 continue;
2059 name_len = mono_metadata_decode_blob_size (p, &p);
2060 name = (char *)g_malloc (name_len + 1);
2061 memcpy (name, p, name_len);
2062 name [name_len] = 0;
2063 p += name_len;
2064 g_assert (!strcmp (name, "WrapNonExceptionThrows"));
2065 g_free (name);
2066 /* The value is a BOOLEAN */
2067 val = *p;
2069 mono_custom_attrs_free (attrs);
2072 ass->wrap_non_exception_throws = val;
2073 mono_memory_barrier ();
2074 ass->wrap_non_exception_throws_inited = TRUE;
2076 return val;
2079 #define MAX_UNMANAGED_BACKTRACE 128
2080 static MonoArray*
2081 build_native_trace (MonoError *error)
2083 error_init (error);
2084 /* This puppy only makes sense on mobile, IOW, ARM. */
2085 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2086 MonoArray *res;
2087 void *native_trace [MAX_UNMANAGED_BACKTRACE];
2088 int size = -1;
2089 MONO_ENTER_GC_SAFE;
2090 size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE);
2091 MONO_EXIT_GC_SAFE;
2092 int i;
2094 if (!size)
2095 return NULL;
2096 res = mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, size, error);
2097 return_val_if_nok (error, NULL);
2099 for (i = 0; i < size; i++)
2100 mono_array_set_internal (res, gpointer, i, native_trace [i]);
2101 return res;
2102 #else
2103 return NULL;
2104 #endif
2107 static void
2108 remove_wrappers_from_trace (GList **trace_ips_p)
2110 GList *trace_ips = *trace_ips_p;
2111 GList *p = trace_ips;
2113 /* jit info, generic info, ip */
2114 while (p) {
2115 MonoJitInfo *jinfo = (MonoJitInfo*) p->data;
2116 GList *next_p = p->next->next->next;
2117 /* FIXME Maybe remove more wrapper types */
2118 if (jinfo->d.method->wrapper_type == MONO_WRAPPER_OTHER) {
2119 trace_ips = g_list_delete_link (trace_ips, p->next->next);
2120 trace_ips = g_list_delete_link (trace_ips, p->next);
2121 trace_ips = g_list_delete_link (trace_ips, p);
2123 p = next_p;
2126 *trace_ips_p = trace_ips;
2129 /* This can be called more than once on a MonoException. */
2130 static void
2131 setup_stack_trace (MonoException *mono_ex, GSList **dynamic_methods, GList *trace_ips, gboolean remove_wrappers)
2133 if (mono_ex) {
2134 GList *trace_ips_copy = g_list_copy (trace_ips);
2135 if (remove_wrappers)
2136 remove_wrappers_from_trace (&trace_ips_copy);
2137 trace_ips_copy = g_list_reverse (trace_ips_copy);
2138 ERROR_DECL (error);
2139 MonoArray *ips_arr = mono_glist_to_array (trace_ips_copy, mono_defaults.int_class, error);
2140 mono_error_assert_ok (error);
2141 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
2142 MONO_OBJECT_SETREF_INTERNAL (mono_ex, native_trace_ips, build_native_trace (error));
2143 mono_error_assert_ok (error);
2144 if (*dynamic_methods) {
2145 /* These methods could go away anytime, so save a reference to them in the exception object */
2146 GSList *l;
2147 MonoMList *list = (MonoMList*)mono_ex->dynamic_methods;
2149 for (l = *dynamic_methods; l; l = l->next) {
2150 guint32 dis_link;
2151 MonoDomain *domain = mono_domain_get ();
2153 if (domain->method_to_dyn_method) {
2154 mono_domain_lock (domain);
2155 dis_link = (guint32)(size_t)g_hash_table_lookup (domain->method_to_dyn_method, l->data);
2156 mono_domain_unlock (domain);
2157 if (dis_link) {
2158 MonoObject *o = mono_gchandle_get_target_internal (dis_link);
2159 if (o) {
2160 list = mono_mlist_prepend_checked (list, o, error);
2161 mono_error_assert_ok (error);
2167 MONO_OBJECT_SETREF_INTERNAL (mono_ex, dynamic_methods, list);
2169 g_slist_free (*dynamic_methods);
2170 *dynamic_methods = NULL;
2173 g_list_free (trace_ips_copy);
2177 typedef enum {
2178 MONO_FIRST_PASS_UNHANDLED,
2179 MONO_FIRST_PASS_CALLBACK_TO_NATIVE,
2180 MONO_FIRST_PASS_HANDLED,
2181 } MonoFirstPassResult;
2184 * handle_exception_first_pass:
2186 * The first pass of exception handling. Unwind the stack until a catch
2187 * clause which can catch OBJ is found. Store the index of the filter clause
2188 * which caught the exception into OUT_FILTER_IDX. Return
2189 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2190 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2191 * wrapper and an exception handling callback is installed (in which case
2192 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2194 static MonoFirstPassResult
2195 handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception, StackFrameInfo *catch_frame)
2197 ERROR_DECL (error);
2198 MonoDomain *domain = mono_domain_get ();
2199 MonoJitInfo *ji = NULL;
2200 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2201 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2202 MonoLMF *lmf = mono_get_lmf ();
2203 GList *trace_ips = NULL;
2204 GSList *dynamic_methods = NULL;
2205 MonoException *mono_ex;
2206 gboolean stack_overflow = FALSE;
2207 MonoContext initial_ctx;
2208 MonoMethod *method;
2209 int frame_count = 0;
2210 gint32 filter_idx;
2211 int i;
2212 MonoObject *ex_obj;
2213 Unwinder unwinder;
2214 gboolean in_interp;
2216 MonoFirstPassResult result = MONO_FIRST_PASS_UNHANDLED;
2218 g_assert (ctx != NULL);
2220 if (obj == (MonoObject *)domain->stack_overflow_ex)
2221 stack_overflow = TRUE;
2223 mono_ex = (MonoException*)obj;
2224 MonoArray *initial_trace_ips = mono_ex->trace_ips;
2225 if (initial_trace_ips) {
2226 int len = mono_array_length_internal (initial_trace_ips) / TRACE_IP_ENTRY_SIZE;
2228 // If we catch in managed/non-wrapper, we don't save the catching frame
2229 if (!mono_ex->caught_in_unmanaged)
2230 len -= 1;
2232 for (i = 0; i < len; i++) {
2233 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
2234 gpointer p = mono_array_get_internal (initial_trace_ips, gpointer, (i * TRACE_IP_ENTRY_SIZE) + j);
2235 trace_ips = g_list_prepend (trace_ips, p);
2240 // Reset the state because we're making it be caught somewhere
2241 if (mono_ex->caught_in_unmanaged)
2242 MONO_OBJECT_SETREF_INTERNAL (mono_ex, caught_in_unmanaged, 0);
2244 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2245 mono_error_assert_ok (error);
2246 mono_ex = NULL;
2249 if (!call_filter)
2250 call_filter = (int (*) (MonoContext *, void *))mono_get_call_filter ();
2252 g_assert (jit_tls->end_of_stack);
2253 g_assert (jit_tls->abort_func);
2255 if (out_filter_idx)
2256 *out_filter_idx = -1;
2257 if (out_ji)
2258 *out_ji = NULL;
2259 if (out_prev_ji)
2260 *out_prev_ji = NULL;
2261 filter_idx = 0;
2262 initial_ctx = *ctx;
2264 unwinder_init (&unwinder);
2266 while (1) {
2267 MonoContext new_ctx;
2268 guint32 free_stack;
2269 int clause_index_start = 0;
2270 gboolean unwind_res = TRUE;
2272 StackFrameInfo frame;
2274 if (out_prev_ji)
2275 *out_prev_ji = ji;
2277 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2278 if (!unwind_res) {
2279 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, FALSE);
2280 g_list_free (trace_ips);
2281 return result;
2284 switch (frame.type) {
2285 case FRAME_TYPE_DEBUGGER_INVOKE:
2286 case FRAME_TYPE_MANAGED_TO_NATIVE:
2287 case FRAME_TYPE_TRAMPOLINE:
2288 case FRAME_TYPE_INTERP_TO_MANAGED:
2289 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2290 *ctx = new_ctx;
2291 continue;
2292 case FRAME_TYPE_INTERP:
2293 case FRAME_TYPE_MANAGED:
2294 break;
2295 default:
2296 g_assert_not_reached ();
2297 break;
2300 in_interp = frame.type == FRAME_TYPE_INTERP;
2301 ji = frame.ji;
2303 gpointer ip;
2304 if (in_interp)
2305 ip = (guint8*)ji->code_start + frame.native_offset;
2306 else
2307 ip = MONO_CONTEXT_GET_IP (ctx);
2309 frame_count ++;
2310 method = jinfo_get_method (ji);
2311 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2313 if (mini_debug_options.reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2314 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2315 "The native frame called the managed method:\n%s\n",
2316 mono_method_full_name (method, TRUE));
2319 if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
2320 // avoid giant stack traces during a stack overflow
2321 if (frame_count < 1000) {
2322 trace_ips = g_list_prepend (trace_ips, ip);
2323 trace_ips = g_list_prepend (trace_ips, get_generic_info_from_stack_frame (ji, ctx));
2324 trace_ips = g_list_prepend (trace_ips, ji);
2328 if (method->dynamic)
2329 dynamic_methods = g_slist_prepend (dynamic_methods, method);
2331 if (stack_overflow) {
2332 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2333 } else {
2334 free_stack = 0xffffff;
2337 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && ftnptr_eh_callback) {
2338 result = MONO_FIRST_PASS_CALLBACK_TO_NATIVE;
2342 for (i = clause_index_start; i < ji->num_clauses; i++) {
2343 MonoJitExceptionInfo *ei = &ji->clauses [i];
2344 gboolean filtered = FALSE;
2347 * During stack overflow, wait till the unwinding frees some stack
2348 * space before running handlers/finalizers.
2350 if (free_stack <= (64 * 1024))
2351 continue;
2353 if (is_address_protected (ji, ei, ip)) {
2354 /* catch block */
2355 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2358 * Have to unwrap RuntimeWrappedExceptions if the
2359 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2361 if (non_exception && !wrap_non_exception_throws (method))
2362 ex_obj = non_exception;
2363 else
2364 ex_obj = obj;
2366 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2367 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, FALSE);
2369 #ifndef DISABLE_PERFCOUNTERS
2370 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_filters);
2371 #endif
2373 if (!ji->is_interp) {
2374 #ifndef MONO_CROSS_COMPILE
2375 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2376 if (ji->from_llvm)
2377 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2378 else
2379 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2380 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2381 #else
2382 g_assert (!ji->from_llvm);
2383 /* store the exception object in bp + ei->exvar_offset */
2384 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2385 #endif
2386 #endif
2388 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2390 * Pass the original il clause index to the landing pad so it can
2391 * branch to the landing pad associated with the il clause.
2392 * This is needed because llvm compiled code assumes that the EH
2393 * code always branches to the innermost landing pad.
2395 if (ji->from_llvm)
2396 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2397 #endif
2400 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex, ctx, &initial_ctx);
2402 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2403 jit_tls->orig_ex_ctx_set = TRUE;
2404 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2405 jit_tls->orig_ex_ctx_set = FALSE;
2408 if (ji->is_interp) {
2409 /* The filter ends where the exception handler starts */
2410 filtered = mini_get_interp_callbacks ()->run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter, ei->handler_start);
2411 } else {
2412 filtered = call_filter (ctx, ei->data.filter);
2414 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex, ctx, &initial_ctx);
2415 if (filtered && out_filter_idx)
2416 *out_filter_idx = filter_idx;
2417 if (out_ji)
2418 *out_ji = ji;
2419 filter_idx ++;
2421 if (filtered) {
2422 g_list_free (trace_ips);
2423 /* mono_debugger_agent_handle_exception () needs this */
2424 mini_set_abort_threshold (&frame);
2425 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2426 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
2427 *catch_frame = frame;
2428 result = MONO_FIRST_PASS_HANDLED;
2429 return result;
2433 ERROR_DECL (isinst_error); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2434 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, error)) {
2435 /* runtime invokes catch even unhandled exceptions */
2436 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE);
2437 g_list_free (trace_ips);
2439 if (out_ji)
2440 *out_ji = ji;
2442 /* mono_debugger_agent_handle_exception () needs this */
2443 if (!in_interp)
2444 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2445 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
2446 *catch_frame = frame;
2447 result = MONO_FIRST_PASS_HANDLED;
2448 return result;
2450 mono_error_cleanup (isinst_error);
2454 *ctx = new_ctx;
2457 g_assert_not_reached ();
2461 * We implement delaying of aborts when in finally blocks by reusing the
2462 * abort protected block mechanism. The problem is that when throwing an
2463 * exception in a finally block we don't get to exit the protected block.
2464 * We exit it here when unwinding. Given that the order of the clauses
2465 * in the jit info is from inner clauses to the outer clauses, when we
2466 * want to exit the finally blocks inner to the clause that handles the
2467 * exception, we need to search up to its index.
2469 * FIXME We should do this inside interp, but with mixed mode we can
2470 * resume directly, without giving control back to the interp.
2472 static void
2473 interp_exit_finally_abort_blocks (MonoJitInfo *ji, int start_clause, int end_clause, gpointer ip)
2475 int i;
2476 for (i = start_clause; i < end_clause; i++) {
2477 MonoJitExceptionInfo *ei = &ji->clauses [i];
2478 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY &&
2479 ip >= ei->handler_start &&
2480 ip < ei->data.handler_end) {
2481 mono_threads_end_abort_protected_block ();
2486 static MonoException *
2487 mono_get_exception_runtime_wrapped_checked (MonoObject *wrapped_exception_raw, MonoError *error)
2489 HANDLE_FUNCTION_ENTER ();
2490 MONO_HANDLE_DCL (MonoObject, wrapped_exception);
2491 MonoExceptionHandle ret = mono_get_exception_runtime_wrapped_handle (wrapped_exception, error);
2492 HANDLE_FUNCTION_RETURN_OBJ (ret);
2496 * mono_handle_exception_internal:
2497 * \param ctx saved processor state
2498 * \param obj the exception object
2499 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2501 static gboolean
2502 mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji)
2504 ERROR_DECL (error);
2505 MonoDomain *domain = mono_domain_get ();
2506 MonoJitInfo *ji, *prev_ji;
2507 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2508 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2509 MonoLMF *lmf = mono_get_lmf ();
2510 MonoException *mono_ex;
2511 gboolean stack_overflow = FALSE;
2512 MonoContext initial_ctx;
2513 MonoMethod *method;
2514 int frame_count = 0;
2515 gint32 filter_idx, first_filter_idx = 0;
2516 int i;
2517 MonoObject *ex_obj = NULL;
2518 MonoObject *non_exception = NULL;
2519 Unwinder unwinder;
2520 gboolean in_interp;
2522 g_assert (ctx != NULL);
2523 if (!obj) {
2524 MonoException *ex = mono_get_exception_null_reference ();
2525 MonoString *msg = mono_string_new_checked (domain, "Object reference not set to an instance of an object", error);
2526 mono_error_assert_ok (error);
2527 MONO_OBJECT_SETREF_INTERNAL (ex, message, msg);
2528 obj = (MonoObject *)ex;
2532 * Allocate a new exception object instead of the preconstructed ones.
2534 if (obj == (MonoObject *)domain->stack_overflow_ex) {
2536 * It is not a good idea to try and put even more pressure on the little stack available.
2537 * obj = mono_get_exception_stack_overflow ();
2539 stack_overflow = TRUE;
2541 else if (obj == (MonoObject *)domain->null_reference_ex) {
2542 obj = (MonoObject *)mono_get_exception_null_reference ();
2545 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2546 mono_error_assert_ok (error);
2547 non_exception = obj;
2548 obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, error);
2549 mono_error_assert_ok (error);
2552 mono_ex = (MonoException*)obj;
2554 if (mini_debug_options.suspend_on_exception) {
2555 mono_runtime_printf_err ("Exception thrown, suspending...");
2556 while (1)
2560 if (mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2561 mono_ex = (MonoException*)obj;
2562 } else {
2563 mono_error_assert_ok (error);
2564 mono_ex = NULL;
2567 if (mono_ex && jit_tls->class_cast_from) {
2568 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "InvalidCastException")) {
2569 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
2570 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
2571 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
2572 mono_ex->message = mono_string_new_checked (domain, msg, error);
2573 g_free (from_name);
2574 g_free (to_name);
2575 if (!is_ok (error)) {
2576 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg);
2577 mono_error_assert_ok (error);
2579 g_free (msg);
2581 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "ArrayTypeMismatchException")) {
2582 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
2583 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
2584 char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
2585 mono_ex->message = mono_string_new_checked (domain, msg, error);
2586 g_free (from_name);
2587 g_free (to_name);
2588 if (!is_ok (error)) {
2589 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg);
2590 mono_error_assert_ok (error);
2592 g_free (msg);
2596 if (!call_filter)
2597 call_filter = (int (*)(MonoContext *, void*))mono_get_call_filter ();
2599 g_assert (jit_tls->end_of_stack);
2600 g_assert (jit_tls->abort_func);
2603 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2604 * end up being TRUE on any code path.
2606 memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
2608 if (!resume) {
2609 MonoContext ctx_cp = *ctx;
2610 if (mono_trace_is_enabled ()) {
2611 ERROR_DECL (error);
2612 MonoMethod *system_exception_get_message = mono_class_get_method_from_name_checked (mono_defaults.exception_class, "get_Message", 0, 0, error);
2613 mono_error_cleanup (error);
2614 error_init (error);
2615 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method_internal (obj, system_exception_get_message);
2616 MonoObject *message;
2617 const char *type_name = m_class_get_name (mono_object_class (mono_ex));
2618 char *msg = NULL;
2619 if (get_message == NULL) {
2620 message = NULL;
2621 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
2622 message = NULL;
2623 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
2624 } else {
2625 MonoObject *exc = NULL;
2626 message = mono_runtime_try_invoke (get_message, obj, NULL, &exc, error);
2627 g_assert (exc == NULL);
2628 mono_error_assert_ok (error);
2630 if (msg == NULL) {
2631 if (message) {
2632 msg = mono_string_to_utf8_checked_internal ((MonoString *) message, error);
2633 if (!is_ok (error)) {
2634 mono_error_cleanup (error);
2635 msg = g_strdup ("(error while display System.Exception.Message property)");
2637 } else {
2638 msg = g_strdup ("(System.Exception.Message property not available)");
2641 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)mono_native_thread_id_get (), m_class_get_name_space (mono_object_class (obj)), m_class_get_name (mono_object_class (obj)), msg);
2642 g_free (msg);
2643 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
2644 mono_print_thread_dump_from_ctx (ctx);
2646 jit_tls->orig_ex_ctx_set = TRUE;
2647 MONO_PROFILER_RAISE (exception_throw, (obj));
2648 jit_tls->orig_ex_ctx_set = FALSE;
2650 StackFrameInfo catch_frame;
2651 MonoFirstPassResult res;
2652 res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame);
2654 if (res == MONO_FIRST_PASS_UNHANDLED) {
2655 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2656 /* Reached the top interpreted frames, but there might be native frames above us */
2657 throw_exception (obj, TRUE);
2658 g_assert_not_reached ();
2660 if (mini_debug_options.break_on_exc)
2661 G_BREAKPOINT ();
2662 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2664 if (mini_debug_options.suspend_on_unhandled && mono_object_class (obj) != mono_defaults.threadabortexception_class) {
2665 mono_runtime_printf_err ("Unhandled exception, suspending...");
2666 while (1)
2670 // FIXME: This runs managed code so it might cause another stack overflow when
2671 // we are handling a stack overflow
2672 mini_set_abort_threshold (&catch_frame);
2673 mono_unhandled_exception_internal (obj);
2674 } else {
2675 gboolean unhandled = FALSE;
2678 * The exceptions caught by the mono_runtime_invoke_checked () calls
2679 * in the threadpool needs to be treated as unhandled (#669836).
2681 * FIXME: The check below is hackish, but its hard to distinguish
2682 * these runtime invoke calls from others in the runtime.
2684 if (ji && jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2685 if (prev_ji && jinfo_get_method (prev_ji) == mono_defaults.threadpool_perform_wait_callback_method)
2686 unhandled = TRUE;
2689 if (unhandled)
2690 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2691 else if (jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2692 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2693 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2695 else if (res != MONO_FIRST_PASS_CALLBACK_TO_NATIVE)
2696 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2700 if (out_ji)
2701 *out_ji = NULL;
2702 filter_idx = 0;
2703 initial_ctx = *ctx;
2705 unwinder_init (&unwinder);
2707 while (1) {
2708 MonoContext new_ctx;
2709 guint32 free_stack;
2710 int clause_index_start = 0;
2711 gboolean unwind_res = TRUE;
2712 StackFrameInfo frame;
2713 gpointer ip;
2715 if (resume) {
2716 resume = FALSE;
2717 ji = jit_tls->resume_state.ji;
2718 new_ctx = jit_tls->resume_state.new_ctx;
2719 clause_index_start = jit_tls->resume_state.clause_index;
2720 lmf = jit_tls->resume_state.lmf;
2721 first_filter_idx = jit_tls->resume_state.first_filter_idx;
2722 filter_idx = jit_tls->resume_state.filter_idx;
2723 in_interp = FALSE;
2724 } else {
2725 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2726 if (!unwind_res) {
2727 *(mono_get_lmf_addr ()) = lmf;
2729 jit_tls->abort_func (obj);
2730 g_assert_not_reached ();
2732 switch (frame.type) {
2733 case FRAME_TYPE_DEBUGGER_INVOKE:
2734 case FRAME_TYPE_MANAGED_TO_NATIVE:
2735 case FRAME_TYPE_TRAMPOLINE:
2736 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2737 *ctx = new_ctx;
2738 continue;
2739 case FRAME_TYPE_INTERP_TO_MANAGED:
2740 continue;
2741 case FRAME_TYPE_INTERP:
2742 case FRAME_TYPE_MANAGED:
2743 break;
2744 default:
2745 g_assert_not_reached ();
2746 break;
2748 in_interp = frame.type == FRAME_TYPE_INTERP;
2749 ji = frame.ji;
2752 if (in_interp)
2753 ip = (guint8*)ji->code_start + frame.native_offset;
2754 else
2755 ip = MONO_CONTEXT_GET_IP (ctx);
2757 method = jinfo_get_method (ji);
2758 frame_count ++;
2759 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2761 if (stack_overflow) {
2762 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2763 } else {
2764 free_stack = 0xffffff;
2767 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && ftnptr_eh_callback) {
2768 guint32 handle = mono_gchandle_new_internal (obj, FALSE);
2769 MONO_STACKDATA (stackptr);
2771 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr);
2772 mono_set_lmf (lmf);
2773 ftnptr_eh_callback (handle);
2774 g_error ("Did not expect ftnptr_eh_callback to return.");
2777 for (i = clause_index_start; i < ji->num_clauses; i++) {
2778 MonoJitExceptionInfo *ei = &ji->clauses [i];
2779 gboolean filtered = FALSE;
2782 * During stack overflow, wait till the unwinding frees some stack
2783 * space before running handlers/finalizers.
2785 if (free_stack <= (64 * 1024))
2786 continue;
2788 if (is_address_protected (ji, ei, ip)) {
2789 /* catch block */
2790 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2793 * Have to unwrap RuntimeWrappedExceptions if the
2794 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2796 if (non_exception && !wrap_non_exception_throws (method))
2797 ex_obj = non_exception;
2798 else
2799 ex_obj = obj;
2801 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
2802 #ifndef MONO_CROSS_COMPILE
2803 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2804 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2805 #else
2806 g_assert (!ji->from_llvm);
2807 /* store the exception object in bp + ei->exvar_offset */
2808 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2809 #endif
2810 #endif
2813 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2814 if (ji->from_llvm)
2815 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2816 #endif
2818 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2820 * Filter clauses should only be run in the
2821 * first pass of exception handling.
2823 filtered = (filter_idx == first_filter_idx);
2824 filter_idx ++;
2827 error_init (error);
2828 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
2829 mono_object_isinst_checked (ex_obj, catch_class, error)) || filtered) {
2831 * This guards against the situation that we abort a thread that is executing a finally clause
2832 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2833 * check for this situation here and resume interruption if we are below the guarded block.
2835 if (G_UNLIKELY (jit_tls->handler_block)) {
2836 gboolean is_outside = FALSE;
2837 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
2838 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
2839 //FIXME make this stack direction aware
2841 if (catch_bp > prot_bp) {
2842 is_outside = TRUE;
2843 } else if (catch_bp == prot_bp) {
2844 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2845 * So we check if the catch handler_start is protected by the guarded handler protected region
2847 * Assumptions:
2848 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2849 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2850 * There aren't any further finally/fault handler blocks down the stack over this exception.
2851 * This must be ensured by the code that installs the guard trampoline.
2853 g_assert (ji == mini_jit_info_table_find (domain, (char *)MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
2855 if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
2856 is_outside = TRUE;
2859 if (is_outside) {
2860 jit_tls->handler_block = NULL;
2861 mono_thread_resume_interruption (TRUE); /*We ignore the exception here, it will be raised later*/
2865 if (mono_trace_is_enabled () && mono_trace_eval (method))
2866 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2869 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2870 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2871 * clause. Since we specifically want to indicate that we're executing the
2872 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2873 * instead of ei->flags.
2875 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2876 jit_tls->orig_ex_ctx_set = TRUE;
2877 MONO_PROFILER_RAISE (exception_clause, (method, i, MONO_EXCEPTION_CLAUSE_NONE, ex_obj));
2878 jit_tls->orig_ex_ctx_set = FALSE;
2881 mini_set_abort_threshold (&frame);
2883 if (in_interp) {
2884 interp_exit_finally_abort_blocks (ji, clause_index_start, i, ip);
2886 * ctx->pc points into the interpreter, after the call which transitioned to
2887 * JITted code. Store the unwind state into the
2888 * interpeter state, then resume, the interpreter will unwind itself until
2889 * it reaches the target frame and will continue execution from there.
2890 * The resuming is kinda hackish, from the native code standpoint, it looks
2891 * like the call which transitioned to JITted code has succeeded, but the
2892 * return value register etc. is not set, so we have to be careful.
2894 mini_get_interp_callbacks ()->set_resume_state (jit_tls, mono_ex, ei, frame.interp_frame, ei->handler_start);
2895 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2896 /* ip == 0 means an interpreter frame */
2897 if (MONO_CONTEXT_GET_IP (ctx) != 0)
2898 mono_arch_undo_ip_adjustment (ctx);
2899 } else {
2900 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2902 mono_set_lmf (lmf);
2903 #ifndef DISABLE_PERFCOUNTERS
2904 mono_atomic_fetch_add_i32 (&mono_perfcounters->exceptions_depth, frame_count);
2905 #endif
2906 if (obj == (MonoObject *)domain->stack_overflow_ex)
2907 jit_tls->handling_stack_ovf = FALSE;
2909 return 0;
2911 mono_error_cleanup (error);
2912 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
2913 if (mono_trace_is_enabled () && mono_trace_eval (method))
2914 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2916 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2917 jit_tls->orig_ex_ctx_set = TRUE;
2918 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2919 jit_tls->orig_ex_ctx_set = FALSE;
2922 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2923 if (mono_trace_is_enabled () && mono_trace_eval (method))
2924 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2926 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2927 jit_tls->orig_ex_ctx_set = TRUE;
2928 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2929 jit_tls->orig_ex_ctx_set = FALSE;
2932 #ifndef DISABLE_PERFCOUNTERS
2933 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_finallys);
2934 #endif
2936 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2937 mono_set_lmf (lmf);
2938 if (ji->from_llvm) {
2940 * LLVM compiled finally handlers follow the design
2941 * of the c++ ehabi, i.e. they call a resume function
2942 * at the end instead of returning to the caller.
2943 * So save the exception handling state,
2944 * mono_resume_unwind () will call us again to continue
2945 * the unwinding.
2947 jit_tls->resume_state.ex_obj = obj;
2948 jit_tls->resume_state.ji = ji;
2949 jit_tls->resume_state.clause_index = i + 1;
2950 jit_tls->resume_state.ctx = *ctx;
2951 jit_tls->resume_state.new_ctx = new_ctx;
2952 jit_tls->resume_state.lmf = lmf;
2953 jit_tls->resume_state.first_filter_idx = first_filter_idx;
2954 jit_tls->resume_state.filter_idx = filter_idx;
2955 mini_set_abort_threshold (&frame);
2956 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2957 return 0;
2958 } else {
2959 mini_set_abort_threshold (&frame);
2960 if (in_interp) {
2961 gboolean has_ex = mini_get_interp_callbacks ()->run_finally (&frame, i, ei->handler_start, ei->data.handler_end);
2962 if (has_ex) {
2964 * If run_finally didn't resume to a context, it means that the handler frame
2965 * is linked to the frame calling finally through interpreter frames. This
2966 * means that we will reach the handler frame by resuming the current context.
2968 if (MONO_CONTEXT_GET_IP (ctx) != 0)
2969 mono_arch_undo_ip_adjustment (ctx);
2970 return 0;
2972 } else {
2973 call_filter (ctx, ei->handler_start);
2980 if (in_interp)
2981 interp_exit_finally_abort_blocks (ji, clause_index_start, ji->num_clauses, ip);
2983 if (MONO_PROFILER_ENABLED (method_exception_leave) &&
2984 mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) {
2985 jit_tls->orig_ex_ctx_set = TRUE;
2986 MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
2987 jit_tls->orig_ex_ctx_set = FALSE;
2990 *ctx = new_ctx;
2993 g_assert_not_reached ();
2997 * mono_debugger_run_finally:
2998 * \param start_ctx saved processor state
2999 * This method is called by the Mono Debugger to call all \c finally clauses of the
3000 * current stack frame. It's used when the user issues a \c return command to make
3001 * the current stack frame return. After returning from this method, the debugger
3002 * unwinds the stack one frame and gives control back to the user.
3003 * NOTE: This method is only used when running inside the Mono Debugger.
3005 void
3006 mono_debugger_run_finally (MonoContext *start_ctx)
3008 static int (*call_filter) (MonoContext *, gpointer) = NULL;
3009 MonoDomain *domain = mono_domain_get ();
3010 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3011 MonoLMF *lmf = mono_get_lmf ();
3012 MonoContext ctx, new_ctx;
3013 MonoJitInfo *ji, rji;
3014 int i;
3016 ctx = *start_ctx;
3018 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
3019 if (!ji || ji == (gpointer)-1)
3020 return;
3022 if (!call_filter)
3023 call_filter = (int (*)(MonoContext *, void *))mono_get_call_filter ();
3025 for (i = 0; i < ji->num_clauses; i++) {
3026 MonoJitExceptionInfo *ei = &ji->clauses [i];
3028 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
3029 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
3030 call_filter (&ctx, ei->handler_start);
3036 * mono_handle_exception:
3037 * \param ctx saved processor state
3038 * \param obj the exception object
3040 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3041 * return TRUE.
3043 gboolean
3044 mono_handle_exception (MonoContext *ctx, gpointer void_obj)
3046 MonoObject *obj = (MonoObject*)void_obj;
3048 MONO_REQ_GC_UNSAFE_MODE;
3050 #ifndef DISABLE_PERFCOUNTERS
3051 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_thrown);
3052 #endif
3054 return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
3057 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3059 #ifndef MONO_ARCH_USE_SIGACTION
3060 #error "Can't use sigaltstack without sigaction"
3061 #endif
3063 void
3064 mono_setup_altstack (MonoJitTlsData *tls)
3066 size_t stsize = 0;
3067 stack_t sa;
3068 guint8 *staddr = NULL;
3069 #if defined(TARGET_OSX) || defined(_AIX)
3071 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3072 * stack pages. Stack overflow on main thread will kill the app.
3074 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3075 * do this for thread 1 with its stack at the top of memory. Other threads seem
3076 * fine for the altstack guard page, though.
3078 gboolean disable_stack_guard = mono_threads_platform_is_main_thread ();
3079 #else
3080 gboolean disable_stack_guard = FALSE;
3081 #endif
3083 if (mono_running_on_valgrind ())
3084 return;
3086 mono_thread_info_get_stack_bounds (&staddr, &stsize);
3088 g_assert (staddr);
3090 tls->end_of_stack = staddr + stsize;
3091 tls->stack_size = stsize;
3093 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3095 if (!disable_stack_guard) {
3096 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
3097 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
3099 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
3101 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
3102 /* mprotect can fail for the main thread stack */
3103 gpointer gaddr = mono_valloc (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON|MONO_MMAP_FIXED, MONO_MEM_ACCOUNT_EXCEPTIONS);
3104 if (gaddr) {
3105 g_assert (gaddr == tls->stack_ovf_guard_base);
3106 tls->stack_ovf_valloced = TRUE;
3107 } else {
3108 g_warning ("couldn't allocate guard page, continue without it");
3109 tls->stack_ovf_guard_base = NULL;
3110 tls->stack_ovf_guard_size = 0;
3115 /* Setup an alternate signal stack */
3116 tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON, MONO_MEM_ACCOUNT_EXCEPTIONS);
3117 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3119 g_assert (tls->signal_stack);
3121 sa.ss_sp = tls->signal_stack;
3122 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3123 sa.ss_flags = 0;
3124 g_assert (sigaltstack (&sa, NULL) == 0);
3126 if (tls->stack_ovf_guard_base)
3127 mono_gc_register_altstack ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size, (char*)staddr + stsize - ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size), tls->signal_stack, tls->signal_stack_size);
3128 else
3129 mono_gc_register_altstack (staddr, stsize, tls->signal_stack, tls->signal_stack_size);
3133 void
3134 mono_free_altstack (MonoJitTlsData *tls)
3136 stack_t sa;
3137 int err;
3139 sa.ss_sp = tls->signal_stack;
3140 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3141 sa.ss_flags = SS_DISABLE;
3142 err = sigaltstack (&sa, NULL);
3143 g_assert (err == 0);
3145 if (tls->signal_stack)
3146 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MEM_ACCOUNT_EXCEPTIONS);
3148 if (!tls->stack_ovf_guard_base)
3149 return;
3150 if (tls->stack_ovf_valloced)
3151 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MEM_ACCOUNT_EXCEPTIONS);
3152 else
3153 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3156 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3158 void
3159 mono_setup_altstack (MonoJitTlsData *tls)
3163 void
3164 mono_free_altstack (MonoJitTlsData *tls)
3168 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3170 gboolean
3171 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
3173 if (!jit_tls)
3174 return FALSE;
3176 if (mono_llvm_only)
3177 return FALSE;
3179 /* we got a stack overflow in the soft-guard pages
3180 * There are two cases:
3181 * 1) managed code caused the overflow: we unprotect the soft-guard page
3182 * and let the arch-specific code trigger the exception handling mechanism
3183 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3184 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3185 * and hope we can continue with those enabled, at least until the hard-guard page
3186 * is hit. The alternative to continuing here is to just print a message and abort.
3187 * We may add in the future the code to protect the pages again in the codepath
3188 * when we return from unmanaged to managed code.
3190 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
3191 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
3192 gboolean handled = FALSE;
3194 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3195 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3196 if (ji) {
3197 mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE);
3198 handled = TRUE;
3200 #endif
3201 if (!handled) {
3202 /* We print a message: after this even managed stack overflows
3203 * may crash the runtime
3205 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
3206 if (!jit_tls->handling_stack_ovf) {
3207 jit_tls->handling_stack_ovf = 1;
3208 } else {
3209 /*fprintf (stderr, "Already handling stack overflow\n");*/
3212 return TRUE;
3214 return FALSE;
3217 typedef struct {
3218 MonoMethod *omethod;
3219 int count;
3220 } PrintOverflowUserData;
3222 static gboolean
3223 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3225 MonoMethod *method = NULL;
3226 PrintOverflowUserData *user_data = (PrintOverflowUserData *)data;
3227 gchar *location;
3229 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3230 method = jinfo_get_method (frame->ji);
3232 if (method) {
3233 if (user_data->count == 0) {
3234 /* The first frame is in its prolog, so a line number cannot be computed */
3235 user_data->count ++;
3236 return FALSE;
3239 /* If this is a one method overflow, skip the other instances */
3240 if (method == user_data->omethod)
3241 return FALSE;
3243 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
3244 mono_runtime_printf_err (" %s", location);
3245 g_free (location);
3247 if (user_data->count == 1) {
3248 mono_runtime_printf_err (" <...>");
3249 user_data->omethod = method;
3250 } else {
3251 user_data->omethod = NULL;
3254 user_data->count ++;
3255 } else
3256 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame->native_offset);
3258 return FALSE;
3261 void
3262 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *mctx, guint8* fault_addr)
3264 PrintOverflowUserData ud;
3266 /* we don't do much now, but we can warn the user with a useful message */
3267 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx), fault_addr);
3269 mono_runtime_printf_err ("Stacktrace:");
3271 memset (&ud, 0, sizeof (ud));
3273 mono_walk_stack_with_ctx (print_overflow_stack_frame, mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
3275 _exit (1);
3278 static gboolean
3279 print_stack_frame_signal_safe (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3281 MonoMethod *method = NULL;
3283 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3284 method = jinfo_get_method (frame->ji);
3286 if (method) {
3287 const char *name_space = m_class_get_name_space (method->klass);
3288 g_async_safe_printf("\t at %s%s%s:%s <0x%05x>\n", name_space, (name_space [0] != '\0' ? "." : ""), m_class_get_name (method->klass), method->name, frame->native_offset);
3289 } else {
3290 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame->native_offset);
3293 return FALSE;
3296 static G_GNUC_UNUSED gboolean
3297 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3299 GString *p = (GString*)data;
3300 MonoMethod *method = NULL;
3302 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3303 method = jinfo_get_method (frame->ji);
3305 if (method && frame->domain) {
3306 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3307 g_string_append_printf (p, " %s\n", location);
3308 g_free (location);
3309 } else
3310 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3312 return FALSE;
3315 #ifndef MONO_CROSS_COMPILE
3316 static gboolean handle_crash_loop = FALSE;
3319 * mono_handle_native_crash:
3321 * Handle a native crash (e.g. SIGSEGV) while in native code by
3322 * printing diagnostic information and aborting.
3324 void
3325 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3327 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3329 if (handle_crash_loop)
3330 return;
3332 if (mini_debug_options.suspend_on_native_crash) {
3333 g_async_safe_printf ("Received %s, suspending...\n", signal);
3334 while (1) {
3335 // Sleep for 1 second.
3336 g_usleep (1000 * 1000);
3340 /* prevent infinite loops in crash handling */
3341 handle_crash_loop = TRUE;
3344 * A SIGSEGV indicates something went very wrong so we can no longer depend
3345 * on anything working. So try to print out lots of diagnostics, starting
3346 * with ones which have a greater chance of working.
3349 g_async_safe_printf("\n=================================================================\n");
3350 g_async_safe_printf("\tNative Crash Reporting\n");
3351 g_async_safe_printf("=================================================================\n");
3352 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal);
3353 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3354 g_async_safe_printf("used by your application.\n");
3355 g_async_safe_printf("=================================================================\n");
3356 mono_dump_native_crash_info (signal, mctx, info);
3358 /* !jit_tls means the thread was not registered with the runtime */
3359 // This must be below the native crash dump, because we can't safely
3360 // do runtime state probing after we have walked the managed stack here.
3361 if (jit_tls && mono_thread_internal_current () && mctx) {
3362 g_async_safe_printf ("\n=================================================================\n");
3363 g_async_safe_printf ("\tManaged Stacktrace:\n");
3364 g_async_safe_printf ("=================================================================\n");
3366 mono_walk_stack_full (print_stack_frame_signal_safe, mctx, mono_domain_get (), jit_tls, mono_get_lmf (), MONO_UNWIND_LOOKUP_IL_OFFSET, NULL, TRUE);
3367 g_async_safe_printf ("=================================================================\n");
3370 #ifdef MONO_ARCH_USE_SIGACTION
3371 struct sigaction sa;
3372 sa.sa_handler = SIG_DFL;
3373 sigemptyset (&sa.sa_mask);
3374 sa.sa_flags = 0;
3376 /* Remove our SIGABRT handler */
3377 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
3379 /* On some systems we get a SIGILL when calling abort (), because it might
3380 * fail to raise SIGABRT */
3381 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
3382 #endif
3384 mono_post_native_crash_handler (signal, mctx, info, mono_do_crash_chaining);
3387 #else
3389 void
3390 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3392 g_assert_not_reached ();
3395 #endif /* !MONO_CROSS_COMPILE */
3397 static void
3398 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
3400 MonoInternalThread *thread = mono_thread_internal_current ();
3401 MonoContext ctx;
3402 GString* text;
3404 if (!thread)
3405 return;
3407 text = g_string_new (0);
3409 mono_gstring_append_thread_name (text, thread);
3411 g_string_append_printf (text, " tid=%p this=%p ", (gpointer)(gsize)thread->tid, thread);
3412 mono_thread_internal_describe (thread, text);
3413 g_string_append (text, "\n");
3415 if (start_ctx) {
3416 memcpy (&ctx, start_ctx, sizeof (MonoContext));
3417 } else if (!sigctx)
3418 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
3419 else
3420 mono_sigctx_to_monoctx (sigctx, &ctx);
3422 mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
3424 mono_runtime_printf ("%s", text->str);
3426 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3427 OutputDebugStringA(text->str);
3428 #endif
3430 g_string_free (text, TRUE);
3431 mono_runtime_stdout_fflush ();
3435 * mono_print_thread_dump:
3437 * Print information about the current thread to stdout.
3438 * \p sigctx can be NULL, allowing this to be called from gdb.
3440 void
3441 mono_print_thread_dump (void *sigctx)
3443 mono_print_thread_dump_internal (sigctx, NULL);
3446 void
3447 mono_print_thread_dump_from_ctx (MonoContext *ctx)
3449 mono_print_thread_dump_internal (NULL, ctx);
3453 * mono_resume_unwind:
3455 * This is called by a trampoline from LLVM compiled finally clauses to continue
3456 * unwinding.
3458 void
3459 mono_resume_unwind (MonoContext *ctx)
3461 MONO_REQ_GC_UNSAFE_MODE;
3463 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3464 MonoContext new_ctx;
3466 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
3467 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
3468 new_ctx = *ctx;
3470 mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL);
3472 mono_restore_context (&new_ctx);
3475 typedef struct {
3476 MonoJitInfo *ji;
3477 MonoContext ctx;
3478 MonoJitExceptionInfo *ei;
3479 } FindHandlerBlockData;
3481 static gboolean
3482 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3484 int i;
3485 gpointer ip;
3486 FindHandlerBlockData *pdata = (FindHandlerBlockData *)data;
3487 MonoJitInfo *ji = frame->ji;
3489 if (!ji)
3490 return FALSE;
3492 ip = MONO_CONTEXT_GET_IP (ctx);
3494 for (i = 0; i < ji->num_clauses; ++i) {
3495 MonoJitExceptionInfo *ei = ji->clauses + i;
3496 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3497 continue;
3498 /*If ip points to the first instruction it means the handler block didn't start
3499 so we can leave its execution to the EH machinery*/
3500 if (ei->handler_start <= ip && ip < ei->data.handler_end) {
3501 pdata->ji = ji;
3502 pdata->ei = ei;
3503 pdata->ctx = *ctx;
3504 break;
3507 return FALSE;
3511 static void
3512 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
3514 int i;
3515 MonoJitExceptionInfo *clause = NULL;
3516 gpointer ip;
3517 guint8 *bp;
3519 ip = MONO_CONTEXT_GET_IP (ctx);
3521 for (i = 0; i < ji->num_clauses; ++i) {
3522 clause = &ji->clauses [i];
3523 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3524 continue;
3525 if (clause->handler_start <= ip && clause->data.handler_end > ip)
3526 break;
3529 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3530 g_assert (i < ji->num_clauses);
3532 /*Load the spvar*/
3533 bp = (guint8*)MONO_CONTEXT_GET_BP (ctx);
3534 *(bp + clause->exvar_offset) = 1;
3538 * Finds the bottom handler block running and install a block guard if needed.
3540 static gboolean
3541 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
3543 FindHandlerBlockData data = { 0 };
3544 MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
3546 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3547 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3549 if (!jit_tls || jit_tls->handler_block)
3550 return FALSE;
3552 /* Do an async safe stack walk */
3553 mono_thread_info_set_is_async_context (TRUE);
3554 mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data);
3555 mono_thread_info_set_is_async_context (FALSE);
3557 if (!data.ji)
3558 return FALSE;
3560 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
3562 install_handler_block_guard (data.ji, &data.ctx);
3564 jit_tls->handler_block = data.ei;
3566 return TRUE;
3569 static void
3570 mono_uninstall_current_handler_block_guard (void)
3572 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3573 if (jit_tls)
3574 jit_tls->handler_block = NULL;
3578 static gboolean
3579 mono_current_thread_has_handle_block_guard (void)
3581 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3582 return jit_tls && jit_tls->handler_block != NULL;
3585 void
3586 mono_set_cast_details (MonoClass *from, MonoClass *to)
3588 MonoJitTlsData *jit_tls = NULL;
3590 if (mini_debug_options.better_cast_details) {
3591 jit_tls = mono_tls_get_jit_tls ();
3592 jit_tls->class_cast_from = from;
3593 jit_tls->class_cast_to = to;
3598 /*returns false if the thread is not attached*/
3599 gboolean
3600 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
3602 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3603 if (!thread) {
3604 ctx->valid = FALSE;
3605 return FALSE;
3608 if (sigctx) {
3609 mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
3611 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3612 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3613 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3615 else {
3616 mono_thread_state_init (ctx);
3619 if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
3620 return FALSE;
3622 ctx->valid = TRUE;
3623 return TRUE;
3626 void
3627 mono_thread_state_init (MonoThreadUnwindState *ctx)
3629 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3631 #if defined(MONO_CROSS_COMPILE)
3632 ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
3633 #elif MONO_ARCH_HAS_MONO_CONTEXT
3634 MONO_CONTEXT_GET_CURRENT (ctx->ctx);
3635 #else
3636 g_error ("Use a null sigctx requires a working mono-context");
3637 #endif
3639 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3640 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3641 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
3642 ctx->valid = TRUE;
3646 gboolean
3647 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
3649 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3650 if (!thread) {
3651 ctx->valid = FALSE;
3652 return FALSE;
3655 ctx->ctx = *mctx;
3656 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3657 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3658 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3659 ctx->valid = TRUE;
3660 return TRUE;
3663 /*returns false if the thread is not attached*/
3664 gboolean
3665 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
3667 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3668 MONO_ARCH_CONTEXT_DEF
3670 mono_arch_flush_register_windows ();
3672 if (!thread || !thread->jit_data) {
3673 ctx->valid = FALSE;
3674 return FALSE;
3676 MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
3678 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3679 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3680 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3681 ctx->valid = TRUE;
3682 return TRUE;
3685 static void
3686 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
3688 mono_handle_exception (ctx, (MonoObject *)exc);
3689 mono_restore_context (ctx);
3692 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3693 void
3694 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
3696 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3697 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3698 jit_tls->ex_ctx = *ctx;
3700 mono_arch_setup_async_callback (ctx, async_cb, user_data);
3701 #else
3702 g_error ("This target doesn't support mono_arch_setup_async_callback");
3703 #endif
3707 * mono_restore_context:
3709 * Call the architecture specific restore context function.
3711 void
3712 mono_restore_context (MonoContext *ctx)
3714 static void (*restore_context) (MonoContext *);
3716 if (!restore_context)
3717 restore_context = (void (*)(MonoContext *))mono_get_restore_context ();
3718 restore_context (ctx);
3719 g_assert_not_reached ();
3723 * mono_jinfo_get_unwind_info:
3725 * Return the unwind info for JI.
3727 guint8*
3728 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
3730 if (ji->has_unwind_info) {
3731 /* The address/length in the MonoJitInfo structure itself */
3732 MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji);
3733 *unwind_info_len = info->unw_info_len;
3734 return info->unw_info;
3735 } else if (ji->from_aot)
3736 return mono_aot_get_unwind_info (ji, unwind_info_len);
3737 else
3738 return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
3742 mono_jinfo_get_epilog_size (MonoJitInfo *ji)
3744 MonoArchEHJitInfo *info;
3746 info = mono_jit_info_get_arch_eh_info (ji);
3747 g_assert (info);
3749 return info->epilog_size;
3753 * mono_install_ftnptr_eh_callback:
3755 * Install a callback that should be called when there is a managed exception
3756 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3757 * managed exception to a native exception, to properly unwind the native
3758 * stack; this native exception will then be converted back to a managed
3759 * exception in their managed-to-native wrapper.
3761 void
3762 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
3764 ftnptr_eh_callback = callback;
3768 * LLVM/Bitcode exception handling.
3771 static void
3772 throw_exception (MonoObject *ex, gboolean rethrow)
3774 MONO_REQ_GC_UNSAFE_MODE;
3776 ERROR_DECL (error);
3777 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3778 MonoException *mono_ex;
3780 if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, error)) {
3781 mono_error_assert_ok (error);
3782 mono_ex = mono_get_exception_runtime_wrapped_checked (ex, error);
3783 mono_error_assert_ok (error);
3784 jit_tls->thrown_non_exc = mono_gchandle_new_internal (ex, FALSE);
3786 else
3787 mono_ex = (MonoException*)ex;
3789 // Note: Not pinned
3790 jit_tls->thrown_exc = mono_gchandle_new_internal ((MonoObject*)mono_ex, FALSE);
3792 if (!rethrow) {
3793 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3794 GList *l, *ips = NULL;
3795 GList *trace;
3797 _Unwind_Backtrace (build_stack_trace, &ips);
3798 /* The list contains ip-gshared info pairs */
3799 trace = NULL;
3800 ips = g_list_reverse (ips);
3801 for (l = ips; l; l = l->next) {
3802 trace = g_list_append (trace, l->data);
3803 trace = g_list_append (trace, NULL);
3804 trace = g_list_append (trace, NULL);
3806 MonoArray *ips_arr = mono_glist_to_array (trace, mono_defaults.int_class, error);
3807 mono_error_assert_ok (error);
3808 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3809 g_list_free (l);
3810 g_list_free (trace);
3811 #endif
3814 mono_llvm_cpp_throw_exception ();
3817 void
3818 mono_llvm_throw_exception (MonoObject *ex)
3820 throw_exception (ex, FALSE);
3823 void
3824 mono_llvm_rethrow_exception (MonoObject *ex)
3826 throw_exception (ex, TRUE);
3829 void
3830 mono_llvm_raise_exception (MonoException *e)
3832 mono_llvm_throw_exception ((MonoObject*)e);
3835 void
3836 mono_llvm_reraise_exception (MonoException *e)
3838 mono_llvm_rethrow_exception ((MonoObject*)e);
3841 void
3842 mono_llvm_throw_corlib_exception (guint32 ex_token_index)
3844 guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
3845 MonoException *ex;
3847 ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token);
3849 mono_llvm_throw_exception ((MonoObject*)ex);
3853 * mono_llvm_resume_exception:
3855 * Resume exception propagation.
3857 void
3858 mono_llvm_resume_exception (void)
3860 mono_llvm_cpp_throw_exception ();
3864 * mono_llvm_load_exception:
3866 * Return the currently thrown exception.
3868 MonoObject *
3869 mono_llvm_load_exception (void)
3871 ERROR_DECL (error);
3872 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3874 MonoException *mono_ex = (MonoException*)mono_gchandle_get_target_internal (jit_tls->thrown_exc);
3876 MonoArray *ta = mono_ex->trace_ips;
3878 if (ta) {
3879 GList *trace_ips = NULL;
3880 gpointer ip = MONO_RETURN_ADDRESS ();
3882 size_t upper = mono_array_length_internal (ta);
3884 for (int i = 0; i < upper; i += TRACE_IP_ENTRY_SIZE) {
3885 gpointer curr_ip = mono_array_get_internal (ta, gpointer, i);
3886 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
3887 gpointer p = mono_array_get_internal (ta, gpointer, i + j);
3888 trace_ips = g_list_append (trace_ips, p);
3890 if (ip == curr_ip)
3891 break;
3894 // FIXME: Does this work correctly for rethrows?
3895 // We may be discarding useful information
3896 // when this gets GC'ed
3897 MonoArray *ips_arr = mono_glist_to_array (trace_ips, mono_defaults.int_class, error);
3898 mono_error_assert_ok (error);
3899 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3900 g_list_free (trace_ips);
3902 // FIXME:
3903 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3904 } else {
3905 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, 0, error));
3906 mono_error_assert_ok (error);
3907 MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, mono_array_new_checked (mono_domain_get (), mono_defaults.stack_frame_class, 0, error));
3908 mono_error_assert_ok (error);
3911 return &mono_ex->object;
3915 * mono_llvm_clear_exception:
3917 * Mark the currently thrown exception as handled.
3919 void
3920 mono_llvm_clear_exception (void)
3922 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3923 mono_gchandle_free_internal (jit_tls->thrown_exc);
3924 jit_tls->thrown_exc = 0;
3925 if (jit_tls->thrown_non_exc)
3926 mono_gchandle_free_internal (jit_tls->thrown_non_exc);
3927 jit_tls->thrown_non_exc = 0;
3929 mono_memory_barrier ();
3933 * mono_llvm_match_exception:
3935 * Return the innermost clause containing REGION_START-REGION_END which can handle
3936 * the current exception.
3938 gint32
3939 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
3941 ERROR_DECL (error);
3942 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3943 MonoObject *exc;
3944 gint32 index = -1;
3946 g_assert (jit_tls->thrown_exc);
3947 exc = mono_gchandle_get_target_internal (jit_tls->thrown_exc);
3948 if (jit_tls->thrown_non_exc) {
3950 * Have to unwrap RuntimeWrappedExceptions if the
3951 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
3953 if (!wrap_non_exception_throws (jinfo_get_method (jinfo)))
3954 exc = mono_gchandle_get_target_internal (jit_tls->thrown_non_exc);
3957 for (int i = 0; i < jinfo->num_clauses; i++) {
3958 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
3959 MonoClass *catch_class;
3961 if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
3962 continue;
3964 catch_class = ei->data.catch_class;
3965 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class))) {
3966 MonoGenericContext context;
3967 MonoType *inflated_type;
3969 g_assert (rgctx || this_obj);
3970 context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
3971 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
3972 mono_error_assert_ok (error); /* FIXME don't swallow the error */
3974 catch_class = mono_class_from_mono_type_internal (inflated_type);
3975 mono_metadata_free_type (inflated_type);
3978 // FIXME: Handle edge cases handled in get_exception_catch_class
3979 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, error)) {
3980 index = ei->clause_index;
3981 break;
3982 } else
3983 mono_error_assert_ok (error);
3985 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3986 g_assert_not_reached ();
3990 return index;
3993 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
3994 G_EXTERN_C _Unwind_Reason_Code mono_debug_personality (int a, _Unwind_Action b,
3995 uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
3997 g_assert_not_reached ();
3999 #else
4000 G_EXTERN_C void mono_debug_personality (void);
4002 void
4003 mono_debug_personality (void)
4005 g_assert_not_reached ();
4007 #endif