[mini] Use MonoClass getters in a few files (#7771)
[mono-project.git] / mono / mini / mini-exceptions.c
blob03193a176fd653c7178b93648ef49328e0f8195b
1 /**
2 * \file
3 * generic exception support
5 * Authors:
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Mono Team (mono-list@lists.ximian.com)
9 * Copyright 2001-2003 Ximian, Inc.
10 * Copyright 2003-2008 Novell, Inc.
11 * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <config.h>
16 #include <glib.h>
17 #include <string.h>
19 #ifdef HAVE_SIGNAL_H
20 #include <signal.h>
21 #endif
23 #ifdef HAVE_EXECINFO_H
24 #include <execinfo.h>
25 #endif
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
31 #ifdef HAVE_SYS_WAIT_H
32 #include <sys/wait.h>
33 #endif
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
39 #ifdef HAVE_SYS_SYSCALL_H
40 #include <sys/syscall.h>
41 #endif
43 #ifdef HAVE_SYS_PRCTL_H
44 #include <sys/prctl.h>
45 #endif
47 #ifdef HAVE_UNWIND_H
48 #include <unwind.h>
49 #endif
51 #include <mono/metadata/appdomain.h>
52 #include <mono/metadata/tabledefs.h>
53 #include <mono/metadata/threads.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/exception.h>
57 #include <mono/metadata/exception-internals.h>
58 #include <mono/metadata/object-internals.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/metadata/debug-internals.h>
62 #include <mono/metadata/mono-debug.h>
63 #include <mono/metadata/profiler-private.h>
64 #include <mono/metadata/mono-endian.h>
65 #include <mono/metadata/environment.h>
66 #include <mono/metadata/mono-mlist.h>
67 #include <mono/utils/mono-merp.h>
68 #include <mono/utils/mono-mmap.h>
69 #include <mono/utils/mono-logger-internals.h>
70 #include <mono/utils/mono-error.h>
71 #include <mono/utils/mono-error-internals.h>
73 #include "mini.h"
74 #include "trace.h"
75 #include "debugger-agent.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
96 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
97 * This structure represents one entry.
98 * This should consists of pointers only.
100 typedef struct
102 gpointer ip;
103 gpointer generic_info;
104 /* Only for interpreter frames */
105 MonoJitInfo *ji;
106 } ExceptionTraceIp;
108 /* Number of words in trace_ips belonging to one entry */
109 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
111 static gpointer restore_context_func, call_filter_func;
112 static gpointer throw_exception_func, rethrow_exception_func;
113 static gpointer throw_corlib_exception_func;
115 static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data);
116 static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx);
117 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
118 static gboolean mono_current_thread_has_handle_block_guard (void);
119 static gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx);
120 static void mono_uninstall_current_handler_block_guard (void);
122 static gboolean
123 first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
125 gpointer **data = (gpointer **)addr;
127 if (!frame->managed)
128 return FALSE;
130 if (!ctx) {
131 // FIXME: Happens with llvm_only
132 *data = NULL;
133 return TRUE;
136 *data = frame->frame_addr;
137 g_assert (*data);
138 return TRUE;
141 static gpointer
142 mono_thread_get_managed_sp (void)
144 gpointer addr = NULL;
145 mono_walk_stack (first_managed, MONO_UNWIND_SIGNAL_SAFE, &addr);
146 return addr;
149 static inline void
150 mini_clear_abort_threshold (void)
152 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
153 jit_tls->abort_exc_stack_threshold = NULL;
156 static inline void
157 mini_set_abort_threshold (StackFrameInfo *frame)
159 gpointer sp = frame->frame_addr;
160 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
161 // Only move it up, to avoid thrown/caught
162 // exceptions lower in the stack from triggering
163 // a rethrow
164 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
165 if (!jit_tls->abort_exc_stack_threshold || above_threshold) {
166 jit_tls->abort_exc_stack_threshold = sp;
170 // Note: In the case that the frame is above where the thread abort
171 // was set we bump the threshold so that functions called from the new,
172 // higher threshold don't trigger the thread abort exception
173 static inline gboolean
174 mini_above_abort_threshold (void)
176 gpointer sp = mono_thread_get_managed_sp ();
177 MonoJitTlsData *jit_tls = (MonoJitTlsData*) mono_tls_get_jit_tls ();
179 if (!sp)
180 return TRUE;
182 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
184 if (above_threshold)
185 jit_tls->abort_exc_stack_threshold = sp;
187 return above_threshold;
190 static int
191 mono_get_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
193 SeqPoint sp;
194 if (mono_find_prev_seq_point_for_native_offset (domain, method, native_offset, NULL, &sp))
195 return sp.il_offset;
196 return -1;
199 void
200 mono_exceptions_init (void)
202 MonoRuntimeExceptionHandlingCallbacks cbs;
203 if (mono_aot_only) {
204 restore_context_func = mono_aot_get_trampoline ("restore_context");
205 call_filter_func = mono_aot_get_trampoline ("call_filter");
206 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
207 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
208 } else {
209 MonoTrampInfo *info;
211 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
212 mono_tramp_info_register (info, NULL);
213 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
214 mono_tramp_info_register (info, NULL);
215 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
216 mono_tramp_info_register (info, NULL);
217 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
218 mono_tramp_info_register (info, NULL);
221 mono_arch_exceptions_init ();
223 cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
224 cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
226 if (mono_llvm_only) {
227 cbs.mono_raise_exception = mono_llvm_raise_exception;
228 cbs.mono_reraise_exception = mono_llvm_reraise_exception;
229 } else {
230 cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception ();
231 cbs.mono_reraise_exception = (void (*)(MonoException *))mono_get_rethrow_exception ();
233 cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
234 cbs.mono_exception_walk_trace = mono_exception_walk_trace;
235 cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
236 cbs.mono_uninstall_current_handler_block_guard = mono_uninstall_current_handler_block_guard;
237 cbs.mono_current_thread_has_handle_block_guard = mono_current_thread_has_handle_block_guard;
238 cbs.mono_clear_abort_threshold = mini_clear_abort_threshold;
239 cbs.mono_above_abort_threshold = mini_above_abort_threshold;
240 mono_install_eh_callbacks (&cbs);
241 mono_install_get_seq_point (mono_get_seq_point_for_native_offset);
244 gpointer
245 mono_get_throw_exception (void)
247 g_assert (throw_exception_func);
248 return throw_exception_func;
251 gpointer
252 mono_get_rethrow_exception (void)
254 g_assert (rethrow_exception_func);
255 return rethrow_exception_func;
258 gpointer
259 mono_get_call_filter (void)
261 g_assert (call_filter_func);
262 return call_filter_func;
265 gpointer
266 mono_get_restore_context (void)
268 g_assert (restore_context_func);
269 return restore_context_func;
272 gpointer
273 mono_get_throw_corlib_exception (void)
275 gpointer code = NULL;
276 MonoTrampInfo *info;
278 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
279 if (throw_corlib_exception_func)
280 return throw_corlib_exception_func;
282 if (mono_aot_only)
283 code = mono_aot_get_trampoline ("throw_corlib_exception");
284 else {
285 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
286 mono_tramp_info_register (info, NULL);
289 mono_memory_barrier ();
291 throw_corlib_exception_func = code;
293 return throw_corlib_exception_func;
297 * mono_get_throw_exception_addr:
299 * Return an address which stores the result of
300 * mono_get_throw_exception.
302 gpointer
303 mono_get_throw_exception_addr (void)
305 return &throw_exception_func;
308 static gboolean
309 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
311 MonoTryBlockHoleTableJitInfo *table;
312 int i;
313 guint32 offset;
314 guint16 clause;
316 if (ei->try_start > ip || ip >= ei->try_end)
317 return FALSE;
319 if (!ji->has_try_block_holes)
320 return TRUE;
322 table = mono_jit_info_get_try_block_hole_table_info (ji);
323 offset = (guint32)((char*)ip - (char*)ji->code_start);
324 clause = (guint16)(ei - ji->clauses);
325 g_assert (clause < ji->num_clauses);
327 for (i = 0; i < table->num_holes; ++i) {
328 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
329 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
330 return FALSE;
332 return TRUE;
335 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
337 #if 0
338 static gboolean show_native_addresses = TRUE;
339 #else
340 static gboolean show_native_addresses = FALSE;
341 #endif
343 static _Unwind_Reason_Code
344 build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
346 MonoDomain *domain = mono_domain_get ();
347 uintptr_t ip = _Unwind_GetIP (frame_ctx);
349 if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
350 GList **trace_ips = (GList **)state;
351 *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
354 return _URC_NO_REASON;
357 static GSList*
358 get_unwind_backtrace (void)
360 GSList *ips = NULL;
362 _Unwind_Backtrace (build_stack_trace, &ips);
364 return g_slist_reverse (ips);
367 #else
369 static GSList*
370 get_unwind_backtrace (void)
372 return NULL;
375 #endif
377 static gboolean
378 arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
379 MonoJitInfo *ji, MonoContext *ctx,
380 MonoContext *new_ctx, MonoLMF **lmf,
381 mgreg_t **save_locations,
382 StackFrameInfo *frame)
384 if (!ji && *lmf) {
385 if (((guint64)(*lmf)->previous_lmf) & 2) {
386 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
388 memset (frame, 0, sizeof (StackFrameInfo));
389 frame->ji = ji;
391 *new_ctx = *ctx;
393 if (ext->debugger_invoke) {
395 * This LMF entry is created by the soft debug code to mark transitions to
396 * managed code done during invokes.
398 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
399 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
400 } else if (ext->interp_exit) {
401 frame->type = FRAME_TYPE_INTERP_TO_MANAGED;
402 frame->interp_exit_data = ext->interp_exit_data;
403 } else {
404 g_assert_not_reached ();
407 *lmf = (MonoLMF *)(((guint64)(*lmf)->previous_lmf) & ~3);
409 return TRUE;
413 return mono_arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
417 * find_jit_info:
419 * Translate between the mono_arch_unwind_frame function and the old API.
421 static MonoJitInfo *
422 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
423 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
425 StackFrameInfo frame;
426 MonoJitInfo *ji;
427 gboolean err;
428 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
430 /* Avoid costly table lookup during stack overflow */
431 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
432 ji = prev_ji;
433 else
434 ji = mini_jit_info_table_find (domain, ip, NULL);
436 if (managed)
437 *managed = FALSE;
439 err = arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
440 if (!err)
441 return (MonoJitInfo *)-1;
443 if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
445 * Remove any unused lmf.
446 * Mask out the lower bits which might be used to hold additional information.
448 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(SIZEOF_VOID_P -1));
451 /* Convert between the new and the old APIs */
452 switch (frame.type) {
453 case FRAME_TYPE_MANAGED:
454 if (managed)
455 *managed = TRUE;
456 return frame.ji;
457 case FRAME_TYPE_TRAMPOLINE:
458 return frame.ji;
459 case FRAME_TYPE_MANAGED_TO_NATIVE:
460 if (frame.ji)
461 return frame.ji;
462 else {
463 memset (res, 0, sizeof (MonoJitInfo));
464 res->d.method = frame.method;
465 return res;
467 case FRAME_TYPE_DEBUGGER_INVOKE: {
468 MonoContext tmp_ctx;
471 * The normal exception handling code can't handle this frame, so just
472 * skip it.
474 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
475 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
476 return ji;
478 default:
479 g_assert_not_reached ();
480 return NULL;
484 /* mono_find_jit_info:
486 * This function is used to gather information from @ctx. It return the
487 * MonoJitInfo of the corresponding function, unwinds one stack frame and
488 * stores the resulting context into @new_ctx. It also stores a string
489 * describing the stack location into @trace (if not NULL), and modifies
490 * the @lmf if necessary. @native_offset return the IP offset from the
491 * start of the function or -1 if that info is not available.
493 MonoJitInfo *
494 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
495 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
496 gboolean *managed)
498 gboolean managed2;
499 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
500 MonoJitInfo *ji;
501 MonoMethod *method = NULL;
503 if (trace)
504 *trace = NULL;
506 if (native_offset)
507 *native_offset = -1;
509 if (managed)
510 *managed = FALSE;
512 ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
514 if (ji == (gpointer)-1)
515 return ji;
517 if (ji && !ji->is_trampoline)
518 method = jinfo_get_method (ji);
520 if (managed2 || (method && method->wrapper_type)) {
521 const char *real_ip, *start;
522 gint32 offset;
524 start = (const char *)ji->code_start;
525 if (!managed2)
526 /* ctx->ip points into native code */
527 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
528 else
529 real_ip = (const char*)ip;
531 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
532 offset = real_ip - start;
533 else
534 offset = -1;
536 if (native_offset)
537 *native_offset = offset;
539 if (managed)
540 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
541 *managed = TRUE;
543 if (trace)
544 *trace = mono_debug_print_stack_frame (method, offset, domain);
545 } else {
546 if (trace) {
547 char *fname = mono_method_full_name (jinfo_get_method (res), TRUE);
548 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
549 g_free (fname);
553 return ji;
557 * mono_find_jit_info_ext:
559 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
560 * structure.
561 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
562 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
563 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
564 * to obtain the last managed frame.
565 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
566 * On return, it will be filled with the locations where callee saved registers are saved
567 * by the current frame. This is returned outside of StackFrameInfo because it can be
568 * quite large on some platforms.
569 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
570 * not be set.
572 gboolean
573 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
574 MonoJitInfo *prev_ji, MonoContext *ctx,
575 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
576 mgreg_t **save_locations,
577 StackFrameInfo *frame)
579 gboolean err;
580 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
581 MonoJitInfo *ji;
582 MonoDomain *target_domain = domain;
583 MonoMethod *method = NULL;
584 gboolean async = mono_thread_info_is_async_context ();
586 if (trace)
587 *trace = NULL;
589 /* Avoid costly table lookup during stack overflow */
590 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
591 ji = prev_ji;
592 else
593 ji = mini_jit_info_table_find (domain, ip, &target_domain);
595 if (!target_domain)
596 target_domain = domain;
598 if (save_locations)
599 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (mgreg_t*));
601 err = arch_unwind_frame (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
602 if (!err)
603 return FALSE;
605 if (frame->type != FRAME_TYPE_INTERP_TO_MANAGED && *lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
607 * Remove any unused lmf.
608 * Mask out the lower bits which might be used to hold additional information.
610 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(SIZEOF_VOID_P -1));
613 if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async)
614 method = jinfo_get_method (frame->ji);
616 if (frame->type == FRAME_TYPE_MANAGED && method) {
617 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
618 frame->managed = TRUE;
621 if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
623 * This type of frame is just a marker, the caller should unwind once more to get the
624 * last managed frame.
626 frame->ji = NULL;
627 frame->method = NULL;
630 frame->native_offset = -1;
631 frame->domain = target_domain;
632 frame->async_context = async;
633 frame->frame_addr = MONO_CONTEXT_GET_SP (ctx);
635 ji = frame->ji;
637 if (frame->type == FRAME_TYPE_MANAGED)
638 frame->method = method;
640 if (ji && (frame->managed || (method && method->wrapper_type))) {
641 const char *real_ip, *start;
643 start = (const char *)ji->code_start;
644 if (frame->type == FRAME_TYPE_MANAGED)
645 real_ip = (const char*)ip;
646 else
647 /* ctx->ip points into native code */
648 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
650 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
651 frame->native_offset = real_ip - start;
652 else {
653 frame->native_offset = -1;
656 if (trace)
657 *trace = mono_debug_print_stack_frame (method, frame->native_offset, domain);
658 } else {
659 if (trace && frame->method) {
660 char *fname = mono_method_full_name (frame->method, TRUE);
661 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
662 g_free (fname);
666 return TRUE;
669 typedef struct {
670 gboolean in_interp;
671 MonoInterpStackIter interp_iter;
672 gpointer last_frame_addr;
673 } Unwinder;
675 static void
676 unwinder_init (Unwinder *unwinder)
678 memset (unwinder, 0, sizeof (Unwinder));
681 #if defined(__GNUC__) && defined(TARGET_ARM64)
682 /* gcc 4.9.2 seems to miscompile this on arm64 */
683 static __attribute__((optimize("O0"))) gboolean
684 #else
685 static gboolean
686 #endif
687 unwinder_unwind_frame (Unwinder *unwinder,
688 MonoDomain *domain, MonoJitTlsData *jit_tls,
689 MonoJitInfo *prev_ji, MonoContext *ctx,
690 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
691 mgreg_t **save_locations,
692 StackFrameInfo *frame)
694 gpointer parent;
695 if (unwinder->in_interp) {
696 memcpy (new_ctx, ctx, sizeof (MonoContext));
698 /* Process debugger invokes */
699 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
700 if (unwinder->last_frame_addr > (gpointer)(*lmf)) {
701 if (((guint64)(*lmf)->previous_lmf) & 2) {
702 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
703 if (ext->debugger_invoke) {
704 *lmf = (MonoLMF *)(((guint64)(*lmf)->previous_lmf) & ~7);
705 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
706 return TRUE;
711 unwinder->in_interp = mini_get_interp_callbacks ()->frame_iter_next (&unwinder->interp_iter, frame);
712 if (frame->type == FRAME_TYPE_INTERP) {
713 parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame);
714 unwinder->last_frame_addr = parent;
716 if (!unwinder->in_interp)
717 return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame);
718 return TRUE;
719 } else {
720 gboolean res = mono_find_jit_info_ext (domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf,
721 save_locations, frame);
722 if (!res)
723 return FALSE;
724 if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED) {
725 unwinder->in_interp = TRUE;
726 mini_get_interp_callbacks ()->frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data);
728 unwinder->last_frame_addr = frame->frame_addr;
729 return TRUE;
734 * This function is async-safe.
736 static gpointer
737 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
739 MonoGenericJitInfo *gi;
740 MonoMethod *method;
741 gpointer info;
743 if (!ji->has_generic_jit_info)
744 return NULL;
745 gi = mono_jit_info_get_generic_jit_info (ji);
746 if (!gi->has_this)
747 return NULL;
749 info = NULL;
751 * Search location list if available, it contains the precise location of the
752 * argument for every pc offset, even if the method was interrupted while it was in
753 * its prolog.
755 if (gi->nlocs) {
756 int offset = (mgreg_t)MONO_CONTEXT_GET_IP (ctx) - (mgreg_t)ji->code_start;
757 int i;
759 for (i = 0; i < gi->nlocs; ++i) {
760 MonoDwarfLocListEntry *entry = &gi->locations [i];
762 if (offset >= entry->from && (offset < entry->to || entry->to == 0)) {
763 if (entry->is_reg)
764 info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg);
765 else
766 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset);
767 break;
770 g_assert (i < gi->nlocs);
771 } else {
772 if (gi->this_in_reg)
773 info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg);
774 else
775 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
776 gi->this_offset);
779 method = jinfo_get_method (ji);
780 if (mono_method_get_context (method)->method_inst) {
781 /* A MonoMethodRuntimeGenericContext* */
782 return info;
783 } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || m_class_is_valuetype (method->klass)) {
784 /* A MonoVTable* */
785 return info;
786 } else {
787 /* Avoid returning a managed object */
788 MonoObject *this_obj = (MonoObject *)info;
790 return this_obj->vtable;
795 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
797 static MonoGenericContext
798 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
800 MonoGenericContext context = { NULL, NULL };
801 MonoClass *klass, *method_container_class;
802 MonoMethod *method;
804 g_assert (generic_info);
806 method = jinfo_get_method (ji);
807 g_assert (method->is_inflated);
808 if (mono_method_get_context (method)->method_inst) {
809 MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext *)generic_info;
811 klass = mrgctx->class_vtable->klass;
812 context.method_inst = mrgctx->method_inst;
813 g_assert (context.method_inst);
814 } else {
815 MonoVTable *vtable = (MonoVTable *)generic_info;
817 klass = vtable->klass;
820 //g_assert (!mono_class_is_gtd (method->klass));
821 if (mono_class_is_ginst (method->klass))
822 method_container_class = mono_class_get_generic_class (method->klass)->container_class;
823 else
824 method_container_class = method->klass;
826 /* class might refer to a subclass of method's class */
827 while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) {
828 klass = m_class_get_parent (klass);
829 g_assert (klass);
832 if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass))
833 context.class_inst = mini_class_get_context (klass)->class_inst;
835 if (mono_class_is_ginst (klass))
836 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass)->container_class, method_container_class));
837 else
838 g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class));
840 return context;
843 static MonoMethod*
844 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
846 ERROR_DECL (error);
847 MonoGenericContext context;
848 MonoMethod *method;
850 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
851 return jinfo_get_method (ji);
852 context = get_generic_context_from_stack_frame (ji, generic_info);
854 method = jinfo_get_method (ji);
855 method = mono_method_get_declaring_generic_method (method);
856 method = mono_class_inflate_generic_method_checked (method, &context, error);
857 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
859 return method;
863 * mono_exception_walk_native_trace:
864 * \param ex The exception object whose frames should be walked
865 * \param func callback to call for each stack frame
866 * \param user_data data passed to the callback
867 * This function walks the stacktrace of an exception. For
868 * each frame the callback function is called with the relevant info.
869 * The walk ends when no more stack frames are found or when the callback
870 * returns a TRUE value.
873 gboolean
874 mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
876 MONO_REQ_GC_UNSAFE_MODE;
878 MonoDomain *domain = mono_domain_get ();
879 MonoArray *ta = ex->trace_ips;
880 int len, i;
882 if (ta == NULL)
883 return FALSE;
885 len = mono_array_length (ta) / TRACE_IP_ENTRY_SIZE;
886 for (i = 0; i < len; i++) {
887 ExceptionTraceIp trace_ip;
889 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
890 gpointer ip = trace_ip.ip;
891 gpointer generic_info = trace_ip.generic_info;
892 MonoJitInfo *ji = mono_jit_info_table_find (domain, ip);
894 if (ji == NULL) {
895 if (func (NULL, ip, 0, FALSE, user_data))
896 return TRUE;
897 } else {
898 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
899 if (func (method, ji->code_start, (char *) ip - (char *) ji->code_start, TRUE, user_data))
900 return TRUE;
904 return len > 0;
907 MonoArray *
908 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
910 ERROR_DECL (error);
911 MonoDomain *domain = mono_domain_get ();
912 MonoArray *res;
913 MonoArray *ta = exc->trace_ips;
914 MonoDebugSourceLocation *location;
915 int i, len;
917 if (ta == NULL) {
918 /* Exception is not thrown yet */
919 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, error);
920 mono_error_set_pending_exception (error);
921 return res;
924 len = mono_array_length (ta) / TRACE_IP_ENTRY_SIZE;
926 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, error);
927 if (mono_error_set_pending_exception (error))
928 return NULL;
930 for (i = skip; i < len; i++) {
931 MonoJitInfo *ji;
932 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
933 if (!mono_error_ok (error)) {
934 mono_error_set_pending_exception (error);
935 return NULL;
937 ExceptionTraceIp trace_ip;
938 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
939 gpointer ip = trace_ip.ip;
940 gpointer generic_info = trace_ip.generic_info;
941 MonoMethod *method;
943 if (trace_ip.ji) {
944 ji = trace_ip.ji;
945 } else {
946 ji = mono_jit_info_table_find (domain, ip);
947 if (ji == NULL) {
948 /* Unmanaged frame */
949 mono_array_setref (res, i, sf);
950 continue;
954 g_assert (ji != NULL);
956 if (mono_llvm_only || !generic_info)
957 /* Can't resolve actual method */
958 method = jinfo_get_method (ji);
959 else
960 method = get_method_from_stack_frame (ji, generic_info);
961 if (jinfo_get_method (ji)->wrapper_type) {
962 char *s;
964 sf->method = NULL;
965 s = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION);
966 MonoString *name = mono_string_new_checked (domain, s, error);
967 g_free (s);
968 if (!is_ok (error)) {
969 mono_error_set_pending_exception (error);
970 return NULL;
972 MONO_OBJECT_SETREF (sf, internal_method_name, name);
974 else {
975 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
976 if (!mono_error_ok (error)) {
977 mono_error_set_pending_exception (error);
978 return NULL;
980 MONO_OBJECT_SETREF (sf, method, rm);
983 sf->method_index = ji->from_aot ? mono_aot_find_method_index (method) : 0xffffff;
984 sf->method_address = (gsize) ji->code_start;
985 sf->native_offset = (char *)ip - (char *)ji->code_start;
988 * mono_debug_lookup_source_location() returns both the file / line number information
989 * and the IL offset. Note that computing the IL offset is already an expensive
990 * operation, so we shouldn't call this method twice.
992 location = mono_debug_lookup_source_location (jinfo_get_method (ji), sf->native_offset, domain);
993 if (location) {
994 sf->il_offset = location->il_offset;
995 } else {
996 SeqPoint sp;
997 if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (ji), sf->native_offset, NULL, &sp))
998 sf->il_offset = sp.il_offset;
999 else
1000 sf->il_offset = -1;
1003 if (need_file_info) {
1004 if (location && location->source_file) {
1005 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1006 if (!is_ok (error)) {
1007 mono_error_set_pending_exception (error);
1008 return NULL;
1010 MONO_OBJECT_SETREF (sf, filename, filename);
1011 sf->line = location->row;
1012 sf->column = location->column;
1013 } else {
1014 sf->line = sf->column = 0;
1015 sf->filename = NULL;
1019 mono_debug_free_source_location (location);
1020 mono_array_setref (res, i, sf);
1023 return res;
1026 static void
1027 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1029 if (!start_ctx) {
1030 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1031 if (jit_tls && jit_tls->orig_ex_ctx_set)
1032 start_ctx = &jit_tls->orig_ex_ctx;
1034 mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
1037 * mono_walk_stack_with_ctx:
1038 * Unwind the current thread starting at \p start_ctx.
1039 * If \p start_ctx is null, we capture the current context.
1041 void
1042 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1044 MonoContext extra_ctx;
1045 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1046 MONO_ARCH_CONTEXT_DEF
1048 if (!thread || !thread->jit_data)
1049 return;
1051 if (!start_ctx) {
1052 mono_arch_flush_register_windows ();
1054 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1055 MONO_INIT_CONTEXT_FROM_CURRENT (&extra_ctx);
1056 #else
1057 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
1058 #endif
1059 start_ctx = &extra_ctx;
1062 mono_walk_stack_full (func, start_ctx, mono_domain_get (), (MonoJitTlsData *)thread->jit_data, mono_get_lmf (), unwind_options, user_data);
1066 * mono_walk_stack_with_state:
1067 * Unwind a thread described by \p state.
1069 * State must be valid (state->valid == TRUE).
1071 * If you are using this function to unwind another thread, make sure it is suspended.
1073 * If \p state is null, we capture the current context.
1075 void
1076 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
1078 MonoThreadUnwindState extra_state;
1079 if (!state) {
1080 g_assert (!mono_thread_info_is_async_context ());
1081 if (!mono_thread_state_init_from_current (&extra_state))
1082 return;
1083 state = &extra_state;
1086 g_assert (state->valid);
1088 if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
1089 /* Not attached */
1090 return;
1092 mono_walk_stack_full (func,
1093 &state->ctx,
1094 (MonoDomain *)state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
1095 (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
1096 (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF],
1097 unwind_options, user_data);
1100 void
1101 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
1103 MonoThreadUnwindState state;
1104 if (!mono_thread_state_init_from_current (&state))
1105 return;
1106 mono_walk_stack_with_state (func, &state, options, user_data);
1110 * mono_walk_stack_full:
1111 * \param func callback to call for each stack frame
1112 * \param domain starting appdomain, can be NULL to use the current domain
1113 * \param unwind_options what extra information the unwinder should gather
1114 * \param start_ctx starting state of the stack walk, can be NULL.
1115 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1116 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1117 * \param user_data data passed to the callback
1118 * This function walks the stack of a thread, starting from the state
1119 * represented by \p start_ctx. For each frame the callback
1120 * function is called with the relevant info. The walk ends when no more
1121 * managed stack frames are found or when the callback returns a TRUE value.
1123 static void
1124 mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data)
1126 gint il_offset, i;
1127 MonoContext ctx, new_ctx;
1128 StackFrameInfo frame;
1129 gboolean res;
1130 mgreg_t *reg_locations [MONO_MAX_IREGS];
1131 mgreg_t *new_reg_locations [MONO_MAX_IREGS];
1132 gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
1133 gboolean async = mono_thread_info_is_async_context ();
1134 Unwinder unwinder;
1136 #ifndef TARGET_WASM
1137 if (mono_llvm_only) {
1138 GSList *l, *ips;
1140 if (async)
1141 return;
1143 ips = get_unwind_backtrace ();
1144 for (l = ips; l; l = l->next) {
1145 guint8 *ip = (guint8*)l->data;
1146 memset (&frame, 0, sizeof (StackFrameInfo));
1147 frame.ji = mini_jit_info_table_find (domain, ip, &frame.domain);
1148 if (!frame.ji || frame.ji->is_trampoline)
1149 continue;
1150 frame.type = FRAME_TYPE_MANAGED;
1151 frame.method = jinfo_get_method (frame.ji);
1152 // FIXME: Cannot lookup the actual method
1153 frame.actual_method = frame.method;
1154 if (frame.type == FRAME_TYPE_MANAGED) {
1155 if (!frame.method->wrapper_type || frame.method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
1156 frame.managed = TRUE;
1158 frame.native_offset = ip - (guint8*)frame.ji->code_start;
1159 frame.il_offset = -1;
1161 if (func (&frame, NULL, user_data))
1162 break;
1164 g_free (ips);
1165 return;
1167 #endif
1169 g_assert (start_ctx);
1170 g_assert (domain);
1171 g_assert (jit_tls);
1172 /*The LMF will be null if the target have no managed frames.*/
1173 /* g_assert (lmf); */
1175 if (async)
1176 g_assert (unwind_options == MONO_UNWIND_NONE);
1178 memcpy (&ctx, start_ctx, sizeof (MonoContext));
1179 memset (reg_locations, 0, sizeof (reg_locations));
1181 unwinder_init (&unwinder);
1183 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
1184 frame.lmf = lmf;
1185 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
1186 if (!res)
1187 return;
1189 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji && !frame.ji->is_trampoline) {
1190 MonoDebugSourceLocation *source;
1192 source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
1193 if (source) {
1194 il_offset = source->il_offset;
1195 } else {
1196 SeqPoint sp;
1197 if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (frame.ji), frame.native_offset, NULL, &sp))
1198 il_offset = sp.il_offset;
1199 else
1200 il_offset = -1;
1202 mono_debug_free_source_location (source);
1203 } else
1204 il_offset = -1;
1206 frame.il_offset = il_offset;
1208 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji && !frame.ji->is_trampoline) {
1209 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
1210 } else {
1211 frame.actual_method = frame.method;
1214 if (get_reg_locations)
1215 frame.reg_locations = reg_locations;
1217 if (func (&frame, &ctx, user_data))
1218 return;
1220 if (get_reg_locations) {
1221 for (i = 0; i < MONO_MAX_IREGS; ++i)
1222 if (new_reg_locations [i])
1223 reg_locations [i] = new_reg_locations [i];
1226 ctx = new_ctx;
1230 MonoBoolean
1231 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
1232 MonoReflectionMethod **method,
1233 gint32 *iloffset, gint32 *native_offset,
1234 MonoString **file, gint32 *line, gint32 *column)
1236 ERROR_DECL (error);
1237 MonoDomain *domain = mono_domain_get ();
1238 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1239 MonoLMF *lmf = mono_get_lmf ();
1240 MonoJitInfo *ji = NULL;
1241 MonoContext ctx, new_ctx;
1242 MonoDebugSourceLocation *location;
1243 MonoMethod *jmethod = NULL, *actual_method;
1244 StackFrameInfo frame;
1245 gboolean res;
1246 Unwinder unwinder;
1247 int il_offset = -1;
1249 MONO_ARCH_CONTEXT_DEF;
1251 if (mono_llvm_only) {
1252 GSList *l, *ips;
1253 MonoDomain *frame_domain;
1254 guint8 *frame_ip = NULL;
1256 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1257 jmethod = NULL;
1258 ips = get_unwind_backtrace ();
1259 for (l = ips; l && skip >= 0; l = l->next) {
1260 guint8 *ip = (guint8*)l->data;
1262 frame_ip = ip;
1264 ji = mini_jit_info_table_find (mono_domain_get (), ip, &frame_domain);
1265 if (!ji || ji->is_trampoline)
1266 continue;
1268 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1269 jmethod = jinfo_get_method (ji);
1270 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1271 continue;
1272 skip--;
1274 g_slist_free (ips);
1275 if (!jmethod || !l)
1276 return FALSE;
1277 /* No way to resolve generic instances */
1278 actual_method = jmethod;
1279 *native_offset = frame_ip - (guint8*)ji->code_start;
1280 } else {
1281 mono_arch_flush_register_windows ();
1283 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1284 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
1285 #else
1286 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
1287 #endif
1289 unwinder_init (&unwinder);
1291 new_ctx = ctx;
1292 do {
1293 ctx = new_ctx;
1294 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1295 if (!res)
1296 return FALSE;
1297 switch (frame.type) {
1298 case FRAME_TYPE_MANAGED_TO_NATIVE:
1299 case FRAME_TYPE_DEBUGGER_INVOKE:
1300 case FRAME_TYPE_TRAMPOLINE:
1301 continue;
1302 case FRAME_TYPE_INTERP_TO_MANAGED:
1303 if (!ji) {
1304 /* gsharedvt_out_sig_wrapper from interp2jit transition */
1305 skip--;
1306 break;
1308 continue;
1309 case FRAME_TYPE_INTERP:
1310 case FRAME_TYPE_MANAGED:
1311 ji = frame.ji;
1312 *native_offset = frame.native_offset;
1314 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1315 jmethod = jinfo_get_method (ji);
1316 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1317 continue;
1318 skip--;
1319 break;
1320 default:
1321 g_assert_not_reached ();
1323 } while (skip >= 0);
1325 if (frame.type == FRAME_TYPE_INTERP) {
1326 jmethod = frame.method;
1327 actual_method = frame.actual_method;
1328 } else {
1329 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
1333 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, error);
1334 if (!mono_error_ok (error)) {
1335 mono_error_set_pending_exception (error);
1336 return FALSE;
1338 mono_gc_wbarrier_generic_store (method, (MonoObject*) rm);
1340 if (il_offset != -1) {
1341 location = mono_debug_lookup_source_location_by_il (jmethod, il_offset, domain);
1342 } else {
1343 location = mono_debug_lookup_source_location (jmethod, *native_offset, domain);
1345 if (location)
1346 *iloffset = location->il_offset;
1347 else
1348 *iloffset = 0;
1350 if (need_file_info) {
1351 if (location) {
1352 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
1353 if (!is_ok (error)) {
1354 mono_error_set_pending_exception (error);
1355 return FALSE;
1357 mono_gc_wbarrier_generic_store (file, (MonoObject*)filename);
1358 *line = location->row;
1359 *column = location->column;
1360 } else {
1361 *file = NULL;
1362 *line = *column = 0;
1366 mono_debug_free_source_location (location);
1368 return TRUE;
1371 static MonoClass*
1372 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1374 ERROR_DECL (error);
1375 MonoClass *catch_class = ei->data.catch_class;
1376 MonoType *inflated_type;
1377 MonoGenericContext context;
1379 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1380 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
1381 return NULL;
1383 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1384 return catch_class;
1385 context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1387 /* FIXME: we shouldn't inflate but instead put the
1388 type in the rgctx and fetch it from there. It
1389 might be a good idea to do this lazily, i.e. only
1390 when the exception is actually thrown, so as not to
1391 waste space for exception clauses which might never
1392 be encountered. */
1393 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
1394 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1396 catch_class = mono_class_from_mono_type (inflated_type);
1397 mono_metadata_free_type (inflated_type);
1399 return catch_class;
1403 * mini_jit_info_table_find_ext:
1405 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1406 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1407 * OUT_DOMAIN if it is not NULL.
1409 MonoJitInfo*
1410 mini_jit_info_table_find_ext (MonoDomain *domain, gpointer addr, gboolean allow_trampolines, MonoDomain **out_domain)
1412 MonoJitInfo *ji;
1413 MonoInternalThread *t = mono_thread_internal_current ();
1414 gpointer *refs;
1416 if (out_domain)
1417 *out_domain = NULL;
1419 ji = mono_jit_info_table_find_internal (domain, addr, TRUE, allow_trampolines);
1420 if (ji) {
1421 if (out_domain)
1422 *out_domain = domain;
1423 return ji;
1426 /* maybe it is shared code, so we also search in the root domain */
1427 if (domain != mono_get_root_domain ()) {
1428 ji = mono_jit_info_table_find_internal (mono_get_root_domain (), addr, TRUE, allow_trampolines);
1429 if (ji) {
1430 if (out_domain)
1431 *out_domain = mono_get_root_domain ();
1432 return ji;
1436 if (!t)
1437 return NULL;
1439 refs = (gpointer *)((t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL);
1440 for (; refs && *refs; refs++) {
1441 if (*refs != domain && *refs != mono_get_root_domain ()) {
1442 ji = mono_jit_info_table_find_internal ((MonoDomain*) *refs, addr, TRUE, allow_trampolines);
1443 if (ji) {
1444 if (out_domain)
1445 *out_domain = (MonoDomain*) *refs;
1446 return ji;
1451 return NULL;
1454 MonoJitInfo*
1455 mini_jit_info_table_find (MonoDomain *domain, gpointer addr, MonoDomain **out_domain)
1457 return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain);
1460 /* Class lazy loading functions */
1461 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
1464 * wrap_non_exception_throws:
1466 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
1467 * WrapNonExceptionThrows flag set.
1469 static gboolean
1470 wrap_non_exception_throws (MonoMethod *m)
1472 ERROR_DECL (error);
1473 MonoAssembly *ass = m_class_get_image (m->klass)->assembly;
1474 MonoCustomAttrInfo* attrs;
1475 MonoClass *klass;
1476 int i;
1477 gboolean val = FALSE;
1479 if (m->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
1480 MonoDynamicMethod *dm = (MonoDynamicMethod *)m;
1481 if (dm->assembly)
1482 ass = dm->assembly;
1484 g_assert (ass);
1485 if (ass->wrap_non_exception_throws_inited)
1486 return ass->wrap_non_exception_throws;
1488 klass = mono_class_get_runtime_compat_attr_class ();
1490 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, error);
1491 mono_error_cleanup (error); /* FIXME don't swallow the error */
1492 if (attrs) {
1493 for (i = 0; i < attrs->num_attrs; ++i) {
1494 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1495 const gchar *p;
1496 int num_named, named_type, name_len;
1497 char *name;
1499 if (!attr->ctor || attr->ctor->klass != klass)
1500 continue;
1501 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
1502 p = (const char*)attr->data;
1503 g_assert (read16 (p) == 0x0001);
1504 p += 2;
1505 num_named = read16 (p);
1506 if (num_named != 1)
1507 continue;
1508 p += 2;
1509 named_type = *p;
1510 p ++;
1511 /* data_type = *p; */
1512 p ++;
1513 /* Property */
1514 if (named_type != 0x54)
1515 continue;
1516 name_len = mono_metadata_decode_blob_size (p, &p);
1517 name = (char *)g_malloc (name_len + 1);
1518 memcpy (name, p, name_len);
1519 name [name_len] = 0;
1520 p += name_len;
1521 g_assert (!strcmp (name, "WrapNonExceptionThrows"));
1522 g_free (name);
1523 /* The value is a BOOLEAN */
1524 val = *p;
1526 mono_custom_attrs_free (attrs);
1529 ass->wrap_non_exception_throws = val;
1530 mono_memory_barrier ();
1531 ass->wrap_non_exception_throws_inited = TRUE;
1533 return val;
1536 #define MAX_UNMANAGED_BACKTRACE 128
1537 static MonoArray*
1538 build_native_trace (MonoError *error)
1540 error_init (error);
1541 /* This puppy only makes sense on mobile, IOW, ARM. */
1542 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
1543 MonoArray *res;
1544 void *native_trace [MAX_UNMANAGED_BACKTRACE];
1545 int size = -1;
1546 MONO_ENTER_GC_SAFE;
1547 size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE);
1548 MONO_EXIT_GC_SAFE;
1549 int i;
1551 if (!size)
1552 return NULL;
1553 res = mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, size, error);
1554 return_val_if_nok (error, NULL);
1556 for (i = 0; i < size; i++)
1557 mono_array_set (res, gpointer, i, native_trace [i]);
1558 return res;
1559 #else
1560 return NULL;
1561 #endif
1564 static void
1565 setup_stack_trace (MonoException *mono_ex, GSList *dynamic_methods, GList **trace_ips)
1567 if (mono_ex) {
1568 *trace_ips = g_list_reverse (*trace_ips);
1569 ERROR_DECL (error);
1570 MonoArray *ips_arr = mono_glist_to_array (*trace_ips, mono_defaults.int_class, error);
1571 mono_error_assert_ok (error);
1572 MONO_OBJECT_SETREF (mono_ex, trace_ips, ips_arr);
1573 MONO_OBJECT_SETREF (mono_ex, native_trace_ips, build_native_trace (error));
1574 mono_error_assert_ok (error);
1575 if (dynamic_methods) {
1576 /* These methods could go away anytime, so save a reference to them in the exception object */
1577 GSList *l;
1578 MonoMList *list = NULL;
1580 for (l = dynamic_methods; l; l = l->next) {
1581 guint32 dis_link;
1582 MonoDomain *domain = mono_domain_get ();
1584 if (domain->method_to_dyn_method) {
1585 mono_domain_lock (domain);
1586 dis_link = (guint32)(size_t)g_hash_table_lookup (domain->method_to_dyn_method, l->data);
1587 mono_domain_unlock (domain);
1588 if (dis_link) {
1589 MonoObject *o = mono_gchandle_get_target (dis_link);
1590 if (o) {
1591 list = mono_mlist_prepend_checked (list, o, error);
1592 mono_error_assert_ok (error);
1598 MONO_OBJECT_SETREF (mono_ex, dynamic_methods, list);
1601 g_list_free (*trace_ips);
1602 *trace_ips = NULL;
1606 * handle_exception_first_pass:
1608 * The first pass of exception handling. Unwind the stack until a catch clause which can catch
1609 * OBJ is found. Store the index of the filter clause which caught the exception into
1610 * OUT_FILTER_IDX. Return TRUE if the exception is caught, FALSE otherwise.
1612 static gboolean
1613 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)
1615 ERROR_DECL (error);
1616 MonoDomain *domain = mono_domain_get ();
1617 MonoJitInfo *ji = NULL;
1618 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1619 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1620 MonoLMF *lmf = mono_get_lmf ();
1621 GList *trace_ips = NULL;
1622 GSList *dynamic_methods = NULL;
1623 MonoException *mono_ex;
1624 gboolean stack_overflow = FALSE;
1625 MonoContext initial_ctx;
1626 MonoMethod *method;
1627 int frame_count = 0;
1628 gint32 filter_idx;
1629 int i;
1630 MonoObject *ex_obj;
1631 Unwinder unwinder;
1632 gboolean in_interp;
1634 g_assert (ctx != NULL);
1636 if (obj == (MonoObject *)domain->stack_overflow_ex)
1637 stack_overflow = TRUE;
1639 mono_ex = (MonoException*)obj;
1640 MonoArray *initial_trace_ips = mono_ex->trace_ips;
1641 if (initial_trace_ips) {
1642 int len = mono_array_length (initial_trace_ips) / TRACE_IP_ENTRY_SIZE;
1644 for (i = 0; i < (len - 1); i++) {
1645 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
1646 gpointer p = mono_array_get (initial_trace_ips, gpointer, (i * TRACE_IP_ENTRY_SIZE) + j);
1647 trace_ips = g_list_prepend (trace_ips, p);
1652 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
1653 mono_error_assert_ok (error);
1654 mono_ex = NULL;
1657 if (!call_filter)
1658 call_filter = (int (*) (MonoContext *, void *))mono_get_call_filter ();
1660 g_assert (jit_tls->end_of_stack);
1661 g_assert (jit_tls->abort_func);
1663 if (out_filter_idx)
1664 *out_filter_idx = -1;
1665 if (out_ji)
1666 *out_ji = NULL;
1667 if (out_prev_ji)
1668 *out_prev_ji = NULL;
1669 filter_idx = 0;
1670 initial_ctx = *ctx;
1672 unwinder_init (&unwinder);
1674 while (1) {
1675 MonoContext new_ctx;
1676 guint32 free_stack;
1677 int clause_index_start = 0;
1678 gboolean unwind_res = TRUE;
1680 StackFrameInfo frame;
1682 if (out_prev_ji)
1683 *out_prev_ji = ji;
1685 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1686 if (!unwind_res) {
1687 setup_stack_trace (mono_ex, dynamic_methods, &trace_ips);
1688 g_slist_free (dynamic_methods);
1689 return FALSE;
1692 switch (frame.type) {
1693 case FRAME_TYPE_DEBUGGER_INVOKE:
1694 case FRAME_TYPE_MANAGED_TO_NATIVE:
1695 case FRAME_TYPE_TRAMPOLINE:
1696 case FRAME_TYPE_INTERP_TO_MANAGED:
1697 *ctx = new_ctx;
1698 continue;
1699 case FRAME_TYPE_INTERP:
1700 case FRAME_TYPE_MANAGED:
1701 break;
1702 default:
1703 g_assert_not_reached ();
1704 break;
1707 in_interp = frame.type == FRAME_TYPE_INTERP;
1708 ji = frame.ji;
1710 gpointer ip;
1711 if (in_interp)
1712 ip = (guint8*)ji->code_start + frame.native_offset;
1713 else
1714 ip = MONO_CONTEXT_GET_IP (ctx);
1716 frame_count ++;
1717 method = jinfo_get_method (ji);
1718 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
1720 if (mini_get_debug_options ()->reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
1721 g_error ("A native frame was found while unwinding the stack after an exception.\n"
1722 "The native frame called the managed method:\n%s\n",
1723 mono_method_full_name (method, TRUE));
1726 if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1727 // avoid giant stack traces during a stack overflow
1728 if (frame_count < 1000) {
1729 trace_ips = g_list_prepend (trace_ips, ip);
1730 trace_ips = g_list_prepend (trace_ips, get_generic_info_from_stack_frame (ji, ctx));
1731 trace_ips = g_list_prepend (trace_ips, ji);
1735 if (method->dynamic)
1736 dynamic_methods = g_slist_prepend (dynamic_methods, method);
1738 if (stack_overflow) {
1739 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1740 } else {
1741 free_stack = 0xffffff;
1744 for (i = clause_index_start; i < ji->num_clauses; i++) {
1745 MonoJitExceptionInfo *ei = &ji->clauses [i];
1746 gboolean filtered = FALSE;
1749 * During stack overflow, wait till the unwinding frees some stack
1750 * space before running handlers/finalizers.
1752 if (free_stack <= (64 * 1024))
1753 continue;
1755 if (is_address_protected (ji, ei, ip)) {
1756 /* catch block */
1757 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1760 * Have to unwrap RuntimeWrappedExceptions if the
1761 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1763 if (non_exception && !wrap_non_exception_throws (method))
1764 ex_obj = non_exception;
1765 else
1766 ex_obj = obj;
1768 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1769 #ifndef DISABLE_PERFCOUNTERS
1770 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_filters);
1771 #endif
1773 if (!ji->is_interp) {
1774 #ifndef MONO_CROSS_COMPILE
1775 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1776 if (ji->from_llvm)
1777 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1778 else
1779 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
1780 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1781 #else
1782 g_assert (!ji->from_llvm);
1783 /* store the exception object in bp + ei->exvar_offset */
1784 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1785 #endif
1786 #endif
1788 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
1790 * Pass the original il clause index to the landing pad so it can
1791 * branch to the landing pad associated with the il clause.
1792 * This is needed because llvm compiled code assumes that the EH
1793 * code always branches to the innermost landing pad.
1795 if (ji->from_llvm)
1796 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
1797 #endif
1800 mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx);
1801 if (ji->is_interp) {
1802 filtered = mini_get_interp_callbacks ()->run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter);
1803 } else {
1804 filtered = call_filter (ctx, ei->data.filter);
1806 mono_debugger_agent_end_exception_filter (mono_ex, ctx, &initial_ctx);
1807 if (filtered && out_filter_idx)
1808 *out_filter_idx = filter_idx;
1809 if (out_ji)
1810 *out_ji = ji;
1811 filter_idx ++;
1813 if (filtered) {
1814 setup_stack_trace (mono_ex, dynamic_methods, &trace_ips);
1815 g_slist_free (dynamic_methods);
1816 /* mono_debugger_agent_handle_exception () needs this */
1817 mini_set_abort_threshold (&frame);
1818 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1819 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
1820 *catch_frame = frame;
1821 return TRUE;
1825 ERROR_DECL_VALUE (isinst_error);
1826 error_init (&isinst_error);
1827 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, error)) {
1828 setup_stack_trace (mono_ex, dynamic_methods, &trace_ips);
1829 g_slist_free (dynamic_methods);
1831 if (out_ji)
1832 *out_ji = ji;
1834 /* mono_debugger_agent_handle_exception () needs this */
1835 if (!in_interp)
1836 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1837 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
1838 *catch_frame = frame;
1839 return TRUE;
1841 mono_error_cleanup (&isinst_error);
1845 *ctx = new_ctx;
1848 g_assert_not_reached ();
1852 * mono_handle_exception_internal:
1853 * \param ctx saved processor state
1854 * \param obj the exception object
1855 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
1857 static gboolean
1858 mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji)
1860 ERROR_DECL (error);
1861 MonoDomain *domain = mono_domain_get ();
1862 MonoJitInfo *ji, *prev_ji;
1863 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1864 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1865 MonoLMF *lmf = mono_get_lmf ();
1866 MonoException *mono_ex;
1867 gboolean stack_overflow = FALSE;
1868 MonoContext initial_ctx;
1869 MonoMethod *method;
1870 int frame_count = 0;
1871 gint32 filter_idx, first_filter_idx = 0;
1872 int i;
1873 MonoObject *ex_obj;
1874 MonoObject *non_exception = NULL;
1875 Unwinder unwinder;
1876 gboolean in_interp;
1878 g_assert (ctx != NULL);
1879 if (!obj) {
1880 MonoException *ex = mono_get_exception_null_reference ();
1881 MonoString *msg = mono_string_new_checked (domain, "Object reference not set to an instance of an object", error);
1882 mono_error_assert_ok (error);
1883 MONO_OBJECT_SETREF (ex, message, msg);
1884 obj = (MonoObject *)ex;
1888 * Allocate a new exception object instead of the preconstructed ones.
1890 if (obj == (MonoObject *)domain->stack_overflow_ex) {
1892 * It is not a good idea to try and put even more pressure on the little stack available.
1893 * obj = mono_get_exception_stack_overflow ();
1895 stack_overflow = TRUE;
1897 else if (obj == (MonoObject *)domain->null_reference_ex) {
1898 obj = (MonoObject *)mono_get_exception_null_reference ();
1901 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
1902 mono_error_assert_ok (error);
1903 non_exception = obj;
1904 obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, error);
1905 mono_error_assert_ok (error);
1908 mono_ex = (MonoException*)obj;
1910 if (mini_get_debug_options ()->suspend_on_exception) {
1911 mono_runtime_printf_err ("Exception thrown, suspending...");
1912 while (1)
1916 if (mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) {
1917 mono_ex = (MonoException*)obj;
1918 } else {
1919 mono_error_assert_ok (error);
1920 mono_ex = NULL;
1923 if (mono_ex && jit_tls->class_cast_from) {
1924 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "InvalidCastException")) {
1925 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1926 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1927 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
1928 mono_ex->message = mono_string_new_checked (domain, msg, error);
1929 g_free (from_name);
1930 g_free (to_name);
1931 if (!is_ok (error)) {
1932 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg);
1933 mono_error_assert_ok (error);
1935 g_free (msg);
1937 if (!strcmp (m_class_get_name (mono_ex->object.vtable->klass), "ArrayTypeMismatchException")) {
1938 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1939 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1940 char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
1941 mono_ex->message = mono_string_new_checked (domain, msg, error);
1942 g_free (from_name);
1943 g_free (to_name);
1944 if (!is_ok (error)) {
1945 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg);
1946 mono_error_assert_ok (error);
1948 g_free (msg);
1952 if (!call_filter)
1953 call_filter = (int (*)(MonoContext *, void*))mono_get_call_filter ();
1955 g_assert (jit_tls->end_of_stack);
1956 g_assert (jit_tls->abort_func);
1959 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
1960 * end up being TRUE on any code path.
1962 memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
1964 if (!resume) {
1965 gboolean res;
1967 MonoContext ctx_cp = *ctx;
1968 if (mono_trace_is_enabled ()) {
1969 MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0);
1970 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message);
1971 MonoObject *message;
1972 const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
1973 char *msg = NULL;
1974 if (get_message == NULL) {
1975 message = NULL;
1976 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
1977 message = NULL;
1978 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
1979 } else {
1980 MonoObject *exc = NULL;
1981 message = mono_runtime_try_invoke (get_message, obj, NULL, &exc, error);
1982 g_assert (exc == NULL);
1983 mono_error_assert_ok (error);
1985 if (msg == NULL) {
1986 if (message) {
1987 msg = mono_string_to_utf8_checked ((MonoString *) message, error);
1988 if (!is_ok (error)) {
1989 mono_error_cleanup (error);
1990 msg = g_strdup ("(error while display System.Exception.Message property)");
1992 } else {
1993 msg = g_strdup ("(System.Exception.Message property not available)");
1996 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);
1997 g_free (msg);
1998 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
1999 mono_print_thread_dump_from_ctx (ctx);
2001 jit_tls->orig_ex_ctx_set = TRUE;
2002 MONO_PROFILER_RAISE (exception_throw, (obj));
2003 jit_tls->orig_ex_ctx_set = FALSE;
2005 StackFrameInfo catch_frame;
2006 res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame);
2008 if (!res) {
2009 if (mini_get_debug_options ()->break_on_exc)
2010 G_BREAKPOINT ();
2011 mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2013 if (mini_get_debug_options ()->suspend_on_unhandled) {
2014 mono_runtime_printf_err ("Unhandled exception, suspending...");
2015 while (1)
2019 // FIXME: This runs managed code so it might cause another stack overflow when
2020 // we are handling a stack overflow
2021 mini_set_abort_threshold (&catch_frame);
2022 mono_unhandled_exception (obj);
2023 } else {
2024 gboolean unhandled = FALSE;
2027 * The exceptions caught by the mono_runtime_invoke_checked () calls
2028 * in the threadpool needs to be treated as unhandled (#669836).
2030 * FIXME: The check below is hackish, but its hard to distinguish
2031 * these runtime invoke calls from others in the runtime.
2033 if (ji && jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2034 if (prev_ji && jinfo_get_method (prev_ji) == mono_defaults.threadpool_perform_wait_callback_method)
2035 unhandled = TRUE;
2038 if (unhandled)
2039 mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2040 else
2041 mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2045 if (out_ji)
2046 *out_ji = NULL;
2047 filter_idx = 0;
2048 initial_ctx = *ctx;
2050 unwinder_init (&unwinder);
2052 while (1) {
2053 MonoContext new_ctx;
2054 guint32 free_stack;
2055 int clause_index_start = 0;
2056 gboolean unwind_res = TRUE;
2057 StackFrameInfo frame;
2058 gpointer ip;
2060 if (resume) {
2061 resume = FALSE;
2062 ji = jit_tls->resume_state.ji;
2063 new_ctx = jit_tls->resume_state.new_ctx;
2064 clause_index_start = jit_tls->resume_state.clause_index;
2065 lmf = jit_tls->resume_state.lmf;
2066 first_filter_idx = jit_tls->resume_state.first_filter_idx;
2067 filter_idx = jit_tls->resume_state.filter_idx;
2068 in_interp = FALSE;
2069 } else {
2070 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2071 if (!unwind_res) {
2072 *(mono_get_lmf_addr ()) = lmf;
2074 jit_tls->abort_func (obj);
2075 g_assert_not_reached ();
2077 switch (frame.type) {
2078 case FRAME_TYPE_DEBUGGER_INVOKE:
2079 case FRAME_TYPE_MANAGED_TO_NATIVE:
2080 case FRAME_TYPE_TRAMPOLINE:
2081 *ctx = new_ctx;
2082 continue;
2083 case FRAME_TYPE_INTERP_TO_MANAGED:
2084 continue;
2085 case FRAME_TYPE_INTERP:
2086 case FRAME_TYPE_MANAGED:
2087 break;
2088 default:
2089 g_assert_not_reached ();
2090 break;
2092 in_interp = frame.type == FRAME_TYPE_INTERP;
2093 ji = frame.ji;
2096 if (in_interp)
2097 ip = (guint8*)ji->code_start + frame.native_offset;
2098 else
2099 ip = MONO_CONTEXT_GET_IP (ctx);
2101 method = jinfo_get_method (ji);
2102 frame_count ++;
2103 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2105 if (stack_overflow) {
2106 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2107 } else {
2108 free_stack = 0xffffff;
2111 for (i = clause_index_start; i < ji->num_clauses; i++) {
2112 MonoJitExceptionInfo *ei = &ji->clauses [i];
2113 gboolean filtered = FALSE;
2116 * During stack overflow, wait till the unwinding frees some stack
2117 * space before running handlers/finalizers.
2119 if (free_stack <= (64 * 1024))
2120 continue;
2122 if (is_address_protected (ji, ei, ip)) {
2123 /* catch block */
2124 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2127 * Have to unwrap RuntimeWrappedExceptions if the
2128 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2130 if (non_exception && !wrap_non_exception_throws (method))
2131 ex_obj = non_exception;
2132 else
2133 ex_obj = obj;
2135 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
2136 #ifndef MONO_CROSS_COMPILE
2137 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2138 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2139 #else
2140 g_assert (!ji->from_llvm);
2141 /* store the exception object in bp + ei->exvar_offset */
2142 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2143 #endif
2144 #endif
2147 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2148 if (ji->from_llvm)
2149 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2150 #endif
2152 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2154 * Filter clauses should only be run in the
2155 * first pass of exception handling.
2157 filtered = (filter_idx == first_filter_idx);
2158 filter_idx ++;
2161 error_init (error);
2162 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
2163 mono_object_isinst_checked (ex_obj, catch_class, error)) || filtered) {
2165 * This guards against the situation that we abort a thread that is executing a finally clause
2166 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2167 * check for this situation here and resume interruption if we are below the guarded block.
2169 if (G_UNLIKELY (jit_tls->handler_block)) {
2170 gboolean is_outside = FALSE;
2171 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
2172 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
2173 //FIXME make this stack direction aware
2175 if (catch_bp > prot_bp) {
2176 is_outside = TRUE;
2177 } else if (catch_bp == prot_bp) {
2178 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2179 * So we check if the catch handler_start is protected by the guarded handler protected region
2181 * Assumptions:
2182 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2183 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2184 * There aren't any further finally/fault handler blocks down the stack over this exception.
2185 * This must be ensured by the code that installs the guard trampoline.
2187 g_assert (ji == mini_jit_info_table_find (domain, (char *)MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
2189 if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
2190 is_outside = TRUE;
2193 if (is_outside) {
2194 jit_tls->handler_block = NULL;
2195 mono_thread_resume_interruption (TRUE); /*We ignore the exception here, it will be raised later*/
2199 if (mono_trace_is_enabled () && mono_trace_eval (method))
2200 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2201 jit_tls->orig_ex_ctx_set = TRUE;
2202 MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj));
2203 jit_tls->orig_ex_ctx_set = FALSE;
2204 mini_set_abort_threshold (&frame);
2206 if (in_interp) {
2208 * ctx->pc points into the interpreter, after the call which transitioned to
2209 * JITted code. Store the unwind state into the
2210 * interpeter state, then resume, the interpreter will unwind itself until
2211 * it reaches the target frame and will continue execution from there.
2212 * The resuming is kinda hackish, from the native code standpoint, it looks
2213 * like the call which transitioned to JITted code has succeeded, but the
2214 * return value register etc. is not set, so we have to be careful.
2216 mini_get_interp_callbacks ()->set_resume_state (jit_tls, mono_ex, ei, frame.interp_frame, ei->handler_start);
2217 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2218 /* ip == 0 means an interpreter frame */
2219 if (MONO_CONTEXT_GET_IP (ctx) != 0)
2220 mono_arch_undo_ip_adjustment (ctx);
2221 } else {
2222 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2224 mono_set_lmf (lmf);
2225 #ifndef DISABLE_PERFCOUNTERS
2226 mono_atomic_fetch_add_i32 (&mono_perfcounters->exceptions_depth, frame_count);
2227 #endif
2228 if (obj == (MonoObject *)domain->stack_overflow_ex)
2229 jit_tls->handling_stack_ovf = FALSE;
2231 return 0;
2233 mono_error_cleanup (error);
2234 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
2235 if (mono_trace_is_enabled () && mono_trace_eval (method))
2236 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2237 jit_tls->orig_ex_ctx_set = TRUE;
2238 MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj));
2239 jit_tls->orig_ex_ctx_set = FALSE;
2241 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2242 if (mono_trace_is_enabled () && mono_trace_eval (method))
2243 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2244 jit_tls->orig_ex_ctx_set = TRUE;
2245 MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj));
2246 jit_tls->orig_ex_ctx_set = FALSE;
2247 #ifndef DISABLE_PERFCOUNTERS
2248 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_finallys);
2249 #endif
2251 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2252 mono_set_lmf (lmf);
2253 if (ji->from_llvm) {
2255 * LLVM compiled finally handlers follow the design
2256 * of the c++ ehabi, i.e. they call a resume function
2257 * at the end instead of returning to the caller.
2258 * So save the exception handling state,
2259 * mono_resume_unwind () will call us again to continue
2260 * the unwinding.
2262 jit_tls->resume_state.ex_obj = obj;
2263 jit_tls->resume_state.ji = ji;
2264 jit_tls->resume_state.clause_index = i + 1;
2265 jit_tls->resume_state.ctx = *ctx;
2266 jit_tls->resume_state.new_ctx = new_ctx;
2267 jit_tls->resume_state.lmf = lmf;
2268 jit_tls->resume_state.first_filter_idx = first_filter_idx;
2269 jit_tls->resume_state.filter_idx = filter_idx;
2270 mini_set_abort_threshold (&frame);
2271 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2272 return 0;
2273 } else {
2274 mini_set_abort_threshold (&frame);
2275 if (in_interp) {
2276 gboolean has_ex = mini_get_interp_callbacks ()->run_finally (&frame, i, ei->handler_start);
2277 if (has_ex)
2278 return 0;
2279 } else {
2280 call_filter (ctx, ei->handler_start);
2287 if (MONO_PROFILER_ENABLED (method_exception_leave) &&
2288 mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) {
2289 jit_tls->orig_ex_ctx_set = TRUE;
2290 MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
2291 jit_tls->orig_ex_ctx_set = FALSE;
2294 *ctx = new_ctx;
2297 g_assert_not_reached ();
2301 * mono_debugger_run_finally:
2302 * \param start_ctx saved processor state
2303 * This method is called by the Mono Debugger to call all \c finally clauses of the
2304 * current stack frame. It's used when the user issues a \c return command to make
2305 * the current stack frame return. After returning from this method, the debugger
2306 * unwinds the stack one frame and gives control back to the user.
2307 * NOTE: This method is only used when running inside the Mono Debugger.
2309 void
2310 mono_debugger_run_finally (MonoContext *start_ctx)
2312 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2313 MonoDomain *domain = mono_domain_get ();
2314 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2315 MonoLMF *lmf = mono_get_lmf ();
2316 MonoContext ctx, new_ctx;
2317 MonoJitInfo *ji, rji;
2318 int i;
2320 ctx = *start_ctx;
2322 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
2323 if (!ji || ji == (gpointer)-1)
2324 return;
2326 if (!call_filter)
2327 call_filter = (int (*)(MonoContext *, void *))mono_get_call_filter ();
2329 for (i = 0; i < ji->num_clauses; i++) {
2330 MonoJitExceptionInfo *ei = &ji->clauses [i];
2332 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
2333 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
2334 call_filter (&ctx, ei->handler_start);
2340 * mono_handle_exception:
2341 * \param ctx saved processor state
2342 * \param obj the exception object
2344 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
2345 * return TRUE.
2347 gboolean
2348 mono_handle_exception (MonoContext *ctx, MonoObject *obj)
2350 MONO_REQ_GC_UNSAFE_MODE;
2352 #ifndef DISABLE_PERFCOUNTERS
2353 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_thrown);
2354 #endif
2356 return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
2359 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2361 #ifndef MONO_ARCH_USE_SIGACTION
2362 #error "Can't use sigaltstack without sigaction"
2363 #endif
2365 void
2366 mono_setup_altstack (MonoJitTlsData *tls)
2368 size_t stsize = 0;
2369 stack_t sa;
2370 guint8 *staddr = NULL;
2372 if (mono_running_on_valgrind ())
2373 return;
2375 mono_thread_info_get_stack_bounds (&staddr, &stsize);
2377 g_assert (staddr);
2379 tls->end_of_stack = staddr + stsize;
2380 tls->stack_size = stsize;
2382 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
2384 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
2385 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
2387 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
2389 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
2390 /* mprotect can fail for the main thread stack */
2391 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);
2392 g_assert (gaddr == tls->stack_ovf_guard_base);
2393 tls->stack_ovf_valloced = TRUE;
2396 /* Setup an alternate signal stack */
2397 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);
2398 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
2400 g_assert (tls->signal_stack);
2402 sa.ss_sp = tls->signal_stack;
2403 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
2404 sa.ss_flags = 0;
2405 g_assert (sigaltstack (&sa, NULL) == 0);
2407 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);
2410 void
2411 mono_free_altstack (MonoJitTlsData *tls)
2413 stack_t sa;
2414 int err;
2416 sa.ss_sp = tls->signal_stack;
2417 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
2418 sa.ss_flags = SS_DISABLE;
2419 err = sigaltstack (&sa, NULL);
2420 g_assert (err == 0);
2422 if (tls->signal_stack)
2423 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MEM_ACCOUNT_EXCEPTIONS);
2424 if (tls->stack_ovf_valloced)
2425 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MEM_ACCOUNT_EXCEPTIONS);
2426 else
2427 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
2430 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
2432 void
2433 mono_setup_altstack (MonoJitTlsData *tls)
2437 void
2438 mono_free_altstack (MonoJitTlsData *tls)
2442 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
2444 gboolean
2445 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
2447 if (mono_llvm_only)
2448 return FALSE;
2450 /* we got a stack overflow in the soft-guard pages
2451 * There are two cases:
2452 * 1) managed code caused the overflow: we unprotect the soft-guard page
2453 * and let the arch-specific code trigger the exception handling mechanism
2454 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
2455 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
2456 * and hope we can continue with those enabled, at least until the hard-guard page
2457 * is hit. The alternative to continuing here is to just print a message and abort.
2458 * We may add in the future the code to protect the pages again in the codepath
2459 * when we return from unmanaged to managed code.
2461 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
2462 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
2463 gboolean handled = FALSE;
2465 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
2466 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2467 if (ji) {
2468 mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE);
2469 handled = TRUE;
2471 #endif
2472 if (!handled) {
2473 /* We print a message: after this even managed stack overflows
2474 * may crash the runtime
2476 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
2477 if (!jit_tls->handling_stack_ovf) {
2478 jit_tls->handling_stack_ovf = 1;
2479 } else {
2480 /*fprintf (stderr, "Already handling stack overflow\n");*/
2483 return TRUE;
2485 return FALSE;
2488 typedef struct {
2489 MonoMethod *omethod;
2490 int count;
2491 } PrintOverflowUserData;
2493 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2494 static gboolean
2495 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2497 MonoMethod *method = NULL;
2498 PrintOverflowUserData *user_data = (PrintOverflowUserData *)data;
2499 gchar *location;
2501 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2502 method = jinfo_get_method (frame->ji);
2504 if (method) {
2505 if (user_data->count == 0) {
2506 /* The first frame is in its prolog, so a line number cannot be computed */
2507 user_data->count ++;
2508 return FALSE;
2511 /* If this is a one method overflow, skip the other instances */
2512 if (method == user_data->omethod)
2513 return FALSE;
2515 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2516 mono_runtime_printf_err (" %s", location);
2517 g_free (location);
2519 if (user_data->count == 1) {
2520 mono_runtime_printf_err (" <...>");
2521 user_data->omethod = method;
2522 } else {
2523 user_data->omethod = NULL;
2526 user_data->count ++;
2527 } else
2528 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame->native_offset);
2530 return FALSE;
2532 #endif
2534 void
2535 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
2537 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2538 PrintOverflowUserData ud;
2539 MonoContext mctx;
2540 #endif
2542 /* we don't do much now, but we can warn the user with a useful message */
2543 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
2545 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2546 mono_sigctx_to_monoctx (ctx, &mctx);
2548 mono_runtime_printf_err ("Stacktrace:");
2550 memset (&ud, 0, sizeof (ud));
2552 mono_walk_stack_with_ctx (print_overflow_stack_frame, &mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
2553 #else
2554 if (ji && !ji->is_trampoline && jinfo_get_method (ji))
2555 mono_runtime_printf_err ("At %s", mono_method_full_name (jinfo_get_method (ji), TRUE));
2556 else
2557 mono_runtime_printf_err ("At <unmanaged>.");
2558 #endif
2560 _exit (1);
2563 static gboolean
2564 print_stack_frame_to_stderr (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2566 MonoMethod *method = NULL;
2568 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2569 method = jinfo_get_method (frame->ji);
2571 if (method) {
2572 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2573 mono_runtime_printf_err (" %s", location);
2574 g_free (location);
2575 } else
2576 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame->native_offset);
2578 return FALSE;
2581 static G_GNUC_UNUSED gboolean
2582 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2584 GString *p = (GString*)data;
2585 MonoMethod *method = NULL;
2587 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2588 method = jinfo_get_method (frame->ji);
2590 if (method && frame->domain) {
2591 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
2592 g_string_append_printf (p, " %s\n", location);
2593 g_free (location);
2594 } else
2595 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
2597 return FALSE;
2600 #ifndef MONO_CROSS_COMPILE
2602 static void print_process_map (void)
2604 #ifdef __linux__
2605 FILE *fp = fopen ("/proc/self/maps", "r");
2606 char line [256];
2608 if (fp == NULL) {
2609 mono_runtime_printf_err ("no /proc/self/maps, not on linux?\n");
2610 return;
2613 mono_runtime_printf_err ("/proc/self/maps:");
2615 while (fgets (line, sizeof (line), fp)) {
2616 // strip newline
2617 size_t len = strlen (line) - 1;
2618 if (len >= 0 && line [len] == '\n')
2619 line [len] = '\0';
2621 mono_runtime_printf_err ("%s", line);
2624 fclose (fp);
2625 #else
2626 /* do nothing */
2627 #endif
2630 static gboolean handle_crash_loop = FALSE;
2633 * mono_handle_native_crash:
2635 * Handle a native crash (e.g. SIGSEGV) while in native code by
2636 * printing diagnostic information and aborting.
2638 void
2639 mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
2641 #ifdef MONO_ARCH_USE_SIGACTION
2642 struct sigaction sa;
2643 #endif
2644 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2646 if (handle_crash_loop)
2647 return;
2649 if (mini_get_debug_options ()->suspend_on_native_crash) {
2650 mono_runtime_printf_err ("Received %s, suspending...", signal);
2651 #ifdef HOST_WIN32
2652 while (1)
2654 #else
2655 while (1) {
2656 sleep (1);
2658 #endif
2661 /* prevent infinite loops in crash handling */
2662 handle_crash_loop = TRUE;
2664 /* !jit_tls means the thread was not registered with the runtime */
2665 if (jit_tls && mono_thread_internal_current ()) {
2666 mono_runtime_printf_err ("Stacktrace:\n");
2668 /* FIXME: Is MONO_UNWIND_LOOKUP_IL_OFFSET correct here? */
2669 mono_walk_stack (print_stack_frame_to_stderr, MONO_UNWIND_LOOKUP_IL_OFFSET, NULL);
2672 print_process_map ();
2674 #ifdef HAVE_BACKTRACE_SYMBOLS
2676 void *array [256];
2677 char **names;
2678 int i, size;
2680 mono_runtime_printf_err ("\nNative stacktrace:\n");
2682 size = backtrace (array, 256);
2683 names = backtrace_symbols (array, size);
2684 for (i =0; i < size; ++i) {
2685 mono_runtime_printf_err ("\t%s", names [i]);
2687 g_free (names);
2689 /* Try to get more meaningful information using gdb */
2691 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && (defined(SYS_fork) || HAVE_FORK)
2692 if (!mini_get_debug_options ()->no_gdb_backtrace) {
2693 /* From g_spawn_command_line_sync () in eglib */
2694 pid_t pid;
2695 int status;
2696 pid_t crashed_pid = getpid ();
2699 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
2700 * it will deadlock. Call the syscall directly instead.
2702 #if defined(HOST_ANDROID)
2703 /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
2704 g_assert_not_reached ();
2705 #elif !defined(HOST_DARWIN) && defined(SYS_fork)
2706 pid = (pid_t) syscall (SYS_fork);
2707 #elif HAVE_FORK
2708 pid = (pid_t) fork ();
2709 #else
2710 g_assert_not_reached ();
2711 #endif
2713 #if defined (HAVE_PRCTL) && defined(PR_SET_PTRACER)
2714 if (pid > 0) {
2715 // Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to
2716 // a value other than 0 (the most permissive ptrace scope). Most modern Linux
2717 // distributions set the scope to 1 which allows attaching only to direct children of
2718 // the current process
2719 prctl (PR_SET_PTRACER, pid, 0, 0, 0);
2721 #endif
2723 #if defined(TARGET_OSX)
2724 if (mono_merp_enabled ()) {
2725 if (pid == 0) {
2726 MonoContext mctx;
2727 if (!ctx) {
2728 mono_runtime_printf_err ("\nMust always pass non-null context when using merp.\n");
2729 exit (1);
2732 mono_sigctx_to_monoctx (ctx, &mctx);
2734 intptr_t thread_pointer = (intptr_t) MONO_CONTEXT_GET_SP (&mctx);
2736 mono_merp_invoke (crashed_pid, thread_pointer, signal);
2738 exit (1);
2741 #endif
2743 if (pid == 0) {
2744 dup2 (STDERR_FILENO, STDOUT_FILENO);
2746 mono_gdb_render_native_backtraces (crashed_pid);
2747 exit (1);
2750 mono_runtime_printf_err ("\nDebug info from gdb:\n");
2751 waitpid (pid, &status, 0);
2753 #endif
2755 #else
2756 #ifdef HOST_ANDROID
2757 /* set DUMPABLE for this process so debuggerd can attach with ptrace(2), see:
2758 * https://android.googlesource.com/platform/bionic/+/151da681000c07da3c24cd30a3279b1ca017f452/linker/debugger.cpp#206
2759 * this has changed on later versions of Android. Also, we don't want to
2760 * set this on start-up as DUMPABLE has security implications. */
2761 prctl (PR_SET_DUMPABLE, 1);
2763 mono_runtime_printf_err ("\nNo native Android stacktrace (see debuggerd output).\n");
2764 #endif
2765 #endif
2768 * A SIGSEGV indicates something went very wrong so we can no longer depend
2769 * on anything working. So try to print out lots of diagnostics, starting
2770 * with ones which have a greater chance of working.
2772 mono_runtime_printf_err (
2773 "\n"
2774 "=================================================================\n"
2775 "Got a %s while executing native code. This usually indicates\n"
2776 "a fatal error in the mono runtime or one of the native libraries \n"
2777 "used by your application.\n"
2778 "=================================================================\n",
2779 signal);
2781 #ifdef MONO_ARCH_USE_SIGACTION
2782 sa.sa_handler = SIG_DFL;
2783 sigemptyset (&sa.sa_mask);
2784 sa.sa_flags = 0;
2786 /* Remove our SIGABRT handler */
2787 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
2789 /* On some systems we get a SIGILL when calling abort (), because it might
2790 * fail to raise SIGABRT */
2791 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
2792 #endif
2794 if (!mono_do_crash_chaining) {
2795 /*Android abort is a fluke, it doesn't abort, it triggers another segv. */
2796 #if defined (HOST_ANDROID)
2797 exit (-1);
2798 #else
2799 abort ();
2800 #endif
2804 #else
2806 void
2807 mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
2809 g_assert_not_reached ();
2812 #endif /* !MONO_CROSS_COMPILE */
2814 static void
2815 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
2817 MonoInternalThread *thread = mono_thread_internal_current ();
2818 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2819 MonoContext ctx;
2820 #endif
2821 GString* text;
2822 char *name;
2823 GError *gerror = NULL;
2825 if (!thread)
2826 return;
2828 text = g_string_new (0);
2829 if (thread->name) {
2830 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &gerror);
2831 g_assert (!gerror);
2832 g_string_append_printf (text, "\n\"%s\"", name);
2833 g_free (name);
2835 else if (thread->threadpool_thread)
2836 g_string_append (text, "\n\"<threadpool thread>\"");
2837 else
2838 g_string_append (text, "\n\"<unnamed thread>\"");
2840 g_string_append_printf (text, " tid=%p this=%p ", (gpointer)(gsize)thread->tid, thread);
2841 mono_thread_internal_describe (thread, text);
2842 g_string_append (text, "\n");
2844 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2845 if (start_ctx) {
2846 memcpy (&ctx, start_ctx, sizeof (MonoContext));
2847 } else if (!sigctx)
2848 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
2849 else
2850 mono_sigctx_to_monoctx (sigctx, &ctx);
2852 mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
2853 #else
2854 mono_runtime_printf ("\t<Stack traces in thread dumps not supported on this platform>");
2855 #endif
2857 mono_runtime_printf ("%s", text->str);
2859 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
2860 OutputDebugStringA(text->str);
2861 #endif
2863 g_string_free (text, TRUE);
2864 mono_runtime_stdout_fflush ();
2868 * mono_print_thread_dump:
2870 * Print information about the current thread to stdout.
2871 * \p sigctx can be NULL, allowing this to be called from gdb.
2873 void
2874 mono_print_thread_dump (void *sigctx)
2876 mono_print_thread_dump_internal (sigctx, NULL);
2879 void
2880 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2882 mono_print_thread_dump_internal (NULL, ctx);
2886 * mono_resume_unwind:
2888 * This is called by a trampoline from LLVM compiled finally clauses to continue
2889 * unwinding.
2891 void
2892 mono_resume_unwind (MonoContext *ctx)
2894 MONO_REQ_GC_UNSAFE_MODE;
2896 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2897 MonoContext new_ctx;
2899 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
2900 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
2901 new_ctx = *ctx;
2903 mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL);
2905 mono_restore_context (&new_ctx);
2908 typedef struct {
2909 MonoJitInfo *ji;
2910 MonoContext ctx;
2911 MonoJitExceptionInfo *ei;
2912 } FindHandlerBlockData;
2914 static gboolean
2915 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2917 int i;
2918 gpointer ip;
2919 FindHandlerBlockData *pdata = (FindHandlerBlockData *)data;
2920 MonoJitInfo *ji = frame->ji;
2922 if (!ji)
2923 return FALSE;
2925 ip = MONO_CONTEXT_GET_IP (ctx);
2927 for (i = 0; i < ji->num_clauses; ++i) {
2928 MonoJitExceptionInfo *ei = ji->clauses + i;
2929 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2930 continue;
2931 /*If ip points to the first instruction it means the handler block didn't start
2932 so we can leave its execution to the EH machinery*/
2933 if (ei->handler_start <= ip && ip < ei->data.handler_end) {
2934 pdata->ji = ji;
2935 pdata->ei = ei;
2936 pdata->ctx = *ctx;
2937 break;
2940 return FALSE;
2944 static void
2945 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
2947 int i;
2948 MonoJitExceptionInfo *clause = NULL;
2949 gpointer ip;
2950 guint8 *bp;
2952 ip = MONO_CONTEXT_GET_IP (ctx);
2954 for (i = 0; i < ji->num_clauses; ++i) {
2955 clause = &ji->clauses [i];
2956 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2957 continue;
2958 if (clause->handler_start <= ip && clause->data.handler_end > ip)
2959 break;
2962 /*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
2963 g_assert (i < ji->num_clauses);
2965 /*Load the spvar*/
2966 bp = (guint8*)MONO_CONTEXT_GET_BP (ctx);
2967 *(bp + clause->exvar_offset) = 1;
2971 * Finds the bottom handler block running and install a block guard if needed.
2973 static gboolean
2974 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
2976 FindHandlerBlockData data = { 0 };
2977 MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
2979 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
2980 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
2982 if (!jit_tls || jit_tls->handler_block)
2983 return FALSE;
2985 /* Do an async safe stack walk */
2986 mono_thread_info_set_is_async_context (TRUE);
2987 mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data);
2988 mono_thread_info_set_is_async_context (FALSE);
2990 if (!data.ji)
2991 return FALSE;
2993 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
2995 install_handler_block_guard (data.ji, &data.ctx);
2997 jit_tls->handler_block = data.ei;
2999 return TRUE;
3002 static void
3003 mono_uninstall_current_handler_block_guard (void)
3005 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3006 if (jit_tls)
3007 jit_tls->handler_block = NULL;
3011 static gboolean
3012 mono_current_thread_has_handle_block_guard (void)
3014 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3015 return jit_tls && jit_tls->handler_block != NULL;
3018 void
3019 mono_set_cast_details (MonoClass *from, MonoClass *to)
3021 MonoJitTlsData *jit_tls = NULL;
3023 if (mini_get_debug_options ()->better_cast_details) {
3024 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3025 jit_tls->class_cast_from = from;
3026 jit_tls->class_cast_to = to;
3031 /*returns false if the thread is not attached*/
3032 gboolean
3033 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
3035 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3036 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3037 if (!thread) {
3038 ctx->valid = FALSE;
3039 return FALSE;
3042 if (sigctx) {
3043 mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
3045 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3046 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3047 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3049 else {
3050 mono_thread_state_init (ctx);
3053 if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
3054 return FALSE;
3056 ctx->valid = TRUE;
3057 return TRUE;
3058 #else
3059 g_error ("Implement mono_arch_sigctx_to_monoctx for the current target");
3060 return FALSE;
3061 #endif
3064 void
3065 mono_thread_state_init (MonoThreadUnwindState *ctx)
3067 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3069 #if defined(MONO_CROSS_COMPILE)
3070 ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
3071 #elif MONO_ARCH_HAS_MONO_CONTEXT
3072 MONO_CONTEXT_GET_CURRENT (ctx->ctx);
3073 #else
3074 g_error ("Use a null sigctx requires a working mono-context");
3075 #endif
3077 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3078 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3079 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
3080 ctx->valid = TRUE;
3084 gboolean
3085 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
3087 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3088 if (!thread) {
3089 ctx->valid = FALSE;
3090 return FALSE;
3093 ctx->ctx = *mctx;
3094 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3095 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3096 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3097 ctx->valid = TRUE;
3098 return TRUE;
3101 /*returns false if the thread is not attached*/
3102 gboolean
3103 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
3105 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3106 MONO_ARCH_CONTEXT_DEF
3108 mono_arch_flush_register_windows ();
3110 if (!thread || !thread->jit_data) {
3111 ctx->valid = FALSE;
3112 return FALSE;
3114 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
3115 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx->ctx);
3116 #else
3117 MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
3118 #endif
3120 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3121 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3122 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3123 ctx->valid = TRUE;
3124 return TRUE;
3127 static void
3128 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
3130 mono_handle_exception (ctx, (MonoObject *)exc);
3131 mono_restore_context (ctx);
3134 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3135 void
3136 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
3138 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3139 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3140 jit_tls->ex_ctx = *ctx;
3142 mono_arch_setup_async_callback (ctx, async_cb, user_data);
3143 #else
3144 g_error ("This target doesn't support mono_arch_setup_async_callback");
3145 #endif
3149 * mono_restore_context:
3151 * Call the architecture specific restore context function.
3153 void
3154 mono_restore_context (MonoContext *ctx)
3156 static void (*restore_context) (MonoContext *);
3158 if (!restore_context)
3159 restore_context = (void (*)(MonoContext *))mono_get_restore_context ();
3160 restore_context (ctx);
3161 g_assert_not_reached ();
3165 * mono_jinfo_get_unwind_info:
3167 * Return the unwind info for JI.
3169 guint8*
3170 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
3172 if (ji->has_unwind_info) {
3173 /* The address/length in the MonoJitInfo structure itself */
3174 MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji);
3175 *unwind_info_len = info->unw_info_len;
3176 return info->unw_info;
3177 } else if (ji->from_aot)
3178 return mono_aot_get_unwind_info (ji, unwind_info_len);
3179 else
3180 return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
3184 mono_jinfo_get_epilog_size (MonoJitInfo *ji)
3186 MonoArchEHJitInfo *info;
3188 info = mono_jit_info_get_arch_eh_info (ji);
3189 g_assert (info);
3191 return info->epilog_size;
3195 * LLVM/Bitcode exception handling.
3198 static void
3199 throw_exception (MonoObject *ex, gboolean rethrow)
3201 MONO_REQ_GC_UNSAFE_MODE;
3203 ERROR_DECL (error);
3204 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3205 MonoException *mono_ex;
3207 if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, error)) {
3208 mono_error_assert_ok (error);
3209 mono_ex = mono_get_exception_runtime_wrapped_checked (ex, error);
3210 mono_error_assert_ok (error);
3211 jit_tls->thrown_non_exc = mono_gchandle_new (ex, FALSE);
3213 else
3214 mono_ex = (MonoException*)ex;
3216 // Note: Not pinned
3217 jit_tls->thrown_exc = mono_gchandle_new ((MonoObject*)mono_ex, FALSE);
3219 if (!rethrow) {
3220 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3221 GList *l, *ips = NULL;
3222 GList *trace;
3224 _Unwind_Backtrace (build_stack_trace, &ips);
3225 /* The list contains ip-gshared info pairs */
3226 trace = NULL;
3227 ips = g_list_reverse (ips);
3228 for (l = ips; l; l = l->next) {
3229 trace = g_list_append (trace, l->data);
3230 trace = g_list_append (trace, NULL);
3231 trace = g_list_append (trace, NULL);
3233 MonoArray *ips_arr = mono_glist_to_array (trace, mono_defaults.int_class, error);
3234 mono_error_assert_ok (error);
3235 MONO_OBJECT_SETREF (mono_ex, trace_ips, ips_arr);
3236 g_list_free (l);
3237 g_list_free (trace);
3238 #endif
3241 mono_llvm_cpp_throw_exception ();
3244 void
3245 mono_llvm_throw_exception (MonoObject *ex)
3247 throw_exception (ex, FALSE);
3250 void
3251 mono_llvm_rethrow_exception (MonoObject *ex)
3253 throw_exception (ex, TRUE);
3256 void
3257 mono_llvm_raise_exception (MonoException *e)
3259 mono_llvm_throw_exception ((MonoObject*)e);
3262 void
3263 mono_llvm_reraise_exception (MonoException *e)
3265 mono_llvm_rethrow_exception ((MonoObject*)e);
3268 void
3269 mono_llvm_throw_corlib_exception (guint32 ex_token_index)
3271 guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
3272 MonoException *ex;
3274 ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token);
3276 mono_llvm_throw_exception ((MonoObject*)ex);
3280 * mono_llvm_resume_exception:
3282 * Resume exception propagation.
3284 void
3285 mono_llvm_resume_exception (void)
3287 mono_llvm_cpp_throw_exception ();
3291 * mono_llvm_load_exception:
3293 * Return the currently thrown exception.
3295 MonoObject *
3296 mono_llvm_load_exception (void)
3298 ERROR_DECL (error);
3299 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3301 MonoException *mono_ex = (MonoException*)mono_gchandle_get_target (jit_tls->thrown_exc);
3303 if (mono_ex->trace_ips) {
3304 GList *trace_ips = NULL;
3305 gpointer ip = MONO_RETURN_ADDRESS ();
3307 size_t upper = mono_array_length (mono_ex->trace_ips);
3309 for (int i = 0; i < upper; i += TRACE_IP_ENTRY_SIZE) {
3310 gpointer curr_ip = mono_array_get (mono_ex->trace_ips, gpointer, i);
3311 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
3312 gpointer p = mono_array_get (mono_ex->trace_ips, gpointer, i + j);
3313 trace_ips = g_list_append (trace_ips, p);
3315 if (ip == curr_ip)
3316 break;
3319 // FIXME: Does this work correctly for rethrows?
3320 // We may be discarding useful information
3321 // when this gets GC'ed
3322 MonoArray *ips_arr = mono_glist_to_array (trace_ips, mono_defaults.int_class, error);
3323 mono_error_assert_ok (error);
3324 MONO_OBJECT_SETREF (mono_ex, trace_ips, ips_arr);
3325 g_list_free (trace_ips);
3327 // FIXME:
3328 //MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3329 } else {
3330 MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, 0, error));
3331 mono_error_assert_ok (error);
3332 MONO_OBJECT_SETREF (mono_ex, stack_trace, mono_array_new_checked (mono_domain_get (), mono_defaults.stack_frame_class, 0, error));
3333 mono_error_assert_ok (error);
3336 return &mono_ex->object;
3340 * mono_llvm_clear_exception:
3342 * Mark the currently thrown exception as handled.
3344 void
3345 mono_llvm_clear_exception (void)
3347 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3348 mono_gchandle_free (jit_tls->thrown_exc);
3349 jit_tls->thrown_exc = 0;
3350 if (jit_tls->thrown_non_exc)
3351 mono_gchandle_free (jit_tls->thrown_non_exc);
3352 jit_tls->thrown_non_exc = 0;
3354 mono_memory_barrier ();
3358 * mono_llvm_match_exception:
3360 * Return the innermost clause containing REGION_START-REGION_END which can handle
3361 * the current exception.
3363 gint32
3364 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
3366 ERROR_DECL (error);
3367 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3368 MonoObject *exc;
3369 gint32 index = -1;
3371 g_assert (jit_tls->thrown_exc);
3372 exc = mono_gchandle_get_target (jit_tls->thrown_exc);
3373 if (jit_tls->thrown_non_exc) {
3375 * Have to unwrap RuntimeWrappedExceptions if the
3376 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
3378 if (!wrap_non_exception_throws (jinfo_get_method (jinfo)))
3379 exc = mono_gchandle_get_target (jit_tls->thrown_non_exc);
3382 for (int i = 0; i < jinfo->num_clauses; i++) {
3383 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
3384 MonoClass *catch_class;
3386 if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
3387 continue;
3389 catch_class = ei->data.catch_class;
3390 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (catch_class))) {
3391 MonoGenericContext context;
3392 MonoType *inflated_type;
3394 g_assert (rgctx || this_obj);
3395 context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
3396 inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
3397 mono_error_assert_ok (error); /* FIXME don't swallow the error */
3399 catch_class = mono_class_from_mono_type (inflated_type);
3400 mono_metadata_free_type (inflated_type);
3403 // FIXME: Handle edge cases handled in get_exception_catch_class
3404 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, error)) {
3405 index = ei->clause_index;
3406 break;
3407 } else
3408 mono_error_assert_ok (error);
3410 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3411 g_assert_not_reached ();
3415 return index;
3418 #ifdef ENABLE_LLVM
3419 _Unwind_Reason_Code
3420 mono_debug_personality (int a, _Unwind_Action b,
3421 uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
3423 g_assert_not_reached ();
3425 #else
3426 void
3427 mono_debug_personality (void);
3429 void
3430 mono_debug_personality (void)
3432 g_assert_not_reached ();
3434 #endif