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