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