[runtime] Transition the trampoline code to use memory managers for memory allocation...
[mono-project.git] / mono / mini / mini-exceptions.c
blob0a5ce187ce9dc0c6bac6e39724a37119418c4555
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/metadata/handle.h>
65 #include <mono/utils/mono-merp.h>
66 #include <mono/utils/mono-mmap.h>
67 #include <mono/utils/mono-logger-internals.h>
68 #include <mono/utils/mono-error.h>
69 #include <mono/utils/mono-error-internals.h>
70 #include <mono/utils/mono-state.h>
71 #include <mono/utils/mono-threads-debug.h>
73 #include "mini.h"
74 #include "trace.h"
75 #include "debugger-agent.h"
76 #include "debugger-engine.h"
77 #include "seq-points.h"
78 #include "llvm-runtime.h"
79 #include "mini-llvm.h"
80 #include "aot-runtime.h"
81 #include "mini-runtime.h"
82 #include "interp/interp.h"
84 #ifdef ENABLE_LLVM
85 #include "mini-llvm-cpp.h"
86 #endif
88 #ifdef TARGET_ARM
89 #include "mini-arm.h"
90 #endif
92 #ifndef MONO_ARCH_CONTEXT_DEF
93 #define MONO_ARCH_CONTEXT_DEF
94 #endif
96 #if !defined(DISABLE_CRASH_REPORTING)
97 #include <gmodule.h>
98 #endif
99 #include "mono/utils/mono-tls-inline.h"
102 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
103 * This structure represents one entry.
104 * This should consists of pointers only.
106 typedef struct
108 gpointer ip;
109 gpointer generic_info;
110 /* Only for interpreter frames */
111 MonoJitInfo *ji;
112 } ExceptionTraceIp;
114 /* Number of words in trace_ips belonging to one entry */
115 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
117 static gpointer restore_context_func, call_filter_func;
118 static gpointer throw_exception_func, rethrow_exception_func, rethrow_preserve_exception_func;
119 static gpointer throw_corlib_exception_func;
121 static MonoFtnPtrEHCallback ftnptr_eh_callback;
123 static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data, gboolean crash_context);
124 static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx);
125 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
126 static gboolean mono_current_thread_has_handle_block_guard (void);
127 static gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx);
128 static void mono_uninstall_current_handler_block_guard (void);
129 static gboolean mono_exception_walk_trace_internal (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data);
130 static void throw_exception (MonoObject *ex, gboolean rethrow);
132 static void mono_summarize_managed_stack (MonoThreadSummary *out);
133 static void mono_summarize_unmanaged_stack (MonoThreadSummary *out);
134 static void mono_summarize_exception (MonoException *exc, MonoThreadSummary *out);
135 static void mono_crash_reporting_register_native_library (const char *module_path, const char *module_name);
136 static void mono_crash_reporting_allow_all_native_libraries (void);
138 static gboolean
139 first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
141 gpointer *data = (gpointer *)addr;
143 if (!frame->managed)
144 return FALSE;
146 if (!ctx) {
147 // FIXME: Happens with llvm_only
148 *data = NULL;
149 return TRUE;
152 *data = frame->frame_addr;
153 g_assert (*data);
154 return TRUE;
157 static gpointer
158 mono_thread_get_managed_sp (void)
160 gpointer addr = NULL;
161 mono_walk_stack (first_managed, MONO_UNWIND_SIGNAL_SAFE, &addr);
162 return addr;
165 static void
166 mini_clear_abort_threshold (void)
168 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
169 jit_tls->abort_exc_stack_threshold = NULL;
172 static void
173 mini_set_abort_threshold (StackFrameInfo *frame)
175 gpointer sp = frame->frame_addr;
176 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
177 // Only move it up, to avoid thrown/caught
178 // exceptions lower in the stack from triggering
179 // a rethrow
180 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
181 if (!jit_tls->abort_exc_stack_threshold || above_threshold) {
182 jit_tls->abort_exc_stack_threshold = sp;
186 // Note: In the case that the frame is above where the thread abort
187 // was set we bump the threshold so that functions called from the new,
188 // higher threshold don't trigger the thread abort exception
189 static gboolean
190 mini_above_abort_threshold (void)
192 gpointer sp = mono_thread_get_managed_sp ();
193 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
195 if (!sp)
196 return TRUE;
198 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
200 if (above_threshold)
201 jit_tls->abort_exc_stack_threshold = sp;
203 return above_threshold;
206 static int
207 mono_get_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
209 SeqPoint sp;
210 if (mono_find_prev_seq_point_for_native_offset (domain, method, native_offset, NULL, &sp))
211 return sp.il_offset;
212 return -1;
215 void
216 mono_exceptions_init (void)
218 MonoRuntimeExceptionHandlingCallbacks cbs;
219 if (mono_ee_features.use_aot_trampolines) {
220 restore_context_func = mono_aot_get_trampoline ("restore_context");
221 call_filter_func = mono_aot_get_trampoline ("call_filter");
222 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
223 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
224 rethrow_preserve_exception_func = mono_aot_get_trampoline ("rethrow_preserve_exception");
225 } else if (!mono_llvm_only) {
226 MonoTrampInfo *info;
228 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
229 mono_tramp_info_register (info, NULL);
230 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
231 mono_tramp_info_register (info, NULL);
232 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
233 mono_tramp_info_register (info, NULL);
234 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
235 mono_tramp_info_register (info, NULL);
236 rethrow_preserve_exception_func = mono_arch_get_rethrow_preserve_exception (&info, FALSE);
237 mono_tramp_info_register (info, NULL);
240 mono_arch_exceptions_init ();
242 cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
243 cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
244 cbs.mono_summarize_managed_stack = mono_summarize_managed_stack;
245 cbs.mono_summarize_unmanaged_stack = mono_summarize_unmanaged_stack;
246 cbs.mono_summarize_exception = mono_summarize_exception;
247 cbs.mono_register_native_library = mono_crash_reporting_register_native_library;
248 cbs.mono_allow_all_native_libraries = mono_crash_reporting_allow_all_native_libraries;
250 if (mono_llvm_only) {
251 cbs.mono_raise_exception = mono_llvm_raise_exception;
252 cbs.mono_reraise_exception = mono_llvm_reraise_exception;
253 } else {
254 cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception ();
255 cbs.mono_reraise_exception = (void (*)(MonoException *))mono_get_rethrow_exception ();
257 cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
258 cbs.mono_exception_walk_trace = mono_exception_walk_trace;
259 cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
260 cbs.mono_uninstall_current_handler_block_guard = mono_uninstall_current_handler_block_guard;
261 cbs.mono_current_thread_has_handle_block_guard = mono_current_thread_has_handle_block_guard;
262 cbs.mono_clear_abort_threshold = mini_clear_abort_threshold;
263 cbs.mono_above_abort_threshold = mini_above_abort_threshold;
264 mono_install_eh_callbacks (&cbs);
265 mono_install_get_seq_point (mono_get_seq_point_for_native_offset);
268 gpointer
269 mono_get_throw_exception (void)
271 g_assert (throw_exception_func);
272 return throw_exception_func;
275 gpointer
276 mono_get_rethrow_exception (void)
278 g_assert (rethrow_exception_func);
279 return rethrow_exception_func;
282 gpointer
283 mono_get_rethrow_preserve_exception (void)
285 g_assert (rethrow_preserve_exception_func);
286 return rethrow_preserve_exception_func;
289 static void
290 no_call_filter (void)
292 g_assert_not_reached ();
295 gpointer
296 mono_get_call_filter (void)
298 /* This is called even in llvmonly mode etc. */
299 if (!call_filter_func)
300 return (gpointer)no_call_filter;
301 return call_filter_func;
304 gpointer
305 mono_get_restore_context (void)
307 g_assert (restore_context_func);
308 return restore_context_func;
311 gpointer
312 mono_get_throw_corlib_exception (void)
314 gpointer code = NULL;
315 MonoTrampInfo *info;
317 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
318 if (throw_corlib_exception_func)
319 return throw_corlib_exception_func;
321 if (mono_ee_features.use_aot_trampolines)
322 code = mono_aot_get_trampoline ("throw_corlib_exception");
323 else {
324 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
325 mono_tramp_info_register (info, NULL);
328 mono_memory_barrier ();
330 throw_corlib_exception_func = code;
332 return throw_corlib_exception_func;
336 * mono_get_throw_exception_addr:
338 * Return an address which stores the result of
339 * mono_get_throw_exception.
341 gpointer
342 mono_get_throw_exception_addr (void)
344 return &throw_exception_func;
347 gpointer
348 mono_get_rethrow_preserve_exception_addr (void)
350 return &rethrow_preserve_exception_func;
353 static gboolean
354 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
356 MonoTryBlockHoleTableJitInfo *table;
357 int i;
358 guint32 offset;
359 guint16 clause;
361 if (ei->try_start > ip || ip >= ei->try_end)
362 return FALSE;
364 if (!ji->has_try_block_holes)
365 return TRUE;
367 table = mono_jit_info_get_try_block_hole_table_info (ji);
368 offset = (guint32)((char*)ip - (char*)ji->code_start);
369 clause = (guint16)(ei - ji->clauses);
370 g_assert (clause < ji->num_clauses);
372 for (i = 0; i < table->num_holes; ++i) {
373 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
374 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
375 return FALSE;
377 return TRUE;
380 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
382 #if 0
383 static gboolean show_native_addresses = TRUE;
384 #else
385 static gboolean show_native_addresses = FALSE;
386 #endif
388 static _Unwind_Reason_Code
389 build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
391 MonoDomain *domain = mono_domain_get ();
392 uintptr_t ip = _Unwind_GetIP (frame_ctx);
394 if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
395 GList **trace_ips = (GList **)state;
396 *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
399 return _URC_NO_REASON;
402 static GSList*
403 get_unwind_backtrace (void)
405 GSList *ips = NULL;
407 _Unwind_Backtrace (build_stack_trace, &ips);
409 return g_slist_reverse (ips);
412 #else
414 static GSList*
415 get_unwind_backtrace (void)
417 return NULL;
420 #endif
422 static gboolean
423 arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
424 MonoJitInfo *ji, MonoContext *ctx,
425 MonoContext *new_ctx, MonoLMF **lmf,
426 host_mgreg_t **save_locations,
427 StackFrameInfo *frame)
429 if (!ji && *lmf) {
430 if (((gsize)(*lmf)->previous_lmf) & 2) {
431 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
433 memset (frame, 0, sizeof (StackFrameInfo));
434 frame->ji = ji;
436 *new_ctx = *ctx;
438 if (ext->kind == MONO_LMFEXT_DEBUGGER_INVOKE) {
440 * This LMF entry is created by the soft debug code to mark transitions to
441 * managed code done during invokes.
443 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
444 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
445 } else if (ext->kind == MONO_LMFEXT_INTERP_EXIT || ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX) {
446 frame->type = FRAME_TYPE_INTERP_TO_MANAGED;
447 frame->interp_exit_data = ext->interp_exit_data;
448 if (ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX) {
449 frame->type = FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX;
450 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
452 } else {
453 g_assert_not_reached ();
456 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~3);
458 return TRUE;
462 return mono_arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
466 * find_jit_info:
468 * Translate between the mono_arch_unwind_frame function and the old API.
470 static MonoJitInfo *
471 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
472 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
474 StackFrameInfo frame;
475 MonoJitInfo *ji;
476 gboolean err;
477 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
479 /* Avoid costly table lookup during stack overflow */
480 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
481 ji = prev_ji;
482 else
483 ji = mini_jit_info_table_find (domain, ip, NULL);
485 if (managed)
486 *managed = FALSE;
488 err = arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
489 if (!err)
490 return (MonoJitInfo *)-1;
492 if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
494 * Remove any unused lmf.
495 * Mask out the lower bits which might be used to hold additional information.
497 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P -1));
500 /* Convert between the new and the old APIs */
501 switch (frame.type) {
502 case FRAME_TYPE_MANAGED:
503 if (managed)
504 *managed = TRUE;
505 return frame.ji;
506 case FRAME_TYPE_TRAMPOLINE:
507 return frame.ji;
508 case FRAME_TYPE_MANAGED_TO_NATIVE:
509 if (frame.ji)
510 return frame.ji;
511 else {
512 memset (res, 0, sizeof (MonoJitInfo));
513 res->d.method = frame.method;
514 return res;
516 case FRAME_TYPE_DEBUGGER_INVOKE: {
517 MonoContext tmp_ctx;
520 * The normal exception handling code can't handle this frame, so just
521 * skip it.
523 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
524 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
525 return ji;
527 default:
528 g_assert_not_reached ();
529 return NULL;
533 /* mono_find_jit_info:
535 * This function is used to gather information from @ctx. It return the
536 * MonoJitInfo of the corresponding function, unwinds one stack frame and
537 * stores the resulting context into @new_ctx. It also stores a string
538 * describing the stack location into @trace (if not NULL), and modifies
539 * the @lmf if necessary. @native_offset return the IP offset from the
540 * start of the function or -1 if that info is not available.
542 MonoJitInfo *
543 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
544 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
545 gboolean *managed)
547 gboolean managed2;
548 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
549 MonoJitInfo *ji;
550 MonoMethod *method = NULL;
552 if (trace)
553 *trace = NULL;
555 if (native_offset)
556 *native_offset = -1;
558 if (managed)
559 *managed = FALSE;
561 ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
563 if (ji == (gpointer)-1)
564 return ji;
566 if (ji && !ji->is_trampoline)
567 method = jinfo_get_method (ji);
569 if (managed2 || (method && method->wrapper_type)) {
570 const char *real_ip, *start;
571 gint32 offset;
573 start = (const char *)ji->code_start;
574 if (!managed2)
575 /* ctx->ip points into native code */
576 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
577 else
578 real_ip = (const char*)ip;
580 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
581 offset = real_ip - start;
582 else
583 offset = -1;
585 if (native_offset)
586 *native_offset = offset;
588 if (managed)
589 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
590 *managed = TRUE;
592 if (trace)
593 *trace = mono_debug_print_stack_frame (method, offset, domain);
594 } else {
595 if (trace) {
596 char *fname = mono_method_full_name (jinfo_get_method (res), TRUE);
597 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
598 g_free (fname);
602 return ji;
606 * mono_find_jit_info_ext:
608 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
609 * structure.
610 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
611 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
612 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
613 * to obtain the last managed frame.
614 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
615 * On return, it will be filled with the locations where callee saved registers are saved
616 * by the current frame. This is returned outside of StackFrameInfo because it can be
617 * quite large on some platforms.
618 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
619 * not be set.
621 gboolean
622 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
623 MonoJitInfo *prev_ji, MonoContext *ctx,
624 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
625 host_mgreg_t **save_locations,
626 StackFrameInfo *frame)
628 gboolean err;
629 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
630 MonoJitInfo *ji;
631 MonoDomain *target_domain = domain;
632 MonoMethod *method = NULL;
633 gboolean async = mono_thread_info_is_async_context ();
635 if (trace)
636 *trace = NULL;
638 /* Avoid costly table lookup during stack overflow */
639 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
640 ji = prev_ji;
641 else
642 ji = mini_jit_info_table_find_ext (domain, ip, TRUE, &target_domain);
644 if (!target_domain)
645 target_domain = domain;
647 if (save_locations)
648 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (host_mgreg_t*));
650 err = arch_unwind_frame (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
651 if (!err)
652 return FALSE;
654 gboolean not_i2m = frame->type != FRAME_TYPE_INTERP_TO_MANAGED && frame->type != FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX;
656 if (not_i2m && *lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
658 * Remove any unused lmf.
659 * Mask out the lower bits which might be used to hold additional information.
661 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P -1));
664 if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async)
665 method = jinfo_get_method (frame->ji);
667 if (frame->type == FRAME_TYPE_MANAGED && method) {
668 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
669 frame->managed = TRUE;
672 if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
674 * This type of frame is just a marker, the caller should unwind once more to get the
675 * last managed frame.
677 frame->ji = NULL;
678 frame->method = NULL;
681 frame->native_offset = -1;
682 frame->domain = target_domain;
683 frame->async_context = async;
684 frame->frame_addr = MONO_CONTEXT_GET_SP (ctx);
686 ji = frame->ji;
688 if (frame->type == FRAME_TYPE_MANAGED)
689 frame->method = method;
691 if (ji && (frame->managed || (method && method->wrapper_type))) {
692 const char *real_ip, *start;
694 start = (const char *)ji->code_start;
695 if (frame->type == FRAME_TYPE_MANAGED)
696 real_ip = (const char*)ip;
697 else
698 /* ctx->ip points into native code */
699 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
701 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
702 frame->native_offset = real_ip - start;
703 else {
704 frame->native_offset = -1;
707 if (trace)
708 *trace = mono_debug_print_stack_frame (method, frame->native_offset, domain);
709 } else {
710 if (trace && frame->method) {
711 char *fname = mono_method_full_name (frame->method, TRUE);
712 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
713 g_free (fname);
717 return TRUE;
720 typedef struct {
721 gboolean in_interp;
722 MonoInterpStackIter interp_iter;
723 gpointer last_frame_addr;
724 } Unwinder;
726 static void
727 unwinder_init (Unwinder *unwinder)
729 memset (unwinder, 0, sizeof (Unwinder));
732 #if defined(__GNUC__) && defined(TARGET_ARM64)
733 /* gcc 4.9.2 seems to miscompile this on arm64 */
734 static __attribute__((optimize("O0"))) gboolean
735 #else
736 static gboolean
737 #endif
738 unwinder_unwind_frame (Unwinder *unwinder,
739 MonoDomain *domain, MonoJitTlsData *jit_tls,
740 MonoJitInfo *prev_ji, MonoContext *ctx,
741 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
742 host_mgreg_t **save_locations,
743 StackFrameInfo *frame)
745 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 const gpointer parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame);
764 unwinder->last_frame_addr = parent;
767 if (!unwinder->in_interp)
768 return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame);
769 return TRUE;
770 } else {
771 gboolean res = mono_find_jit_info_ext (domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf,
772 save_locations, frame);
773 if (!res)
774 return FALSE;
775 if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED || frame->type == FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX) {
776 unwinder->in_interp = TRUE;
777 mini_get_interp_callbacks ()->frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data);
779 unwinder->last_frame_addr = frame->frame_addr;
780 return TRUE;
785 * This function is async-safe.
787 static gpointer
788 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
790 MonoGenericJitInfo *gi;
791 MonoMethod *method;
792 gpointer info;
794 if (!ji->has_generic_jit_info)
795 return NULL;
796 gi = mono_jit_info_get_generic_jit_info (ji);
797 if (!gi->has_this)
798 return NULL;
800 info = NULL;
802 * Search location list if available, it contains the precise location of the
803 * argument for every pc offset, even if the method was interrupted while it was in
804 * its prolog.
806 if (gi->nlocs) {
807 int offset = (gsize)MONO_CONTEXT_GET_IP (ctx) - (gsize)ji->code_start;
808 int i;
810 for (i = 0; i < gi->nlocs; ++i) {
811 MonoDwarfLocListEntry *entry = &gi->locations [i];
813 if (offset >= entry->from && (offset < entry->to || entry->to == 0)) {
814 if (entry->is_reg)
815 info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg);
816 else
817 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset);
818 break;
821 g_assert (i < gi->nlocs);
822 } else {
823 if (gi->this_in_reg)
824 info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg);
825 else
826 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
827 gi->this_offset);
830 method = jinfo_get_method (ji);
831 if (mono_method_get_context (method)->method_inst) {
832 /* A MonoMethodRuntimeGenericContext* */
833 return info;
834 } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || m_class_is_valuetype (method->klass)) {
835 /* A MonoVTable* */
836 return info;
837 } else {
838 /* Avoid returning a managed object */
839 MonoObject *this_obj = (MonoObject *)info;
841 return this_obj->vtable;
846 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
848 MonoGenericContext
849 mono_get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
851 MonoGenericContext context = { NULL, NULL };
852 MonoClass *klass, *method_container_class;
853 MonoMethod *method;
855 g_assert (generic_info);
857 method = jinfo_get_method (ji);
858 g_assert (method->is_inflated);
859 if (mono_method_get_context (method)->method_inst) {
860 MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext *)generic_info;
862 klass = mrgctx->class_vtable->klass;
863 context.method_inst = mrgctx->method_inst;
864 g_assert (context.method_inst);
865 } else {
866 MonoVTable *vtable = (MonoVTable *)generic_info;
868 klass = vtable->klass;
871 //g_assert (!mono_class_is_gtd (method->klass));
872 if (mono_class_is_ginst (method->klass))
873 method_container_class = mono_class_get_generic_class (method->klass)->container_class;
874 else
875 method_container_class = method->klass;
877 /* class might refer to a subclass of method's class */
878 while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) {
879 klass = m_class_get_parent (klass);
880 g_assert (klass);
883 if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass))
884 context.class_inst = mini_class_get_context (klass)->class_inst;
886 if (mono_class_is_ginst (klass))
887 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass)->container_class, method_container_class));
888 else
889 g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class));
891 return context;
895 static MonoMethod*
896 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
898 ERROR_DECL (error);
899 MonoGenericContext context;
900 MonoMethod *method;
902 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
903 return jinfo_get_method (ji);
904 context = mono_get_generic_context_from_stack_frame (ji, generic_info);
906 method = jinfo_get_method (ji);
907 method = mono_method_get_declaring_generic_method (method);
908 method = mono_class_inflate_generic_method_checked (method, &context, error);
909 g_assert (is_ok (error)); /* FIXME don't swallow the error */
911 return method;
915 * mono_exception_walk_native_trace:
916 * \param ex The exception object whose frames should be walked
917 * \param func callback to call for each stack frame
918 * \param user_data data passed to the callback
919 * This function walks the stacktrace of an exception. For
920 * each frame the callback function is called with the relevant info.
921 * The walk ends when no more stack frames are found or when the callback
922 * returns a TRUE value.
925 gboolean
926 mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
928 gboolean res;
930 MONO_ENTER_GC_UNSAFE;
931 res = mono_exception_walk_trace_internal (ex, func, user_data);
932 MONO_EXIT_GC_UNSAFE;
933 return res;
936 static gboolean
937 mono_exception_stackframe_obj_walk (MonoStackFrame *captured_frame, MonoExceptionFrameWalk func, gpointer user_data)
939 if (!captured_frame)
940 return TRUE;
942 gpointer ip = (gpointer) (captured_frame->method_address + captured_frame->native_offset);
943 MonoJitInfo *ji = mono_jit_info_table_find_internal (mono_domain_get (), ip, TRUE, TRUE);
945 // Other domain maybe?
946 if (!ji)
947 return FALSE;
948 MonoMethod *method = jinfo_get_method (ji);
950 gboolean r = func (method, (gpointer) captured_frame->method_address, captured_frame->native_offset, TRUE, user_data);
951 if (r)
952 return TRUE;
954 return FALSE;
957 static gboolean
958 mono_exception_stacktrace_obj_walk (MonoStackTrace *st, MonoExceptionFrameWalk func, gpointer user_data)
960 int num_captured = st->captured_traces ? mono_array_length_internal (st->captured_traces) : 0;
961 for (int i=0; i < num_captured; i++) {
962 MonoStackTrace *curr_trace = mono_array_get_fast (st->captured_traces, MonoStackTrace *, i);
963 mono_exception_stacktrace_obj_walk (curr_trace, func, user_data);
966 int num_frames = st->frames ? mono_array_length_internal (st->frames) : 0;
967 for (int frame = 0; frame < num_frames; frame++) {
968 gboolean r = mono_exception_stackframe_obj_walk (mono_array_get_fast (st->frames, MonoStackFrame *, frame), func, user_data);
969 if (r)
970 return TRUE;
973 return TRUE;
976 gboolean
977 mono_exception_walk_trace_internal (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
979 MONO_REQ_GC_UNSAFE_MODE;
981 MonoDomain *domain = mono_domain_get ();
982 MonoArray *ta = ex->trace_ips;
984 /* Exception is not thrown yet */
985 if (ta == NULL)
986 return FALSE;
988 int len = mono_array_length_internal (ta) / TRACE_IP_ENTRY_SIZE;
989 gboolean otherwise_has_traces = len > 0;
991 for (int i = 0; i < len; i++) {
992 ExceptionTraceIp trace_ip;
994 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
995 gpointer ip = trace_ip.ip;
996 gpointer generic_info = trace_ip.generic_info;
998 MonoJitInfo *ji = NULL;
999 if (trace_ip.ji) {
1000 ji = trace_ip.ji;
1001 } else {
1002 ji = mono_jit_info_table_find (domain, ip);
1005 if (ji == NULL) {
1006 gboolean r;
1007 MONO_ENTER_GC_SAFE;
1008 r = func (NULL, ip, 0, FALSE, user_data);
1009 MONO_EXIT_GC_SAFE;
1010 if (r)
1011 break;
1012 } else {
1013 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
1014 if (func (method, ji->code_start, (char *) ip - (char *) ji->code_start, TRUE, user_data))
1015 break;
1019 ta = (MonoArray *) ex->captured_traces;
1020 len = ta ? mono_array_length_internal (ta) : 0;
1021 gboolean captured_has_traces = len > 0;
1023 for (int i = 0; i < len; i++) {
1024 MonoStackTrace *captured_trace = mono_array_get_fast (ta, MonoStackTrace *, i);
1025 if (!captured_trace)
1026 break;
1028 mono_exception_stacktrace_obj_walk (captured_trace, func, user_data);
1031 return captured_has_traces || otherwise_has_traces;
1034 MonoArray *
1035 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
1037 ERROR_DECL (error);
1038 MonoDomain *domain = mono_domain_get ();
1039 MonoArray *res;
1040 MonoArray *ta = exc->trace_ips;
1041 MonoDebugSourceLocation *location;
1042 int i, len;
1044 if (ta == NULL) {
1045 /* Exception is not thrown yet */
1046 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, error);
1047 mono_error_set_pending_exception (error);
1048 return res;
1051 HANDLE_FUNCTION_ENTER ();
1053 MONO_HANDLE_PIN (ta);
1055 len = mono_array_length_internal (ta) / TRACE_IP_ENTRY_SIZE;
1057 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, error);
1058 if (!is_ok (error))
1059 goto fail;
1061 MONO_HANDLE_PIN (res);
1063 MonoObjectHandle sf_h;
1064 sf_h = MONO_HANDLE_NEW (MonoObject, NULL);
1066 for (i = skip; i < len; i++) {
1067 MonoJitInfo *ji;
1068 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
1069 if (!is_ok (error))
1070 goto fail;
1071 MONO_HANDLE_ASSIGN_RAW (sf_h, sf);
1073 ExceptionTraceIp trace_ip;
1074 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
1075 gpointer ip = trace_ip.ip;
1076 gpointer generic_info = trace_ip.generic_info;
1077 MonoMethod *method;
1079 if (trace_ip.ji) {
1080 ji = trace_ip.ji;
1081 } else {
1082 ji = mono_jit_info_table_find (domain, ip);
1083 if (ji == NULL) {
1084 /* Unmanaged frame */
1085 mono_array_setref_internal (res, i, sf);
1086 continue;
1090 g_assert (ji != NULL);
1092 if (mono_llvm_only || !generic_info)
1093 /* Can't resolve actual method */
1094 method = jinfo_get_method (ji);
1095 else
1096 method = get_method_from_stack_frame (ji, generic_info);
1097 if (jinfo_get_method (ji)->wrapper_type) {
1098 char *s;
1100 sf->method = NULL;
1101 s = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION);
1102 MonoString *name = mono_string_new_checked (domain, s, error);
1103 g_free (s);
1104 if (!is_ok (error))
1105 goto fail;
1106 MONO_OBJECT_SETREF_INTERNAL (sf, internal_method_name, name);
1108 else {
1109 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
1110 if (!is_ok (error))
1111 goto fail;
1112 MONO_OBJECT_SETREF_INTERNAL (sf, method, rm);
1115 sf->method_index = ji->from_aot ? mono_aot_find_method_index (method) : 0xffffff;
1116 sf->method_address = (gsize) ji->code_start;
1117 sf->native_offset = (char *)ip - (char *)ji->code_start;
1120 * mono_debug_lookup_source_location() returns both the file / line number information
1121 * and the IL offset. Note that computing the IL offset is already an expensive
1122 * operation, so we shouldn't call this method twice.
1124 location = mono_debug_lookup_source_location (jinfo_get_method (ji), sf->native_offset, domain);
1125 if (location) {
1126 sf->il_offset = location->il_offset;
1127 } else {
1128 SeqPoint sp;
1129 if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (ji), sf->native_offset, NULL, &sp))
1130 sf->il_offset = sp.il_offset;
1131 else
1132 sf->il_offset = -1;
1135 if (need_file_info) {
1136 if (location && location->source_file) {
1137 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1138 if (!is_ok (error))
1139 goto fail;
1140 MONO_OBJECT_SETREF_INTERNAL (sf, filename, filename);
1141 sf->line = location->row;
1142 sf->column = location->column;
1143 } else {
1144 sf->line = sf->column = 0;
1145 sf->filename = NULL;
1149 mono_debug_free_source_location (location);
1150 mono_array_setref_internal (res, i - skip, sf);
1152 goto exit;
1154 fail:
1155 mono_error_set_pending_exception (error);
1156 res = NULL;
1157 exit:
1158 HANDLE_FUNCTION_RETURN_VAL (res);
1161 static void
1162 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1164 if (!start_ctx) {
1165 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1166 if (jit_tls && jit_tls->orig_ex_ctx_set)
1167 start_ctx = &jit_tls->orig_ex_ctx;
1169 mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
1172 * mono_walk_stack_with_ctx:
1173 * Unwind the current thread starting at \p start_ctx.
1174 * If \p start_ctx is null, we capture the current context.
1176 void
1177 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1179 MonoContext extra_ctx;
1180 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1181 MONO_ARCH_CONTEXT_DEF
1183 if (!thread || !thread->jit_data)
1184 return;
1186 if (!start_ctx) {
1187 mono_arch_flush_register_windows ();
1188 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
1189 start_ctx = &extra_ctx;
1192 mono_walk_stack_full (func, start_ctx, mono_domain_get (), thread->jit_data, mono_get_lmf (), unwind_options, user_data, FALSE);
1196 * mono_walk_stack_with_state:
1197 * Unwind a thread described by \p state.
1199 * State must be valid (state->valid == TRUE).
1201 * If you are using this function to unwind another thread, make sure it is suspended.
1203 * If \p state is null, we capture the current context.
1205 void
1206 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
1208 MonoThreadUnwindState extra_state;
1209 if (!state) {
1210 g_assert (!mono_thread_info_is_async_context ());
1211 if (!mono_thread_state_init_from_current (&extra_state))
1212 return;
1213 state = &extra_state;
1216 g_assert (state->valid);
1218 if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
1219 /* Not attached */
1220 return;
1222 mono_walk_stack_full (func,
1223 &state->ctx,
1224 (MonoDomain *)state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
1225 (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
1226 (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF],
1227 unwind_options, user_data, FALSE);
1230 void
1231 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
1233 MonoThreadUnwindState state;
1234 if (!mono_thread_state_init_from_current (&state))
1235 return;
1236 mono_walk_stack_with_state (func, &state, options, user_data);
1240 * mono_walk_stack_full:
1241 * \param func callback to call for each stack frame
1242 * \param domain starting appdomain, can be NULL to use the current domain
1243 * \param unwind_options what extra information the unwinder should gather
1244 * \param start_ctx starting state of the stack walk, can be NULL.
1245 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1246 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1247 * \param user_data data passed to the callback
1248 * \param crash_context tells us that we're in a context where it's not safe to lock or allocate
1249 * This function walks the stack of a thread, starting from the state
1250 * represented by \p start_ctx. For each frame the callback
1251 * function is called with the relevant info. The walk ends when no more
1252 * managed stack frames are found or when the callback returns a TRUE value.
1254 static void
1255 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)
1257 gint il_offset;
1258 MonoContext ctx, new_ctx;
1259 StackFrameInfo frame;
1260 gboolean res;
1261 host_mgreg_t *reg_locations [MONO_MAX_IREGS];
1262 host_mgreg_t *new_reg_locations [MONO_MAX_IREGS];
1263 gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
1264 gboolean async = mono_thread_info_is_async_context ();
1265 Unwinder unwinder;
1267 memset (&frame, 0, sizeof (StackFrameInfo));
1269 #ifndef TARGET_WASM
1270 if (mono_llvm_only) {
1271 GSList *l, *ips;
1273 if (async)
1274 return;
1276 ips = get_unwind_backtrace ();
1277 for (l = ips; l; l = l->next) {
1278 guint8 *ip = (guint8*)l->data;
1279 memset (&frame, 0, sizeof (StackFrameInfo));
1280 frame.ji = mini_jit_info_table_find (domain, ip, &frame.domain);
1281 if (!frame.ji || frame.ji->is_trampoline)
1282 continue;
1283 frame.type = FRAME_TYPE_MANAGED;
1284 frame.method = jinfo_get_method (frame.ji);
1285 // FIXME: Cannot lookup the actual method
1286 frame.actual_method = frame.method;
1287 if (frame.type == FRAME_TYPE_MANAGED) {
1288 if (!frame.method->wrapper_type || frame.method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
1289 frame.managed = TRUE;
1291 frame.native_offset = ip - (guint8*)frame.ji->code_start;
1292 frame.il_offset = -1;
1294 if (func (&frame, NULL, user_data))
1295 break;
1297 g_slist_free (ips);
1298 return;
1300 #endif
1302 if (!start_ctx) {
1303 g_warning ("start_ctx required for stack walk");
1304 return;
1307 if (!domain) {
1308 g_warning ("domain required for stack walk");
1309 return;
1312 if (!jit_tls) {
1313 g_warning ("jit_tls required for stack walk");
1314 return;
1317 /*The LMF will be null if the target have no managed frames.*/
1318 /* g_assert (lmf); */
1319 if (async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD)) {
1320 g_warning ("async && (unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) not legal");
1321 return;
1324 memcpy (&ctx, start_ctx, sizeof (MonoContext));
1325 memset (reg_locations, 0, sizeof (reg_locations));
1327 unwinder_init (&unwinder);
1329 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
1330 frame.lmf = lmf;
1331 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
1332 if (!res)
1333 return;
1335 if (frame.type == FRAME_TYPE_TRAMPOLINE)
1336 goto next;
1338 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) {
1339 MonoDebugSourceLocation *source = NULL;
1341 // Don't do this when we can be in a signal handler
1342 if (!crash_context)
1343 source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
1344 if (source) {
1345 il_offset = source->il_offset;
1346 } else {
1347 MonoSeqPointInfo *seq_points = NULL;
1349 // It's more reliable to look into the global cache if possible
1350 if (crash_context)
1351 seq_points = (MonoSeqPointInfo *) frame.ji->seq_points;
1352 else
1353 seq_points = mono_get_seq_points (domain, jinfo_get_method (frame.ji));
1355 SeqPoint sp;
1356 if (seq_points && mono_seq_point_find_prev_by_native_offset (seq_points, frame.native_offset, &sp))
1357 il_offset = sp.il_offset;
1358 else
1359 il_offset = -1;
1361 mono_debug_free_source_location (source);
1362 } else
1363 il_offset = -1;
1365 frame.il_offset = il_offset;
1367 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) {
1368 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
1369 } else {
1370 frame.actual_method = frame.method;
1373 if (get_reg_locations)
1374 frame.reg_locations = reg_locations;
1376 if (func (&frame, &ctx, user_data))
1377 return;
1379 next:
1380 if (get_reg_locations) {
1381 for (int i = 0; i < MONO_MAX_IREGS; ++i)
1382 if (new_reg_locations [i])
1383 reg_locations [i] = new_reg_locations [i];
1386 ctx = new_ctx;
1390 #ifdef DISABLE_CRASH_REPORTING
1392 static void
1393 mono_summarize_managed_stack (MonoThreadSummary *out)
1395 return;
1398 static void
1399 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1401 return;
1404 static void
1405 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1407 return;
1410 static void
1411 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1413 return;
1416 static void
1417 mono_crash_reporting_allow_all_native_libraries ()
1419 return;
1423 #else
1425 typedef struct {
1426 MonoFrameSummary *frames;
1427 int num_frames;
1428 int max_frames;
1429 MonoStackHash *hashes;
1430 const char *error;
1431 } MonoSummarizeUserData;
1433 static void
1434 copy_summary_string_safe (char *dest, const char *src)
1436 g_strlcpy (dest, src, MONO_MAX_SUMMARY_NAME_LEN);
1439 static void
1440 fill_frame_managed_info (MonoFrameSummary *frame, MonoMethod * method)
1442 MonoImage *image = mono_class_get_image (method->klass);
1443 // Used for hashing, more stable across rebuilds than using GUID
1444 copy_summary_string_safe (frame->str_descr, image->assembly_name);
1446 frame->managed_data.guid = image->guid;
1447 frame->managed_data.token = method->token;
1448 frame->managed_data.filename = image->module_name;
1450 MonoDotNetHeader *header = &image->image_info->cli_header;
1451 frame->managed_data.image_size = header->nt.pe_image_size;
1452 frame->managed_data.time_date_stamp = image->time_date_stamp;
1455 typedef struct {
1456 char *suffix;
1457 char *exported_name;
1458 } MonoLibAllowlistEntry;
1460 static GList *native_library_allowlist;
1461 static gboolean allow_all_native_libraries = FALSE;
1463 static void
1464 mono_crash_reporting_register_native_library (const char *module_path, const char *module_name)
1466 // Examples: libsystem_pthread.dylib -> "pthread"
1467 // Examples: libsystem_platform.dylib -> "platform"
1468 // Examples: mono-sgen -> "mono" from above line
1469 MonoLibAllowlistEntry*entry = g_new0 (MonoLibAllowlistEntry, 1);
1470 entry->suffix = g_strdup (module_path);
1471 entry->exported_name = g_strdup (module_name);
1472 native_library_allowlist = g_list_append (native_library_allowlist, entry);
1475 static void
1476 mono_crash_reporting_allow_all_native_libraries ()
1478 allow_all_native_libraries = TRUE;
1481 static gboolean
1482 check_allowlisted_module (const char *in_name, const char **out_module)
1484 #ifndef MONO_PRIVATE_CRASHES
1485 return TRUE;
1486 #else
1487 if (g_str_has_suffix (in_name, "mono-sgen")) {
1488 if (out_module)
1489 copy_summary_string_safe ((char *) *out_module, "mono");
1490 return TRUE;
1492 if (allow_all_native_libraries) {
1493 if (out_module) {
1494 /* for a module name, use the basename of the full path in in_name */
1495 char *basename = (char *) in_name, *p = (char *) in_name;
1496 while (*p != '\0') {
1497 if (*p == '/')
1498 basename = p + 1;
1499 p++;
1501 if (*basename)
1502 copy_summary_string_safe ((char *) *out_module, basename);
1503 else
1504 copy_summary_string_safe ((char *) *out_module, "unknown");
1507 return TRUE;
1510 for (GList *cursor = native_library_allowlist; cursor; cursor = cursor->next) {
1511 MonoLibAllowlistEntry*iter = (MonoLibAllowlistEntry*) cursor->data;
1512 if (!g_str_has_suffix (in_name, iter->suffix))
1513 continue;
1514 if (out_module)
1515 copy_summary_string_safe ((char *) *out_module, iter->exported_name);
1516 return TRUE;
1519 return FALSE;
1520 #endif
1523 static intptr_t
1524 mono_make_portable_ip (intptr_t in_ip, intptr_t module_base)
1526 // FIXME: Make generalize away from llvm tools?
1527 // So lldb starts the pointer base at 0x100000000
1528 // and expects to get pointers as (offset + constant)
1530 // Quirk shared by:
1531 // /usr/bin/symbols -- symbols version: @(#)PROGRAM:symbols PROJECT:SamplingTools-63501
1532 // *CoreSymbolicationDT.framework version: 63750*/
1533 intptr_t offset = in_ip - module_base;
1534 intptr_t magic_value = offset + 0x100000000;
1535 return magic_value;
1538 static gboolean
1539 mono_get_portable_ip (intptr_t in_ip, intptr_t *out_ip, gint32 *out_offset, const char **out_module, char *out_name)
1541 // Note: it's not safe for us to be interrupted while inside of dl_addr, because if we
1542 // try to call dl_addr while interrupted while inside the lock, we will try to take a
1543 // non-recursive lock twice on this thread, and will deadlock.
1544 char sname [256], fname [256];
1545 void *saddr = NULL, *fbase = NULL;
1546 gboolean success = g_module_address ((void*)in_ip, fname, 256, &fbase, sname, 256, &saddr);
1547 if (!success)
1548 return FALSE;
1550 if (!check_allowlisted_module (fname, out_module))
1551 return FALSE;
1553 *out_ip = mono_make_portable_ip ((intptr_t) saddr, (intptr_t) fbase);
1554 *out_offset = in_ip - (intptr_t) saddr;
1556 if (saddr && out_name)
1557 copy_summary_string_safe (out_name, sname);
1558 return TRUE;
1561 static guint64
1562 summarize_offset_free_hash (guint64 accum, MonoFrameSummary *frame)
1564 if (!frame->is_managed)
1565 return accum;
1567 // See: mono_ptrarray_hash
1568 guint64 hash_accum = accum;
1570 // The assembly and the method token, no offsets
1571 hash_accum += mono_metadata_str_hash (frame->str_descr);
1572 hash_accum += frame->managed_data.token;
1574 return hash_accum;
1577 static guint64
1578 summarize_offset_rich_hash (guint64 accum, MonoFrameSummary *frame)
1580 // See: mono_ptrarray_hash
1581 guint64 hash_accum = accum;
1583 if (!frame->is_managed) {
1584 hash_accum += frame->unmanaged_data.ip;
1585 } else {
1586 hash_accum += mono_metadata_str_hash (frame->str_descr);
1587 hash_accum += frame->managed_data.token;
1588 hash_accum += frame->managed_data.il_offset;
1591 return hash_accum;
1594 static gboolean
1595 summarize_frame_internal (MonoMethod *method, gpointer ip, size_t native_offset, int il_offset, gboolean managed, gpointer user_data)
1597 MonoSummarizeUserData *ud = (MonoSummarizeUserData *) user_data;
1599 gboolean valid_state = ud->num_frames + 1 < ud->max_frames;
1600 if (!valid_state) {
1601 ud->error = "Exceeded the maximum number of frames";
1602 return TRUE;
1605 MonoFrameSummary *dest = &ud->frames [ud->num_frames];
1607 dest->unmanaged_data.ip = (intptr_t) ip;
1608 dest->is_managed = managed;
1609 dest->unmanaged_data.module [0] = '\0';
1611 if (!managed && method && method->wrapper_type != MONO_WRAPPER_NONE && method->wrapper_type < MONO_WRAPPER_NUM) {
1612 dest->is_managed = FALSE;
1613 dest->unmanaged_data.has_name = TRUE;
1614 copy_summary_string_safe (dest->str_descr, mono_wrapper_type_to_str (method->wrapper_type));
1617 #ifndef MONO_PRIVATE_CRASHES
1618 if (method)
1619 dest->managed_data.name = (char *) method->name;
1620 #endif
1622 if (managed) {
1623 if (!method) {
1624 ud->error = "Managed method frame, but no provided managed method";
1625 return TRUE;
1627 fill_frame_managed_info (dest, method);
1628 dest->managed_data.native_offset = native_offset;
1629 dest->managed_data.il_offset = il_offset;
1630 } else {
1631 dest->managed_data.token = -1;
1635 ud->hashes->offset_free_hash = summarize_offset_free_hash (ud->hashes->offset_free_hash, dest);
1636 ud->hashes->offset_rich_hash = summarize_offset_rich_hash (ud->hashes->offset_rich_hash, dest);
1638 // We return FALSE, so we're continuing walking
1639 // And we increment the pointer because we're done with this cell in the array
1640 ud->num_frames++;
1641 return FALSE;
1644 static gboolean
1645 summarize_frame_managed_walk (MonoMethod *method, gpointer ip, size_t frame_native_offset, gboolean managed, gpointer user_data)
1647 int il_offset = -1;
1649 if (managed && method) {
1650 MonoDebugSourceLocation *location = mono_debug_lookup_source_location (method, frame_native_offset, mono_domain_get ());
1651 if (location) {
1652 il_offset = location->il_offset;
1653 mono_debug_free_source_location (location);
1657 intptr_t portable_ip = 0;
1658 gint32 offset = 0;
1659 mono_get_portable_ip ((intptr_t) ip, &portable_ip, &offset, NULL, NULL);
1661 return summarize_frame_internal (method, (gpointer) portable_ip, frame_native_offset, il_offset, managed, user_data);
1665 static gboolean
1666 summarize_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
1668 // Don't record trampolines between managed frames
1669 if (frame->ji && frame->ji->is_trampoline)
1670 return TRUE;
1672 if (frame->ji && (frame->ji->is_trampoline || frame->ji->async))
1673 return FALSE; // Keep unwinding
1675 intptr_t ip = 0;
1676 gint32 offset = 0;
1677 mono_get_portable_ip ((intptr_t) MONO_CONTEXT_GET_IP (ctx), &ip, &offset, NULL, NULL);
1678 // Don't need to handle return status "success" because this ip is stored below only, NULL is okay
1680 gboolean is_managed = (frame->type == FRAME_TYPE_MANAGED || frame->type == FRAME_TYPE_INTERP);
1681 MonoMethod *method = NULL;
1682 if (frame && frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
1683 method = jinfo_get_method (frame->ji);
1685 if (is_managed)
1686 method = jinfo_get_method (frame->ji);
1688 return summarize_frame_internal (method, (gpointer) ip, offset, frame->il_offset, is_managed, data);
1691 static void
1692 mono_summarize_exception (MonoException *exc, MonoThreadSummary *out)
1694 memset (out, 0, sizeof (MonoThreadSummary));
1696 MonoException *inner_exc = exc;
1697 int exc_index = 0;
1699 for (exc_index = 0; exc_index < MONO_MAX_SUMMARY_EXCEPTIONS; exc_index++) {
1700 if (inner_exc == NULL)
1701 break;
1703 // Set up state to walk this MonoException's stack
1704 MonoSummarizeUserData data;
1705 memset (&data, 0, sizeof (MonoSummarizeUserData));
1706 data.max_frames = MONO_MAX_SUMMARY_FRAMES;
1707 data.num_frames = 0;
1708 data.frames = out->exceptions [exc_index].managed_frames;
1710 // Accumulate all hashes from all exceptions in traveral order
1711 data.hashes = &out->hashes;
1713 mono_exception_walk_trace (inner_exc, summarize_frame_managed_walk, &data);
1715 // Save per-MonoException info
1716 out->exceptions [exc_index].managed_exc_type = inner_exc->object.vtable->klass;
1717 out->exceptions [exc_index].num_managed_frames = data.num_frames;
1719 // Continue to traverse nesting of exceptions
1720 inner_exc = (MonoException *) inner_exc->inner_ex;
1723 out->num_exceptions = exc_index;
1727 static void
1728 mono_summarize_managed_stack (MonoThreadSummary *out)
1730 MonoSummarizeUserData data;
1731 memset (&data, 0, sizeof (MonoSummarizeUserData));
1732 data.max_frames = MONO_MAX_SUMMARY_FRAMES;
1733 data.num_frames = 0;
1734 data.frames = out->managed_frames;
1735 data.hashes = &out->hashes;
1737 // FIXME: collect stack pointer for both and sort frames by SP
1738 // so people can see relative ordering of both managed and unmanaged frames.
1741 // Summarize managed stack
1743 mono_walk_stack_full (summarize_frame, out->ctx, out->domain, out->jit_tls, out->lmf, MONO_UNWIND_LOOKUP_IL_OFFSET, &data, TRUE);
1744 out->num_managed_frames = data.num_frames;
1746 if (data.error != NULL)
1747 out->error_msg = data.error;
1748 out->is_managed = (out->num_managed_frames != 0);
1751 // Always runs on the dumped thread
1752 static void
1753 mono_summarize_unmanaged_stack (MonoThreadSummary *out)
1755 MONO_ARCH_CONTEXT_DEF
1757 // Summarize unmanaged stack
1759 #ifdef HAVE_BACKTRACE_SYMBOLS
1760 intptr_t frame_ips [MONO_MAX_SUMMARY_FRAMES];
1762 out->num_unmanaged_frames = backtrace ((void **)frame_ips, MONO_MAX_SUMMARY_FRAMES);
1764 for (int i =0; i < out->num_unmanaged_frames; ++i) {
1765 intptr_t ip = frame_ips [i];
1766 MonoFrameSummary *frame = &out->unmanaged_frames [i];
1767 const char* module_buf = frame->unmanaged_data.module;
1768 int success = mono_get_portable_ip (ip, &frame->unmanaged_data.ip, &frame->unmanaged_data.offset, &module_buf, (char *) frame->str_descr);
1770 /* attempt to look up any managed method at that ip */
1771 /* TODO: Trampolines - follow examples from mono_print_method_from_ip() */
1773 MonoJitInfo *ji;
1774 MonoDomain *domain = mono_domain_get ();
1775 MonoDomain *target_domain;
1776 ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
1777 if (ji) {
1778 frame->is_managed = TRUE;
1779 if (!ji->async && !ji->is_trampoline) {
1780 MonoMethod *method = jinfo_get_method (ji);
1781 fill_frame_managed_info (frame, method);
1782 #ifndef MONO_PRIVATE_CRASHES
1783 frame->managed_data.name = method->name;
1784 #endif
1788 if (!success && !ji) {
1789 frame->unmanaged_data.ip = ip;
1790 continue;
1793 if (out->unmanaged_frames [i].str_descr [0] != '\0')
1794 out->unmanaged_frames [i].unmanaged_data.has_name = TRUE;
1796 out->hashes.offset_free_hash = summarize_offset_free_hash (out->hashes.offset_free_hash, frame);
1797 out->hashes.offset_rich_hash = summarize_offset_rich_hash (out->hashes.offset_rich_hash, frame);
1799 #endif
1801 out->lmf = mono_get_lmf ();
1803 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1804 out->info_addr = (intptr_t) thread;
1805 out->jit_tls = thread->jit_data;
1806 out->domain = mono_domain_get ();
1808 if (!out->ctx) {
1809 out->ctx = &out->ctx_mem;
1810 mono_arch_flush_register_windows ();
1811 MONO_INIT_CONTEXT_FROM_FUNC (out->ctx, mono_summarize_unmanaged_stack);
1814 return;
1816 #endif
1819 MonoBoolean
1820 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
1821 MonoReflectionMethod **method,
1822 gint32 *iloffset, gint32 *native_offset,
1823 MonoString **file, gint32 *line, gint32 *column)
1825 ERROR_DECL (error);
1826 MonoDomain *domain = mono_domain_get ();
1827 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
1828 MonoLMF *lmf = mono_get_lmf ();
1829 MonoJitInfo *ji = NULL;
1830 MonoContext ctx, new_ctx;
1831 MonoDebugSourceLocation *location;
1832 MonoMethod *jmethod = NULL, *actual_method;
1833 StackFrameInfo frame;
1834 gboolean res;
1835 Unwinder unwinder;
1836 int il_offset = -1;
1838 MONO_ARCH_CONTEXT_DEF;
1840 g_assert (skip >= 0);
1842 if (mono_llvm_only) {
1843 GSList *l, *ips;
1844 MonoDomain *frame_domain;
1845 guint8 *frame_ip = NULL;
1847 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1848 jmethod = NULL;
1849 ips = get_unwind_backtrace ();
1850 for (l = ips; l && skip >= 0; l = l->next) {
1851 guint8 *ip = (guint8*)l->data;
1853 frame_ip = ip;
1855 ji = mini_jit_info_table_find (mono_domain_get (), ip, &frame_domain);
1856 if (!ji || ji->is_trampoline)
1857 continue;
1859 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1860 jmethod = jinfo_get_method (ji);
1861 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1862 continue;
1863 skip--;
1865 g_slist_free (ips);
1866 if (!jmethod || !l)
1867 return FALSE;
1868 /* No way to resolve generic instances */
1869 actual_method = jmethod;
1870 *native_offset = frame_ip - (guint8*)ji->code_start;
1871 } else {
1872 mono_arch_flush_register_windows ();
1873 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
1875 unwinder_init (&unwinder);
1877 new_ctx = ctx;
1878 do {
1879 ctx = new_ctx;
1880 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1881 if (!res)
1882 return FALSE;
1883 switch (frame.type) {
1884 case FRAME_TYPE_MANAGED_TO_NATIVE:
1885 case FRAME_TYPE_DEBUGGER_INVOKE:
1886 case FRAME_TYPE_TRAMPOLINE:
1887 case FRAME_TYPE_INTERP_TO_MANAGED:
1888 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
1889 continue;
1890 case FRAME_TYPE_INTERP:
1891 case FRAME_TYPE_MANAGED:
1892 ji = frame.ji;
1893 *native_offset = frame.native_offset;
1895 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1896 jmethod = jinfo_get_method (ji);
1897 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1898 continue;
1899 skip--;
1900 break;
1901 default:
1902 g_assert_not_reached ();
1904 } while (skip >= 0);
1906 if (frame.type == FRAME_TYPE_INTERP) {
1907 jmethod = frame.method;
1908 actual_method = frame.actual_method;
1909 } else {
1910 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
1914 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, error);
1915 if (!is_ok (error)) {
1916 mono_error_set_pending_exception (error);
1917 return FALSE;
1919 mono_gc_wbarrier_generic_store_internal (method, (MonoObject*) rm);
1921 if (il_offset != -1) {
1922 location = mono_debug_lookup_source_location_by_il (jmethod, il_offset, domain);
1923 } else {
1924 location = mono_debug_lookup_source_location (jmethod, *native_offset, domain);
1926 if (location)
1927 *iloffset = location->il_offset;
1928 else
1929 *iloffset = 0;
1931 if (need_file_info) {
1932 if (location) {
1933 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1934 if (!is_ok (error)) {
1935 mono_error_set_pending_exception (error);
1936 return FALSE;
1938 mono_gc_wbarrier_generic_store_internal (file, (MonoObject*)filename);
1939 *line = location->row;
1940 *column = location->column;
1941 } else {
1942 *file = NULL;
1943 *line = *column = 0;
1947 mono_debug_free_source_location (location);
1949 return TRUE;
1952 static MonoClass*
1953 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1955 ERROR_DECL (error);
1956 MonoClass *catch_class = ei->data.catch_class;
1957 MonoType *inflated_type;
1958 MonoGenericContext context;
1960 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1961 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
1962 return NULL;
1964 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1965 return catch_class;
1966 context = mono_get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1968 /* FIXME: we shouldn't inflate but instead put the
1969 type in the rgctx and fetch it from there. It
1970 might be a good idea to do this lazily, i.e. only
1971 when the exception is actually thrown, so as not to
1972 waste space for exception clauses which might never
1973 be encountered. */
1974 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
1975 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1977 catch_class = mono_class_from_mono_type_internal (inflated_type);
1978 mono_metadata_free_type (inflated_type);
1980 return catch_class;
1984 * mini_jit_info_table_find_ext:
1986 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1987 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1988 * OUT_DOMAIN if it is not NULL.
1990 MonoJitInfo*
1991 mini_jit_info_table_find_ext (MonoDomain *domain, gpointer addr, gboolean allow_trampolines, MonoDomain **out_domain)
1993 MonoJitInfo *ji;
1994 MonoInternalThread *t = mono_thread_internal_current ();
1995 gpointer *refs;
1997 if (out_domain)
1998 *out_domain = NULL;
2000 ji = mono_jit_info_table_find_internal (domain, addr, TRUE, allow_trampolines);
2001 if (ji) {
2002 if (out_domain)
2003 *out_domain = domain;
2004 return ji;
2007 /* maybe it is shared code, so we also search in the root domain */
2008 if (domain != mono_get_root_domain ()) {
2009 ji = mono_jit_info_table_find_internal (mono_get_root_domain (), addr, TRUE, allow_trampolines);
2010 if (ji) {
2011 if (out_domain)
2012 *out_domain = mono_get_root_domain ();
2013 return ji;
2017 if (!t)
2018 return NULL;
2020 refs = (gpointer *)((t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL);
2021 for (; refs && *refs; refs++) {
2022 if (*refs != domain && *refs != mono_get_root_domain ()) {
2023 ji = mono_jit_info_table_find_internal ((MonoDomain*) *refs, addr, TRUE, allow_trampolines);
2024 if (ji) {
2025 if (out_domain)
2026 *out_domain = (MonoDomain*) *refs;
2027 return ji;
2032 return NULL;
2035 MonoJitInfo*
2036 mini_jit_info_table_find (MonoDomain *domain, gpointer addr, MonoDomain **out_domain)
2038 return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain);
2041 /* Class lazy loading functions */
2042 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
2045 * wrap_non_exception_throws:
2047 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
2048 * WrapNonExceptionThrows flag set.
2050 static gboolean
2051 wrap_non_exception_throws (MonoMethod *m)
2053 ERROR_DECL (error);
2054 MonoAssembly *ass = m_class_get_image (m->klass)->assembly;
2055 MonoCustomAttrInfo* attrs;
2056 MonoClass *klass;
2057 int i;
2058 gboolean val = FALSE;
2060 if (m->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
2061 MonoDynamicMethod *dm = (MonoDynamicMethod *)m;
2062 if (dm->assembly)
2063 ass = dm->assembly;
2065 g_assert (ass);
2066 if (ass->wrap_non_exception_throws_inited)
2067 return ass->wrap_non_exception_throws;
2069 klass = mono_class_get_runtime_compat_attr_class ();
2071 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, error);
2072 mono_error_cleanup (error); /* FIXME don't swallow the error */
2073 if (attrs) {
2074 for (i = 0; i < attrs->num_attrs; ++i) {
2075 MonoCustomAttrEntry *attr = &attrs->attrs [i];
2076 const gchar *p;
2077 int num_named, named_type, name_len;
2078 char *name;
2080 if (!attr->ctor || attr->ctor->klass != klass)
2081 continue;
2082 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
2083 p = (const char*)attr->data;
2084 g_assert (read16 (p) == 0x0001);
2085 p += 2;
2086 num_named = read16 (p);
2087 if (num_named != 1)
2088 continue;
2089 p += 2;
2090 named_type = *p;
2091 p ++;
2092 /* data_type = *p; */
2093 p ++;
2094 /* Property */
2095 if (named_type != 0x54)
2096 continue;
2097 name_len = mono_metadata_decode_blob_size (p, &p);
2098 name = (char *)g_malloc (name_len + 1);
2099 memcpy (name, p, name_len);
2100 name [name_len] = 0;
2101 p += name_len;
2102 g_assert (!strcmp (name, "WrapNonExceptionThrows"));
2103 g_free (name);
2104 /* The value is a BOOLEAN */
2105 val = *p;
2107 mono_custom_attrs_free (attrs);
2110 ass->wrap_non_exception_throws = val;
2111 mono_memory_barrier ();
2112 ass->wrap_non_exception_throws_inited = TRUE;
2114 return val;
2117 #define MAX_UNMANAGED_BACKTRACE 128
2118 static MonoArray*
2119 build_native_trace (MonoError *error)
2121 error_init (error);
2122 /* This puppy only makes sense on mobile, IOW, ARM. */
2123 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
2124 MonoArray *res;
2125 void *native_trace [MAX_UNMANAGED_BACKTRACE];
2126 int size = -1;
2127 MONO_ENTER_GC_SAFE;
2128 size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE);
2129 MONO_EXIT_GC_SAFE;
2130 int i;
2132 if (!size)
2133 return NULL;
2134 res = mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, size, error);
2135 return_val_if_nok (error, NULL);
2137 for (i = 0; i < size; i++)
2138 mono_array_set_internal (res, gpointer, i, native_trace [i]);
2139 return res;
2140 #else
2141 return NULL;
2142 #endif
2145 static void
2146 remove_wrappers_from_trace (GList **trace_ips_p)
2148 GList *trace_ips = *trace_ips_p;
2149 GList *p = trace_ips;
2151 /* jit info, generic info, ip */
2152 while (p) {
2153 MonoJitInfo *jinfo = (MonoJitInfo*) p->data;
2154 GList *next_p = p->next->next->next;
2155 /* FIXME Maybe remove more wrapper types */
2156 if (jinfo->d.method->wrapper_type == MONO_WRAPPER_OTHER) {
2157 trace_ips = g_list_delete_link (trace_ips, p->next->next);
2158 trace_ips = g_list_delete_link (trace_ips, p->next);
2159 trace_ips = g_list_delete_link (trace_ips, p);
2161 p = next_p;
2164 *trace_ips_p = trace_ips;
2167 /* This can be called more than once on a MonoException. */
2168 static void
2169 setup_stack_trace (MonoException *mono_ex, GSList **dynamic_methods, GList *trace_ips, gboolean remove_wrappers)
2171 if (mono_ex) {
2172 GList *trace_ips_copy = g_list_copy (trace_ips);
2173 if (remove_wrappers)
2174 remove_wrappers_from_trace (&trace_ips_copy);
2175 trace_ips_copy = g_list_reverse (trace_ips_copy);
2176 ERROR_DECL (error);
2177 MonoArray *ips_arr = mono_glist_to_array (trace_ips_copy, mono_defaults.int_class, error);
2178 mono_error_assert_ok (error);
2179 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
2180 MONO_OBJECT_SETREF_INTERNAL (mono_ex, native_trace_ips, build_native_trace (error));
2181 mono_error_assert_ok (error);
2182 if (*dynamic_methods) {
2183 /* These methods could go away anytime, so save a reference to them in the exception object */
2184 GSList *l;
2185 MonoMList *list = (MonoMList*)mono_ex->dynamic_methods;
2187 for (l = *dynamic_methods; l; l = l->next) {
2188 MonoGCHandle dis_link;
2189 MonoDomain *domain = mono_domain_get ();
2191 if (domain->method_to_dyn_method) {
2192 mono_domain_lock (domain);
2193 dis_link = (MonoGCHandle)g_hash_table_lookup (domain->method_to_dyn_method, l->data);
2194 mono_domain_unlock (domain);
2195 if (dis_link) {
2196 MonoObject *o = mono_gchandle_get_target_internal (dis_link);
2197 if (o) {
2198 list = mono_mlist_prepend_checked (list, o, error);
2199 mono_error_assert_ok (error);
2205 MONO_OBJECT_SETREF_INTERNAL (mono_ex, dynamic_methods, list);
2207 g_slist_free (*dynamic_methods);
2208 *dynamic_methods = NULL;
2211 g_list_free (trace_ips_copy);
2215 typedef enum {
2216 MONO_FIRST_PASS_UNHANDLED,
2217 MONO_FIRST_PASS_CALLBACK_TO_NATIVE,
2218 MONO_FIRST_PASS_HANDLED,
2219 } MonoFirstPassResult;
2222 * handle_exception_first_pass:
2224 * The first pass of exception handling. Unwind the stack until a catch
2225 * clause which can catch OBJ is found. Store the index of the filter clause
2226 * which caught the exception into OUT_FILTER_IDX. Return
2227 * \c MONO_FIRST_PASS_HANDLED if the exception is caught,
2228 * \c MONO_FIRST_PASS_UNHANDLED otherwise, unless there is a native-to-managed
2229 * wrapper and an exception handling callback is installed (in which case
2230 * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
2232 static MonoFirstPassResult
2233 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)
2235 ERROR_DECL (error);
2236 MonoDomain *domain = mono_domain_get ();
2237 MonoJitInfo *ji = NULL;
2238 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2239 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2240 MonoLMF *lmf = mono_get_lmf ();
2241 GList *trace_ips = NULL;
2242 GSList *dynamic_methods = NULL;
2243 MonoException *mono_ex;
2244 gboolean stack_overflow = FALSE;
2245 MonoContext initial_ctx;
2246 MonoMethod *method;
2247 int frame_count = 0;
2248 gint32 filter_idx;
2249 int i;
2250 MonoObject *ex_obj;
2251 Unwinder unwinder;
2252 gboolean in_interp;
2254 MonoFirstPassResult result = MONO_FIRST_PASS_UNHANDLED;
2256 g_assert (ctx != NULL);
2257 *last_mono_wrapper_runtime_invoke = TRUE;
2258 if (obj == (MonoObject *)domain->stack_overflow_ex)
2259 stack_overflow = TRUE;
2261 mono_ex = (MonoException*)obj;
2262 MonoArray *initial_trace_ips = mono_ex->trace_ips;
2263 if (initial_trace_ips) {
2264 int len = mono_array_length_internal (initial_trace_ips) / TRACE_IP_ENTRY_SIZE;
2266 // If we catch in managed/non-wrapper, we don't save the catching frame
2267 if (!mono_ex->caught_in_unmanaged)
2268 len -= 1;
2270 for (i = 0; i < len; i++) {
2271 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
2272 gpointer p = mono_array_get_internal (initial_trace_ips, gpointer, (i * TRACE_IP_ENTRY_SIZE) + j);
2273 trace_ips = g_list_prepend (trace_ips, p);
2278 // Reset the state because we're making it be caught somewhere
2279 if (mono_ex->caught_in_unmanaged)
2280 MONO_OBJECT_SETREF_INTERNAL (mono_ex, caught_in_unmanaged, 0);
2282 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2283 mono_error_assert_ok (error);
2284 mono_ex = NULL;
2287 if (!call_filter)
2288 call_filter = (int (*) (MonoContext *, void *))mono_get_call_filter ();
2290 g_assert (jit_tls->end_of_stack);
2291 g_assert (jit_tls->abort_func);
2293 if (out_filter_idx)
2294 *out_filter_idx = -1;
2295 if (out_ji)
2296 *out_ji = NULL;
2297 if (out_prev_ji)
2298 *out_prev_ji = NULL;
2299 filter_idx = 0;
2300 initial_ctx = *ctx;
2302 unwinder_init (&unwinder);
2304 while (1) {
2305 MonoContext new_ctx;
2306 guint32 free_stack;
2307 int clause_index_start = 0;
2308 gboolean unwind_res = TRUE;
2310 StackFrameInfo frame;
2312 if (out_prev_ji)
2313 *out_prev_ji = ji;
2315 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2316 if (!unwind_res) {
2317 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, FALSE);
2318 g_list_free (trace_ips);
2319 return result;
2322 switch (frame.type) {
2323 case FRAME_TYPE_DEBUGGER_INVOKE:
2324 case FRAME_TYPE_MANAGED_TO_NATIVE:
2325 case FRAME_TYPE_TRAMPOLINE:
2326 case FRAME_TYPE_INTERP_TO_MANAGED:
2327 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2328 *ctx = new_ctx;
2329 continue;
2330 case FRAME_TYPE_INTERP:
2331 case FRAME_TYPE_MANAGED:
2332 break;
2333 default:
2334 g_assert_not_reached ();
2335 break;
2338 in_interp = frame.type == FRAME_TYPE_INTERP;
2339 ji = frame.ji;
2341 gpointer ip;
2342 if (in_interp)
2343 ip = (guint8*)ji->code_start + frame.native_offset;
2344 else
2345 ip = MONO_CONTEXT_GET_IP (ctx);
2347 frame_count ++;
2348 method = jinfo_get_method (ji);
2349 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2351 if (mini_debug_options.reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2352 g_error ("A native frame was found while unwinding the stack after an exception.\n"
2353 "The native frame called the managed method:\n%s\n",
2354 mono_method_full_name (method, TRUE));
2357 if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
2358 // avoid giant stack traces during a stack overflow
2359 if (frame_count < 1000) {
2360 trace_ips = g_list_prepend (trace_ips, ip);
2361 trace_ips = g_list_prepend (trace_ips, get_generic_info_from_stack_frame (ji, ctx));
2362 trace_ips = g_list_prepend (trace_ips, ji);
2366 if (method->dynamic)
2367 dynamic_methods = g_slist_prepend (dynamic_methods, method);
2369 if (stack_overflow) {
2370 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2371 } else {
2372 free_stack = 0xffffff;
2375 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && ftnptr_eh_callback) {
2376 result = MONO_FIRST_PASS_CALLBACK_TO_NATIVE;
2380 for (i = clause_index_start; i < ji->num_clauses; i++) {
2381 MonoJitExceptionInfo *ei = &ji->clauses [i];
2382 gboolean filtered = FALSE;
2385 * During stack overflow, wait till the unwinding frees some stack
2386 * space before running handlers/finalizers.
2388 if (free_stack <= (64 * 1024))
2389 continue;
2391 if (is_address_protected (ji, ei, ip)) {
2392 /* catch block */
2393 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2396 * Have to unwrap RuntimeWrappedExceptions if the
2397 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2399 if (non_exception && !wrap_non_exception_throws (method))
2400 ex_obj = non_exception;
2401 else
2402 ex_obj = obj;
2404 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2405 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, FALSE);
2407 #ifndef DISABLE_PERFCOUNTERS
2408 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_filters);
2409 #endif
2411 if (!ji->is_interp) {
2412 #ifndef MONO_CROSS_COMPILE
2413 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2414 if (ji->from_llvm)
2415 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2416 else
2417 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
2418 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2419 #else
2420 g_assert (!ji->from_llvm);
2421 /* store the exception object in bp + ei->exvar_offset */
2422 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2423 #endif
2424 #endif
2426 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2428 * Pass the original il clause index to the landing pad so it can
2429 * branch to the landing pad associated with the il clause.
2430 * This is needed because llvm compiled code assumes that the EH
2431 * code always branches to the innermost landing pad.
2433 if (ji->from_llvm)
2434 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2435 #endif
2438 mini_get_dbg_callbacks ()->begin_exception_filter (mono_ex, ctx, &initial_ctx);
2440 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2441 jit_tls->orig_ex_ctx_set = TRUE;
2442 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2443 jit_tls->orig_ex_ctx_set = FALSE;
2446 if (ji->is_interp) {
2447 /* The filter ends where the exception handler starts */
2448 filtered = mini_get_interp_callbacks ()->run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter, ei->handler_start);
2449 } else {
2450 filtered = call_filter (ctx, ei->data.filter);
2452 mini_get_dbg_callbacks ()->end_exception_filter (mono_ex, ctx, &initial_ctx);
2453 if (filtered && out_filter_idx)
2454 *out_filter_idx = filter_idx;
2455 if (out_ji)
2456 *out_ji = ji;
2457 filter_idx ++;
2459 if (filtered) {
2460 g_list_free (trace_ips);
2461 /* mono_debugger_agent_handle_exception () needs this */
2462 mini_set_abort_threshold (&frame);
2463 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2464 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
2465 *catch_frame = frame;
2466 result = MONO_FIRST_PASS_HANDLED;
2467 return result;
2471 ERROR_DECL (isinst_error); // FIXME not used https://github.com/mono/mono/pull/3055/files#r240548187
2472 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, error)) {
2473 /* runtime invokes catch even unhandled exceptions */
2474 setup_stack_trace (mono_ex, &dynamic_methods, trace_ips, method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE);
2475 g_list_free (trace_ips);
2477 if (out_ji)
2478 *out_ji = ji;
2480 /* mono_debugger_agent_handle_exception () needs this */
2481 if (!in_interp)
2482 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2483 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
2484 *catch_frame = frame;
2485 result = MONO_FIRST_PASS_HANDLED;
2486 if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2487 //try to find threadpool_perform_wait_callback_method
2488 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &new_ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2489 while (unwind_res) {
2490 if (frame.ji && !frame.ji->is_trampoline && jinfo_get_method (frame.ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2491 *last_mono_wrapper_runtime_invoke = FALSE;
2492 break;
2494 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &new_ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2497 return result;
2499 mono_error_cleanup (isinst_error);
2503 *ctx = new_ctx;
2506 g_assert_not_reached ();
2510 * We implement delaying of aborts when in finally blocks by reusing the
2511 * abort protected block mechanism. The problem is that when throwing an
2512 * exception in a finally block we don't get to exit the protected block.
2513 * We exit it here when unwinding. Given that the order of the clauses
2514 * in the jit info is from inner clauses to the outer clauses, when we
2515 * want to exit the finally blocks inner to the clause that handles the
2516 * exception, we need to search up to its index.
2518 * FIXME We should do this inside interp, but with mixed mode we can
2519 * resume directly, without giving control back to the interp.
2521 static void
2522 interp_exit_finally_abort_blocks (MonoJitInfo *ji, int start_clause, int end_clause, gpointer ip)
2524 int i;
2525 for (i = start_clause; i < end_clause; i++) {
2526 MonoJitExceptionInfo *ei = &ji->clauses [i];
2527 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY &&
2528 ip >= ei->handler_start &&
2529 ip < ei->data.handler_end) {
2530 mono_threads_end_abort_protected_block ();
2535 static MonoException *
2536 mono_get_exception_runtime_wrapped_checked (MonoObject *wrapped_exception_raw, MonoError *error)
2538 HANDLE_FUNCTION_ENTER ();
2539 MONO_HANDLE_DCL (MonoObject, wrapped_exception);
2540 MonoExceptionHandle ret = mono_get_exception_runtime_wrapped_handle (wrapped_exception, error);
2541 HANDLE_FUNCTION_RETURN_OBJ (ret);
2545 * mono_handle_exception_internal:
2546 * \param ctx saved processor state
2547 * \param obj the exception object
2548 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
2550 static gboolean
2551 mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji)
2553 ERROR_DECL (error);
2554 MonoDomain *domain = mono_domain_get ();
2555 MonoJitInfo *ji, *prev_ji;
2556 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2557 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
2558 MonoLMF *lmf = mono_get_lmf ();
2559 MonoException *mono_ex;
2560 gboolean stack_overflow = FALSE;
2561 MonoContext initial_ctx;
2562 MonoMethod *method;
2563 int frame_count = 0;
2564 gint32 filter_idx, first_filter_idx = 0;
2565 int i;
2566 MonoObject *ex_obj = NULL;
2567 MonoObject *non_exception = NULL;
2568 Unwinder unwinder;
2569 gboolean in_interp;
2570 gboolean is_caught_unmanaged = FALSE;
2571 gboolean last_mono_wrapper_runtime_invoke = TRUE;
2573 g_assert (ctx != NULL);
2574 if (!obj) {
2575 MonoException *ex = mono_get_exception_null_reference ();
2576 MonoString *msg = mono_string_new_checked (domain, "Object reference not set to an instance of an object", error);
2577 mono_error_assert_ok (error);
2578 MONO_OBJECT_SETREF_INTERNAL (ex, message, msg);
2579 obj = (MonoObject *)ex;
2583 * Allocate a new exception object instead of the preconstructed ones.
2585 if (obj == (MonoObject *)domain->stack_overflow_ex) {
2587 * It is not a good idea to try and put even more pressure on the little stack available.
2588 * obj = mono_get_exception_stack_overflow ();
2590 stack_overflow = TRUE;
2592 else if (obj == (MonoObject *)domain->null_reference_ex) {
2593 obj = (MonoObject *)mono_get_exception_null_reference ();
2596 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2597 mono_error_assert_ok (error);
2598 non_exception = obj;
2599 obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, error);
2600 mono_error_assert_ok (error);
2603 mono_ex = (MonoException*)obj;
2605 if (mini_debug_options.suspend_on_exception) {
2606 mono_runtime_printf_err ("Exception thrown, suspending...");
2607 while (1)
2611 if (mono_ex->caught_in_unmanaged)
2612 is_caught_unmanaged = TRUE;
2615 if (mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
2616 mono_ex = (MonoException*)obj;
2617 } else {
2618 mono_error_assert_ok (error);
2619 mono_ex = NULL;
2622 if (mono_ex && jit_tls->class_cast_from) {
2623 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "InvalidCastException")) {
2624 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
2625 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
2626 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
2627 mono_ex->message = mono_string_new_checked (domain, msg, error);
2628 g_free (from_name);
2629 g_free (to_name);
2630 if (!is_ok (error)) {
2631 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg);
2632 mono_error_assert_ok (error);
2634 g_free (msg);
2636 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "ArrayTypeMismatchException")) {
2637 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
2638 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
2639 char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
2640 mono_ex->message = mono_string_new_checked (domain, msg, error);
2641 g_free (from_name);
2642 g_free (to_name);
2643 if (!is_ok (error)) {
2644 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg);
2645 mono_error_assert_ok (error);
2647 g_free (msg);
2651 if (!call_filter)
2652 call_filter = (int (*)(MonoContext *, void*))mono_get_call_filter ();
2654 g_assert (jit_tls->end_of_stack);
2655 g_assert (jit_tls->abort_func);
2658 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
2659 * end up being TRUE on any code path.
2661 memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
2663 if (!resume) {
2664 MonoContext ctx_cp = *ctx;
2665 if (mono_trace_is_enabled ()) {
2666 ERROR_DECL (error);
2667 MonoMethod *system_exception_get_message = mono_class_get_method_from_name_checked (mono_defaults.exception_class, "get_Message", 0, 0, error);
2668 mono_error_cleanup (error);
2669 error_init (error);
2670 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method_internal (obj, system_exception_get_message);
2671 MonoObject *message;
2672 const char *type_name = m_class_get_name (mono_object_class (mono_ex));
2673 char *msg = NULL;
2674 if (get_message == NULL) {
2675 message = NULL;
2676 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
2677 message = NULL;
2678 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
2679 } else {
2680 MonoObject *exc = NULL;
2681 message = mono_runtime_try_invoke (get_message, obj, NULL, &exc, error);
2682 g_assert (exc == NULL);
2683 mono_error_assert_ok (error);
2685 if (msg == NULL) {
2686 if (message) {
2687 msg = mono_string_to_utf8_checked_internal ((MonoString *) message, error);
2688 if (!is_ok (error)) {
2689 mono_error_cleanup (error);
2690 msg = g_strdup ("(error while display System.Exception.Message property)");
2692 } else {
2693 msg = g_strdup ("(System.Exception.Message property not available)");
2696 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)(gsize)mono_native_thread_id_get (), m_class_get_name_space (mono_object_class (obj)), m_class_get_name (mono_object_class (obj)), msg);
2697 g_free (msg);
2698 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
2699 mono_print_thread_dump_from_ctx (ctx);
2701 jit_tls->orig_ex_ctx_set = TRUE;
2702 MONO_PROFILER_RAISE (exception_throw, (obj));
2703 jit_tls->orig_ex_ctx_set = FALSE;
2705 #ifdef ENABLE_NETCORE
2706 mono_first_chance_exception_internal (obj);
2707 #endif
2709 StackFrameInfo catch_frame;
2710 MonoFirstPassResult res;
2711 res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame, &last_mono_wrapper_runtime_invoke);
2713 if (res == MONO_FIRST_PASS_UNHANDLED) {
2714 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2715 /* Reached the top interpreted frames, but there might be native frames above us */
2716 throw_exception (obj, TRUE);
2717 g_assert_not_reached ();
2719 if (mini_debug_options.break_on_exc)
2720 G_BREAKPOINT ();
2721 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2723 // FIXME: This runs managed code so it might cause another stack overflow when
2724 // we are handling a stack overflow
2725 mini_set_abort_threshold (&catch_frame);
2726 mono_unhandled_exception_internal (obj);
2727 } else {
2728 gboolean unhandled = FALSE;
2731 * The exceptions caught by the mono_runtime_invoke_checked () calls
2732 * in the threadpool needs to be treated as unhandled (#669836).
2734 * FIXME: The check below is hackish, but its hard to distinguish
2735 * these runtime invoke calls from others in the runtime.
2737 #ifndef ENABLE_NETCORE
2738 if (ji && jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2739 if (prev_ji && jinfo_get_method (prev_ji) == mono_defaults.threadpool_perform_wait_callback_method)
2740 unhandled = TRUE;
2742 #endif
2744 if (unhandled)
2745 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2746 else if (!ji || (jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
2747 if (last_mono_wrapper_runtime_invoke && !mono_thread_internal_current ()->threadpool_thread) {
2748 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2749 if (mini_get_debug_options ()->top_runtime_invoke_unhandled) {
2750 mini_set_abort_threshold (&catch_frame);
2751 mono_unhandled_exception_internal (obj);
2753 } else {
2754 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2757 else if (res != MONO_FIRST_PASS_CALLBACK_TO_NATIVE)
2758 if (!is_caught_unmanaged)
2759 mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2763 if (out_ji)
2764 *out_ji = NULL;
2765 filter_idx = 0;
2766 initial_ctx = *ctx;
2768 unwinder_init (&unwinder);
2770 while (1) {
2771 MonoContext new_ctx;
2772 guint32 free_stack;
2773 int clause_index_start = 0;
2774 gboolean unwind_res = TRUE;
2775 StackFrameInfo frame;
2776 gpointer ip;
2778 if (resume) {
2779 resume = FALSE;
2780 ji = jit_tls->resume_state.ji;
2781 new_ctx = jit_tls->resume_state.new_ctx;
2782 clause_index_start = jit_tls->resume_state.clause_index;
2783 lmf = jit_tls->resume_state.lmf;
2784 first_filter_idx = jit_tls->resume_state.first_filter_idx;
2785 filter_idx = jit_tls->resume_state.filter_idx;
2786 in_interp = FALSE;
2787 } else {
2788 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2789 if (!unwind_res) {
2790 *(mono_get_lmf_addr ()) = lmf;
2792 jit_tls->abort_func (obj);
2793 g_assert_not_reached ();
2795 switch (frame.type) {
2796 case FRAME_TYPE_DEBUGGER_INVOKE:
2797 case FRAME_TYPE_MANAGED_TO_NATIVE:
2798 case FRAME_TYPE_TRAMPOLINE:
2799 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2800 *ctx = new_ctx;
2801 continue;
2802 case FRAME_TYPE_INTERP_TO_MANAGED:
2803 continue;
2804 case FRAME_TYPE_INTERP:
2805 case FRAME_TYPE_MANAGED:
2806 break;
2807 default:
2808 g_assert_not_reached ();
2809 break;
2811 in_interp = frame.type == FRAME_TYPE_INTERP;
2812 ji = frame.ji;
2815 if (in_interp)
2816 ip = (guint8*)ji->code_start + frame.native_offset;
2817 else
2818 ip = MONO_CONTEXT_GET_IP (ctx);
2820 method = jinfo_get_method (ji);
2821 frame_count ++;
2822 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2824 if (stack_overflow) {
2825 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2826 } else {
2827 free_stack = 0xffffff;
2830 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && ftnptr_eh_callback) {
2831 MonoGCHandle handle = mono_gchandle_new_internal (obj, FALSE);
2832 MONO_STACKDATA (stackptr);
2834 mono_threads_enter_gc_safe_region_unbalanced_internal (&stackptr);
2835 mono_set_lmf (lmf);
2836 ftnptr_eh_callback (handle);
2837 g_error ("Did not expect ftnptr_eh_callback to return.");
2840 for (i = clause_index_start; i < ji->num_clauses; i++) {
2841 MonoJitExceptionInfo *ei = &ji->clauses [i];
2842 gboolean filtered = FALSE;
2845 * During stack overflow, wait till the unwinding frees some stack
2846 * space before running handlers/finalizers.
2848 if (free_stack <= (64 * 1024))
2849 continue;
2851 if (is_address_protected (ji, ei, ip)) {
2852 /* catch block */
2853 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2856 * Have to unwrap RuntimeWrappedExceptions if the
2857 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2859 if (non_exception && !wrap_non_exception_throws (method))
2860 ex_obj = non_exception;
2861 else
2862 ex_obj = obj;
2864 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
2865 #ifndef MONO_CROSS_COMPILE
2866 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2867 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2868 #else
2869 g_assert (!ji->from_llvm);
2870 /* store the exception object in bp + ei->exvar_offset */
2871 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2872 #endif
2873 #endif
2876 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2877 if (ji->from_llvm)
2878 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2879 #endif
2881 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2883 * Filter clauses should only be run in the
2884 * first pass of exception handling.
2886 filtered = (filter_idx == first_filter_idx);
2887 filter_idx ++;
2890 error_init (error);
2891 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
2892 mono_object_isinst_checked (ex_obj, catch_class, error)) || filtered) {
2894 * This guards against the situation that we abort a thread that is executing a finally clause
2895 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2896 * check for this situation here and resume interruption if we are below the guarded block.
2898 if (G_UNLIKELY (jit_tls->handler_block)) {
2899 gboolean is_outside = FALSE;
2900 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
2901 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
2902 //FIXME make this stack direction aware
2904 if (catch_bp > prot_bp) {
2905 is_outside = TRUE;
2906 } else if (catch_bp == prot_bp) {
2907 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2908 * So we check if the catch handler_start is protected by the guarded handler protected region
2910 * Assumptions:
2911 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2912 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2913 * There aren't any further finally/fault handler blocks down the stack over this exception.
2914 * This must be ensured by the code that installs the guard trampoline.
2916 g_assert (ji == mini_jit_info_table_find (domain, (char *)MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
2918 if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
2919 is_outside = TRUE;
2922 if (is_outside) {
2923 jit_tls->handler_block = NULL;
2924 mono_thread_resume_interruption (TRUE); /*We ignore the exception here, it will be raised later*/
2928 if (mono_trace_is_enabled () && mono_trace_eval (method))
2929 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2932 * At this point, ei->flags can be either MONO_EXCEPTION_CLAUSE_NONE for a
2933 * a try-catch clause or MONO_EXCEPTION_CLAUSE_FILTER for a try-filter-catch
2934 * clause. Since we specifically want to indicate that we're executing the
2935 * catch portion of this EH clause, pass MONO_EXCEPTION_CLAUSE_NONE explicitly
2936 * instead of ei->flags.
2938 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2939 jit_tls->orig_ex_ctx_set = TRUE;
2940 MONO_PROFILER_RAISE (exception_clause, (method, i, MONO_EXCEPTION_CLAUSE_NONE, ex_obj));
2941 jit_tls->orig_ex_ctx_set = FALSE;
2944 mini_set_abort_threshold (&frame);
2946 if (in_interp) {
2947 interp_exit_finally_abort_blocks (ji, clause_index_start, i, ip);
2949 * ctx->pc points into the interpreter, after the call which transitioned to
2950 * JITted code. Store the unwind state into the
2951 * interpeter state, then resume, the interpreter will unwind itself until
2952 * it reaches the target frame and will continue execution from there.
2953 * The resuming is kinda hackish, from the native code standpoint, it looks
2954 * like the call which transitioned to JITted code has succeeded, but the
2955 * return value register etc. is not set, so we have to be careful.
2957 mini_get_interp_callbacks ()->set_resume_state (jit_tls, ex_obj, ei, frame.interp_frame, ei->handler_start);
2958 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2959 /* ip == 0 means an interpreter frame */
2960 if (MONO_CONTEXT_GET_IP (ctx) != 0)
2961 mono_arch_undo_ip_adjustment (ctx);
2962 } else {
2963 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2965 mono_set_lmf (lmf);
2966 #ifndef DISABLE_PERFCOUNTERS
2967 mono_atomic_fetch_add_i32 (&mono_perfcounters->exceptions_depth, frame_count);
2968 #endif
2969 if (obj == (MonoObject *)domain->stack_overflow_ex)
2970 jit_tls->handling_stack_ovf = FALSE;
2972 return 0;
2974 mono_error_cleanup (error);
2975 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
2976 if (mono_trace_is_enabled () && mono_trace_eval (method))
2977 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2979 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2980 jit_tls->orig_ex_ctx_set = TRUE;
2981 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2982 jit_tls->orig_ex_ctx_set = FALSE;
2985 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2986 if (mono_trace_is_enabled () && mono_trace_eval (method))
2987 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2989 if (G_UNLIKELY (mono_profiler_clauses_enabled ())) {
2990 jit_tls->orig_ex_ctx_set = TRUE;
2991 MONO_PROFILER_RAISE (exception_clause, (method, i, (MonoExceptionEnum)ei->flags, ex_obj));
2992 jit_tls->orig_ex_ctx_set = FALSE;
2995 #ifndef DISABLE_PERFCOUNTERS
2996 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_finallys);
2997 #endif
2999 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
3000 mono_set_lmf (lmf);
3001 if (ji->from_llvm) {
3003 * LLVM compiled finally handlers follow the design
3004 * of the c++ ehabi, i.e. they call a resume function
3005 * at the end instead of returning to the caller.
3006 * So save the exception handling state,
3007 * mono_resume_unwind () will call us again to continue
3008 * the unwinding.
3010 jit_tls->resume_state.ex_obj = obj;
3011 jit_tls->resume_state.ji = ji;
3012 jit_tls->resume_state.clause_index = i + 1;
3013 jit_tls->resume_state.ctx = *ctx;
3014 jit_tls->resume_state.new_ctx = new_ctx;
3015 jit_tls->resume_state.lmf = lmf;
3016 jit_tls->resume_state.first_filter_idx = first_filter_idx;
3017 jit_tls->resume_state.filter_idx = filter_idx;
3018 mini_set_abort_threshold (&frame);
3019 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
3020 return 0;
3021 } else {
3022 mini_set_abort_threshold (&frame);
3023 if (in_interp) {
3024 gboolean has_ex = mini_get_interp_callbacks ()->run_finally (&frame, i, ei->handler_start, ei->data.handler_end);
3025 if (has_ex) {
3027 * If run_finally didn't resume to a context, it means that the handler frame
3028 * is linked to the frame calling finally through interpreter frames. This
3029 * means that we will reach the handler frame by resuming the current context.
3031 if (MONO_CONTEXT_GET_IP (ctx) != 0)
3032 mono_arch_undo_ip_adjustment (ctx);
3033 return 0;
3035 } else {
3036 call_filter (ctx, ei->handler_start);
3043 if (in_interp)
3044 interp_exit_finally_abort_blocks (ji, clause_index_start, ji->num_clauses, ip);
3046 if (MONO_PROFILER_ENABLED (method_exception_leave) &&
3047 mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) {
3048 jit_tls->orig_ex_ctx_set = TRUE;
3049 MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
3050 jit_tls->orig_ex_ctx_set = FALSE;
3053 *ctx = new_ctx;
3056 g_assert_not_reached ();
3060 * mono_debugger_run_finally:
3061 * \param start_ctx saved processor state
3062 * This method is called by the Mono Debugger to call all \c finally clauses of the
3063 * current stack frame. It's used when the user issues a \c return command to make
3064 * the current stack frame return. After returning from this method, the debugger
3065 * unwinds the stack one frame and gives control back to the user.
3066 * NOTE: This method is only used when running inside the Mono Debugger.
3068 void
3069 mono_debugger_run_finally (MonoContext *start_ctx)
3071 static int (*call_filter) (MonoContext *, gpointer) = NULL;
3072 MonoDomain *domain = mono_domain_get ();
3073 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3074 MonoLMF *lmf = mono_get_lmf ();
3075 MonoContext ctx, new_ctx;
3076 MonoJitInfo *ji, rji;
3077 int i;
3079 ctx = *start_ctx;
3081 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
3082 if (!ji || ji == (gpointer)-1)
3083 return;
3085 if (!call_filter)
3086 call_filter = (int (*)(MonoContext *, void *))mono_get_call_filter ();
3088 for (i = 0; i < ji->num_clauses; i++) {
3089 MonoJitExceptionInfo *ei = &ji->clauses [i];
3091 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
3092 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
3093 call_filter (&ctx, ei->handler_start);
3099 * mono_handle_exception:
3100 * \param ctx saved processor state
3101 * \param obj the exception object
3103 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
3104 * return TRUE.
3106 gboolean
3107 mono_handle_exception (MonoContext *ctx, gpointer void_obj)
3109 MonoObject *obj = (MonoObject*)void_obj;
3111 MONO_REQ_GC_UNSAFE_MODE;
3113 #ifndef DISABLE_PERFCOUNTERS
3114 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_thrown);
3115 #endif
3117 return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
3120 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3122 #ifndef MONO_ARCH_USE_SIGACTION
3123 #error "Can't use sigaltstack without sigaction"
3124 #endif
3126 void
3127 mono_setup_altstack (MonoJitTlsData *tls)
3129 size_t stsize = 0;
3130 stack_t sa;
3131 guint8 *staddr = NULL;
3132 #if defined(TARGET_OSX) || defined(_AIX)
3134 * On macOS Mojave we are encountering a bug when changing mapping for main thread
3135 * stack pages. Stack overflow on main thread will kill the app.
3137 * AIX seems problematic as well; it gives ENOMEM for mprotect and valloc, if we
3138 * do this for thread 1 with its stack at the top of memory. Other threads seem
3139 * fine for the altstack guard page, though.
3141 gboolean disable_stack_guard = mono_threads_platform_is_main_thread ();
3142 #else
3143 gboolean disable_stack_guard = FALSE;
3144 #endif
3146 if (mono_running_on_valgrind ())
3147 return;
3149 mono_thread_info_get_stack_bounds (&staddr, &stsize);
3151 g_assert (staddr);
3153 tls->end_of_stack = staddr + stsize;
3154 tls->stack_size = stsize;
3156 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
3158 if (!disable_stack_guard) {
3159 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
3160 tls->stack_ovf_guard_size = ALIGN_TO (MONO_STACK_OVERFLOW_GUARD_SIZE, mono_pagesize ());
3162 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
3164 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
3165 /* mprotect can fail for the main thread stack */
3166 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);
3167 if (gaddr) {
3168 g_assert (gaddr == tls->stack_ovf_guard_base);
3169 tls->stack_ovf_valloced = TRUE;
3170 } else {
3171 g_warning ("couldn't allocate guard page, continue without it");
3172 tls->stack_ovf_guard_base = NULL;
3173 tls->stack_ovf_guard_size = 0;
3178 /* Setup an alternate signal stack */
3179 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);
3180 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3182 g_assert (tls->signal_stack);
3184 sa.ss_sp = tls->signal_stack;
3185 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3186 sa.ss_flags = 0;
3187 g_assert (sigaltstack (&sa, NULL) == 0);
3189 if (tls->stack_ovf_guard_base)
3190 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);
3191 else
3192 mono_gc_register_altstack (staddr, stsize, tls->signal_stack, tls->signal_stack_size);
3196 void
3197 mono_free_altstack (MonoJitTlsData *tls)
3199 stack_t sa;
3200 int err;
3202 sa.ss_sp = tls->signal_stack;
3203 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
3204 sa.ss_flags = SS_DISABLE;
3205 err = sigaltstack (&sa, NULL);
3206 g_assert (err == 0);
3208 if (tls->signal_stack)
3209 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MEM_ACCOUNT_EXCEPTIONS);
3211 if (!tls->stack_ovf_guard_base)
3212 return;
3213 if (tls->stack_ovf_valloced)
3214 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MEM_ACCOUNT_EXCEPTIONS);
3215 else
3216 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3219 #elif G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32)
3220 void
3221 mono_setup_altstack (MonoJitTlsData *tls)
3223 // Alt stack is not supported on Windows, but we can use this point to at least
3224 // reserve a stack guarantee of available stack memory when handling stack overflow.
3225 ULONG new_stack_guarantee = (ULONG)ALIGN_TO (MONO_STACK_OVERFLOW_GUARD_SIZE, ((gssize)mono_pagesize ()));
3226 SetThreadStackGuarantee (&new_stack_guarantee);
3229 void
3230 mono_free_altstack (MonoJitTlsData *tls)
3234 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3236 void
3237 mono_setup_altstack (MonoJitTlsData *tls)
3241 void
3242 mono_free_altstack (MonoJitTlsData *tls)
3246 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
3248 gboolean
3249 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
3251 if (!jit_tls)
3252 return FALSE;
3254 if (mono_llvm_only)
3255 return FALSE;
3257 /* we got a stack overflow in the soft-guard pages
3258 * There are two cases:
3259 * 1) managed code caused the overflow: we unprotect the soft-guard page
3260 * and let the arch-specific code trigger the exception handling mechanism
3261 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
3262 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
3263 * and hope we can continue with those enabled, at least until the hard-guard page
3264 * is hit. The alternative to continuing here is to just print a message and abort.
3265 * We may add in the future the code to protect the pages again in the codepath
3266 * when we return from unmanaged to managed code.
3268 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
3269 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
3270 gboolean handled = FALSE;
3272 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
3273 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3274 if (ji) {
3275 mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE);
3276 handled = TRUE;
3278 #endif
3279 if (!handled) {
3280 /* We print a message: after this even managed stack overflows
3281 * may crash the runtime
3283 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
3284 if (!jit_tls->handling_stack_ovf) {
3285 jit_tls->handling_stack_ovf = 1;
3286 } else {
3287 /*fprintf (stderr, "Already handling stack overflow\n");*/
3290 return TRUE;
3292 return FALSE;
3295 typedef struct {
3296 MonoMethod *omethod;
3297 int count;
3298 } PrintOverflowUserData;
3300 static gboolean
3301 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3303 MonoMethod *method = NULL;
3304 PrintOverflowUserData *user_data = (PrintOverflowUserData *)data;
3305 gchar *location;
3307 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3308 method = jinfo_get_method (frame->ji);
3310 if (method) {
3311 if (user_data->count == 0) {
3312 /* The first frame is in its prolog, so a line number cannot be computed */
3313 user_data->count ++;
3314 return FALSE;
3317 /* If this is a one method overflow, skip the other instances */
3318 if (method == user_data->omethod)
3319 return FALSE;
3321 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
3322 mono_runtime_printf_err (" %s", location);
3323 g_free (location);
3325 if (user_data->count == 1) {
3326 mono_runtime_printf_err (" <...>");
3327 user_data->omethod = method;
3328 } else {
3329 user_data->omethod = NULL;
3332 user_data->count ++;
3333 } else
3334 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame->native_offset);
3336 return FALSE;
3339 void
3340 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *mctx, guint8* fault_addr)
3342 PrintOverflowUserData ud;
3344 /* we don't do much now, but we can warn the user with a useful message */
3345 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", MONO_CONTEXT_GET_IP (mctx), fault_addr);
3347 mono_runtime_printf_err ("Stacktrace:");
3349 memset (&ud, 0, sizeof (ud));
3351 mono_walk_stack_with_ctx (print_overflow_stack_frame, mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
3353 _exit (1);
3356 static gboolean
3357 print_stack_frame_signal_safe (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3359 MonoMethod *method = NULL;
3361 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3362 method = jinfo_get_method (frame->ji);
3364 if (method) {
3365 const char *name_space = m_class_get_name_space (method->klass);
3366 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);
3367 } else {
3368 g_async_safe_printf("\t at <unknown> <0x%05x>\n", frame->native_offset);
3371 return FALSE;
3374 static G_GNUC_UNUSED gboolean
3375 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3377 GString *p = (GString*)data;
3378 MonoMethod *method = NULL;
3380 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
3381 method = jinfo_get_method (frame->ji);
3383 if (method && frame->domain) {
3384 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3385 g_string_append_printf (p, " %s\n", location);
3386 g_free (location);
3387 } else
3388 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3390 return FALSE;
3393 #ifndef MONO_CROSS_COMPILE
3396 * mono_handle_native_crash:
3398 * Handle a native crash (e.g. SIGSEGV) while in native code by
3399 * printing diagnostic information and aborting.
3401 void
3402 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3404 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3406 #ifdef MONO_ARCH_USE_SIGACTION
3407 struct sigaction sa;
3408 sa.sa_handler = SIG_DFL;
3409 sigemptyset (&sa.sa_mask);
3410 sa.sa_flags = 0;
3412 /* Remove our SIGABRT handler */
3413 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
3415 /* On some systems we get a SIGILL when calling abort (), because it might
3416 * fail to raise SIGABRT */
3417 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
3419 /* Remove SIGCHLD, it uses the finalizer thread */
3420 g_assert (sigaction (SIGCHLD, &sa, NULL) != -1);
3422 /* Remove SIGQUIT, we are already dumping threads */
3423 g_assert (sigaction (SIGQUIT, &sa, NULL) != -1);
3425 #endif
3427 if (mini_debug_options.suspend_on_native_crash) {
3428 g_async_safe_printf ("Received %s, suspending...\n", signal);
3429 while (1) {
3430 // Sleep for 1 second.
3431 g_usleep (1000 * 1000);
3436 * A crash indicates something went very wrong so we can no longer depend
3437 * on anything working. So try to print out lots of diagnostics, starting
3438 * with ones which have a greater chance of working.
3441 g_async_safe_printf("\n=================================================================\n");
3442 g_async_safe_printf("\tNative Crash Reporting\n");
3443 g_async_safe_printf("=================================================================\n");
3444 g_async_safe_printf("Got a %s while executing native code. This usually indicates\n", signal);
3445 g_async_safe_printf("a fatal error in the mono runtime or one of the native libraries \n");
3446 g_async_safe_printf("used by your application.\n");
3447 g_async_safe_printf("=================================================================\n");
3448 mono_dump_native_crash_info (signal, mctx, info);
3450 /* !jit_tls means the thread was not registered with the runtime */
3451 // This must be below the native crash dump, because we can't safely
3452 // do runtime state probing after we have walked the managed stack here.
3453 if (jit_tls && mono_thread_internal_current () && mctx) {
3454 g_async_safe_printf ("\n=================================================================\n");
3455 g_async_safe_printf ("\tManaged Stacktrace:\n");
3456 g_async_safe_printf ("=================================================================\n");
3458 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);
3459 g_async_safe_printf ("=================================================================\n");
3462 mono_post_native_crash_handler (signal, mctx, info, mono_do_crash_chaining);
3465 #else
3467 void
3468 mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
3470 g_assert_not_reached ();
3473 #endif /* !MONO_CROSS_COMPILE */
3475 static void
3476 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
3478 MonoInternalThread *thread = mono_thread_internal_current ();
3479 MonoContext ctx;
3480 GString* text;
3482 if (!thread)
3483 return;
3485 text = g_string_new (0);
3487 mono_gstring_append_thread_name (text, thread);
3489 g_string_append_printf (text, " tid=%p this=%p ", (gpointer)(gsize)thread->tid, thread);
3490 mono_thread_internal_describe (thread, text);
3491 g_string_append (text, "\n");
3493 if (start_ctx) {
3494 memcpy (&ctx, start_ctx, sizeof (MonoContext));
3495 } else if (!sigctx)
3496 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
3497 else
3498 mono_sigctx_to_monoctx (sigctx, &ctx);
3500 mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
3502 mono_runtime_printf ("%s", text->str);
3504 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
3505 OutputDebugStringA(text->str);
3506 #endif
3508 g_string_free (text, TRUE);
3509 mono_runtime_stdout_fflush ();
3513 * mono_print_thread_dump:
3515 * Print information about the current thread to stdout.
3516 * \p sigctx can be NULL, allowing this to be called from gdb.
3518 void
3519 mono_print_thread_dump (void *sigctx)
3521 mono_print_thread_dump_internal (sigctx, NULL);
3524 void
3525 mono_print_thread_dump_from_ctx (MonoContext *ctx)
3527 mono_print_thread_dump_internal (NULL, ctx);
3531 * mono_resume_unwind:
3533 * This is called by a trampoline from LLVM compiled finally clauses to continue
3534 * unwinding.
3536 void
3537 mono_resume_unwind (MonoContext *ctx)
3539 MONO_REQ_GC_UNSAFE_MODE;
3541 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3542 MonoContext new_ctx;
3544 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
3545 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
3546 new_ctx = *ctx;
3548 mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL);
3550 mono_restore_context (&new_ctx);
3553 typedef struct {
3554 MonoJitInfo *ji;
3555 MonoContext ctx;
3556 MonoJitExceptionInfo *ei;
3557 } FindHandlerBlockData;
3559 static gboolean
3560 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
3562 int i;
3563 gpointer ip;
3564 FindHandlerBlockData *pdata = (FindHandlerBlockData *)data;
3565 MonoJitInfo *ji = frame->ji;
3567 if (!ji)
3568 return FALSE;
3570 ip = MONO_CONTEXT_GET_IP (ctx);
3572 for (i = 0; i < ji->num_clauses; ++i) {
3573 MonoJitExceptionInfo *ei = ji->clauses + i;
3574 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3575 continue;
3576 /*If ip points to the first instruction it means the handler block didn't start
3577 so we can leave its execution to the EH machinery*/
3578 if (ei->handler_start <= ip && ip < ei->data.handler_end) {
3579 pdata->ji = ji;
3580 pdata->ei = ei;
3581 pdata->ctx = *ctx;
3582 break;
3585 return FALSE;
3589 static void
3590 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
3592 int i;
3593 MonoJitExceptionInfo *clause = NULL;
3594 gpointer ip;
3595 guint8 *bp;
3597 ip = MONO_CONTEXT_GET_IP (ctx);
3599 for (i = 0; i < ji->num_clauses; ++i) {
3600 clause = &ji->clauses [i];
3601 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3602 continue;
3603 if (clause->handler_start <= ip && clause->data.handler_end > ip)
3604 break;
3607 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
3608 g_assert (i < ji->num_clauses);
3610 /*Load the spvar*/
3611 bp = (guint8*)MONO_CONTEXT_GET_BP (ctx);
3612 *(bp + clause->exvar_offset) = 1;
3616 * Finds the bottom handler block running and install a block guard if needed.
3618 static gboolean
3619 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
3621 FindHandlerBlockData data = { 0 };
3622 MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
3624 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3625 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3627 if (!jit_tls || jit_tls->handler_block)
3628 return FALSE;
3630 /* Do an async safe stack walk */
3631 mono_thread_info_set_is_async_context (TRUE);
3632 mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data);
3633 mono_thread_info_set_is_async_context (FALSE);
3635 if (!data.ji)
3636 return FALSE;
3638 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
3640 install_handler_block_guard (data.ji, &data.ctx);
3642 jit_tls->handler_block = data.ei;
3644 return TRUE;
3647 static void
3648 mono_uninstall_current_handler_block_guard (void)
3650 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3651 if (jit_tls)
3652 jit_tls->handler_block = NULL;
3656 static gboolean
3657 mono_current_thread_has_handle_block_guard (void)
3659 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3660 return jit_tls && jit_tls->handler_block != NULL;
3663 void
3664 mono_set_cast_details (MonoClass *from, MonoClass *to)
3666 MonoJitTlsData *jit_tls = NULL;
3668 if (mini_debug_options.better_cast_details) {
3669 jit_tls = mono_tls_get_jit_tls ();
3670 jit_tls->class_cast_from = from;
3671 jit_tls->class_cast_to = to;
3676 /*returns false if the thread is not attached*/
3677 gboolean
3678 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
3680 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3681 if (!thread) {
3682 ctx->valid = FALSE;
3683 return FALSE;
3686 if (sigctx) {
3687 mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
3689 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3690 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3691 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3693 else {
3694 mono_thread_state_init (ctx);
3697 if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
3698 return FALSE;
3700 ctx->valid = TRUE;
3701 return TRUE;
3704 void
3705 mono_thread_state_init (MonoThreadUnwindState *ctx)
3707 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3709 #if defined(MONO_CROSS_COMPILE)
3710 ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
3711 #elif MONO_ARCH_HAS_MONO_CONTEXT
3712 MONO_CONTEXT_GET_CURRENT (ctx->ctx);
3713 #else
3714 g_error ("Use a null sigctx requires a working mono-context");
3715 #endif
3717 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3718 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3719 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
3720 ctx->valid = TRUE;
3724 gboolean
3725 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
3727 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3728 if (!thread) {
3729 ctx->valid = FALSE;
3730 return FALSE;
3733 ctx->ctx = *mctx;
3734 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3735 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3736 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3737 ctx->valid = TRUE;
3738 return TRUE;
3741 /*returns false if the thread is not attached*/
3742 gboolean
3743 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
3745 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3746 MONO_ARCH_CONTEXT_DEF
3748 mono_arch_flush_register_windows ();
3750 if (!thread || !thread->jit_data) {
3751 ctx->valid = FALSE;
3752 return FALSE;
3754 MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
3756 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3757 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3758 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3759 ctx->valid = TRUE;
3760 return TRUE;
3763 static void
3764 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
3766 mono_handle_exception (ctx, (MonoObject *)exc);
3767 mono_restore_context (ctx);
3770 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3771 void
3772 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
3774 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3775 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
3776 jit_tls->ex_ctx = *ctx;
3778 mono_arch_setup_async_callback (ctx, async_cb, user_data);
3779 #else
3780 g_error ("This target doesn't support mono_arch_setup_async_callback");
3781 #endif
3785 * mono_restore_context:
3787 * Call the architecture specific restore context function.
3789 void
3790 mono_restore_context (MonoContext *ctx)
3792 static void (*restore_context) (MonoContext *);
3794 if (!restore_context)
3795 restore_context = (void (*)(MonoContext *))mono_get_restore_context ();
3796 restore_context (ctx);
3797 g_assert_not_reached ();
3801 * mono_jinfo_get_unwind_info:
3803 * Return the unwind info for JI.
3805 guint8*
3806 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
3808 if (ji->has_unwind_info) {
3809 /* The address/length in the MonoJitInfo structure itself */
3810 MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji);
3811 *unwind_info_len = info->unw_info_len;
3812 return info->unw_info;
3813 } else if (ji->from_aot)
3814 return mono_aot_get_unwind_info (ji, unwind_info_len);
3815 else
3816 return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
3820 mono_jinfo_get_epilog_size (MonoJitInfo *ji)
3822 MonoArchEHJitInfo *info;
3824 info = mono_jit_info_get_arch_eh_info (ji);
3825 g_assert (info);
3827 return info->epilog_size;
3831 * mono_install_ftnptr_eh_callback:
3833 * Install a callback that should be called when there is a managed exception
3834 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
3835 * managed exception to a native exception, to properly unwind the native
3836 * stack; this native exception will then be converted back to a managed
3837 * exception in their managed-to-native wrapper.
3839 void
3840 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
3842 ftnptr_eh_callback = callback;
3846 * LLVM/Bitcode exception handling.
3849 static void
3850 throw_exception (MonoObject *ex, gboolean rethrow)
3852 MONO_REQ_GC_UNSAFE_MODE;
3854 ERROR_DECL (error);
3855 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3856 MonoException *mono_ex;
3858 if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, error)) {
3859 mono_error_assert_ok (error);
3860 mono_ex = mono_get_exception_runtime_wrapped_checked (ex, error);
3861 mono_error_assert_ok (error);
3862 jit_tls->thrown_non_exc = mono_gchandle_new_internal (ex, FALSE);
3864 else
3865 mono_ex = (MonoException*)ex;
3867 // Note: Not pinned
3868 jit_tls->thrown_exc = mono_gchandle_new_internal ((MonoObject*)mono_ex, FALSE);
3870 if (!rethrow) {
3871 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3872 GList *l, *ips = NULL;
3873 GList *trace;
3875 _Unwind_Backtrace (build_stack_trace, &ips);
3876 /* The list contains ip-gshared info pairs */
3877 trace = NULL;
3878 ips = g_list_reverse (ips);
3879 for (l = ips; l; l = l->next) {
3880 trace = g_list_append (trace, l->data);
3881 trace = g_list_append (trace, NULL);
3882 trace = g_list_append (trace, NULL);
3884 MonoArray *ips_arr = mono_glist_to_array (trace, mono_defaults.int_class, error);
3885 mono_error_assert_ok (error);
3886 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3887 g_list_free (l);
3888 g_list_free (trace);
3889 #endif
3892 mono_llvm_cpp_throw_exception ();
3895 void
3896 mono_llvm_throw_exception (MonoObject *ex)
3898 throw_exception (ex, FALSE);
3901 void
3902 mono_llvm_rethrow_exception (MonoObject *ex)
3904 throw_exception (ex, TRUE);
3907 void
3908 mono_llvm_raise_exception (MonoException *e)
3910 mono_llvm_throw_exception ((MonoObject*)e);
3913 void
3914 mono_llvm_reraise_exception (MonoException *e)
3916 mono_llvm_rethrow_exception ((MonoObject*)e);
3919 void
3920 mono_llvm_throw_corlib_exception (guint32 ex_token_index)
3922 guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
3923 MonoException *ex;
3925 ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token);
3927 mono_llvm_throw_exception ((MonoObject*)ex);
3931 * mono_llvm_resume_exception:
3933 * Resume exception propagation.
3935 void
3936 mono_llvm_resume_exception (void)
3938 mono_llvm_cpp_throw_exception ();
3942 * mono_llvm_load_exception:
3944 * Return the currently thrown exception.
3946 MonoObject *
3947 mono_llvm_load_exception (void)
3949 ERROR_DECL (error);
3950 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3952 MonoException *mono_ex = (MonoException*)mono_gchandle_get_target_internal (jit_tls->thrown_exc);
3954 MonoArray *ta = mono_ex->trace_ips;
3956 if (ta) {
3957 GList *trace_ips = NULL;
3958 gpointer ip = MONO_RETURN_ADDRESS ();
3960 size_t upper = mono_array_length_internal (ta);
3962 for (int i = 0; i < upper; i += TRACE_IP_ENTRY_SIZE) {
3963 gpointer curr_ip = mono_array_get_internal (ta, gpointer, i);
3964 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
3965 gpointer p = mono_array_get_internal (ta, gpointer, i + j);
3966 trace_ips = g_list_append (trace_ips, p);
3968 if (ip == curr_ip)
3969 break;
3972 // FIXME: Does this work correctly for rethrows?
3973 // We may be discarding useful information
3974 // when this gets GC'ed
3975 MonoArray *ips_arr = mono_glist_to_array (trace_ips, mono_defaults.int_class, error);
3976 mono_error_assert_ok (error);
3977 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, ips_arr);
3978 g_list_free (trace_ips);
3980 // FIXME:
3981 //MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3982 } else {
3983 MONO_OBJECT_SETREF_INTERNAL (mono_ex, trace_ips, mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, 0, error));
3984 mono_error_assert_ok (error);
3985 MONO_OBJECT_SETREF_INTERNAL (mono_ex, stack_trace, mono_array_new_checked (mono_domain_get (), mono_defaults.stack_frame_class, 0, error));
3986 mono_error_assert_ok (error);
3989 return &mono_ex->object;
3993 * mono_llvm_clear_exception:
3995 * Mark the currently thrown exception as handled.
3997 void
3998 mono_llvm_clear_exception (void)
4000 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
4001 mono_gchandle_free_internal (jit_tls->thrown_exc);
4002 jit_tls->thrown_exc = 0;
4003 if (jit_tls->thrown_non_exc)
4004 mono_gchandle_free_internal (jit_tls->thrown_non_exc);
4005 jit_tls->thrown_non_exc = 0;
4007 mono_memory_barrier ();
4011 * mono_llvm_match_exception:
4013 * Return the innermost clause containing REGION_START-REGION_END which can handle
4014 * the current exception.
4016 gint32
4017 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
4019 ERROR_DECL (error);
4020 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
4021 MonoObject *exc;
4022 gint32 index = -1;
4024 g_assert (jit_tls->thrown_exc);
4025 exc = mono_gchandle_get_target_internal (jit_tls->thrown_exc);
4026 if (jit_tls->thrown_non_exc) {
4028 * Have to unwrap RuntimeWrappedExceptions if the
4029 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
4031 if (!wrap_non_exception_throws (jinfo_get_method (jinfo)))
4032 exc = mono_gchandle_get_target_internal (jit_tls->thrown_non_exc);
4035 for (int i = 0; i < jinfo->num_clauses; i++) {
4036 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
4037 MonoClass *catch_class;
4039 if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
4040 continue;
4042 catch_class = ei->data.catch_class;
4043 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class))) {
4044 MonoGenericContext context;
4045 MonoType *inflated_type;
4047 g_assert (rgctx || this_obj);
4048 context = mono_get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
4049 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
4050 mono_error_assert_ok (error); /* FIXME don't swallow the error */
4052 catch_class = mono_class_from_mono_type_internal (inflated_type);
4053 mono_metadata_free_type (inflated_type);
4056 // FIXME: Handle edge cases handled in get_exception_catch_class
4057 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, error)) {
4058 index = ei->clause_index;
4059 break;
4060 } else
4061 mono_error_assert_ok (error);
4063 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4064 g_assert_not_reached ();
4068 return index;
4071 #if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
4072 G_EXTERN_C _Unwind_Reason_Code mono_debug_personality (int a, _Unwind_Action b,
4073 uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
4075 g_assert_not_reached ();
4077 #else
4078 G_EXTERN_C void mono_debug_personality (void);
4080 void
4081 mono_debug_personality (void)
4083 g_assert_not_reached ();
4085 #endif