Fix guard interrupt protection.
[mono-project.git] / mono / mini / mini-exceptions.c
blobca637adbe5e7be82964c1b41e774a009f3c11527
1 /*
2 * mini-exceptions.c: generic exception support
4 * Authors:
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Mono Team (mono-list@lists.ximian.com)
8 * Copyright 2001-2003 Ximian, Inc.
9 * Copyright 2003-2008 Ximian, Inc.
12 #include <config.h>
13 #include <glib.h>
14 #include <signal.h>
15 #include <string.h>
17 #ifdef HAVE_EXECINFO_H
18 #include <execinfo.h>
19 #endif
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
23 #endif
25 #ifdef HAVE_SYS_WAIT_H
26 #include <sys/wait.h>
27 #endif
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
33 #ifdef HAVE_SYS_SYSCALL_H
34 #include <sys/syscall.h>
35 #endif
37 #include <mono/metadata/appdomain.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/threads-types.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include <mono/metadata/exception.h>
43 #include <mono/metadata/gc-internal.h>
44 #include <mono/metadata/mono-debug.h>
45 #include <mono/metadata/profiler.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/utils/mono-mmap.h>
49 #include "mini.h"
50 #include "debug-mini.h"
51 #include "trace.h"
52 #include "debugger-agent.h"
54 #ifndef MONO_ARCH_CONTEXT_DEF
55 #define MONO_ARCH_CONTEXT_DEF
56 #endif
58 static gpointer restore_context_func, call_filter_func;
59 static gpointer throw_exception_func, rethrow_exception_func;
60 static gpointer throw_corlib_exception_func;
62 static gpointer try_more_restore_tramp = NULL;
63 static gpointer restore_stack_protection_tramp = NULL;
65 static void try_more_restore (void);
66 static void restore_stack_protection (void);
68 void
69 mono_exceptions_init (void)
71 if (mono_aot_only) {
72 restore_context_func = mono_aot_get_trampoline ("restore_context");
73 call_filter_func = mono_aot_get_trampoline ("call_filter");
74 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
75 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
76 } else {
77 MonoTrampInfo *info;
79 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
80 if (info) {
81 mono_save_trampoline_xdebug_info (info);
82 mono_tramp_info_free (info);
84 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
85 if (info) {
86 mono_save_trampoline_xdebug_info (info);
87 mono_tramp_info_free (info);
89 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
90 if (info) {
91 mono_save_trampoline_xdebug_info (info);
92 mono_tramp_info_free (info);
94 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
95 if (info) {
96 mono_save_trampoline_xdebug_info (info);
97 mono_tramp_info_free (info);
100 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
101 try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
102 restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
103 #endif
105 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
106 mono_arch_exceptions_init ();
107 #endif
110 gpointer
111 mono_get_throw_exception (void)
113 g_assert (throw_exception_func);
114 return throw_exception_func;
117 gpointer
118 mono_get_rethrow_exception (void)
120 g_assert (rethrow_exception_func);
121 return rethrow_exception_func;
124 gpointer
125 mono_get_call_filter (void)
127 g_assert (call_filter_func);
128 return call_filter_func;
131 gpointer
132 mono_get_restore_context (void)
134 g_assert (restore_context_func);
135 return restore_context_func;
138 gpointer
139 mono_get_throw_corlib_exception (void)
141 gpointer code = NULL;
142 MonoTrampInfo *info;
144 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
145 if (throw_corlib_exception_func)
146 return throw_corlib_exception_func;
148 if (mono_aot_only)
149 code = mono_aot_get_trampoline ("throw_corlib_exception");
150 else {
151 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
152 if (info) {
153 mono_save_trampoline_xdebug_info (info);
154 mono_tramp_info_free (info);
158 mono_memory_barrier ();
160 throw_corlib_exception_func = code;
162 return throw_corlib_exception_func;
165 static gboolean
166 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
168 MonoTryBlockHoleTableJitInfo *table;
169 int i;
170 guint32 offset;
171 guint16 clause;
173 if (ei->try_start > ip || ip >= ei->try_end)
174 return FALSE;
176 if (!ji->has_try_block_holes)
177 return TRUE;
179 table = mono_jit_info_get_try_block_hole_table_info (ji);
180 offset = (guint32)((char*)ip - (char*)ji->code_start);
181 clause = (guint16)(ei - ji->clauses);
182 g_assert (clause < ji->num_clauses);
184 for (i = 0; i < table->num_holes; ++i) {
185 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
186 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
187 return FALSE;
189 return TRUE;
193 * find_jit_info:
195 * Translate between the mono_arch_find_jit_info function and the old API.
197 static MonoJitInfo *
198 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
199 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
201 StackFrameInfo frame;
202 MonoJitInfo *ji;
203 gboolean err;
204 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
206 /* Avoid costly table lookup during stack overflow */
207 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
208 ji = prev_ji;
209 else
210 ji = mini_jit_info_table_find (domain, ip, NULL);
212 if (managed)
213 *managed = FALSE;
215 err = mono_arch_find_jit_info (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
216 if (!err)
217 return (gpointer)-1;
219 /* Convert between the new and the old APIs */
220 switch (frame.type) {
221 case FRAME_TYPE_MANAGED:
222 if (managed)
223 *managed = TRUE;
224 return frame.ji;
225 case FRAME_TYPE_MANAGED_TO_NATIVE:
226 if (frame.ji)
227 return frame.ji;
228 else {
229 memset (res, 0, sizeof (MonoJitInfo));
230 res->method = frame.method;
231 return res;
233 case FRAME_TYPE_DEBUGGER_INVOKE: {
234 MonoContext tmp_ctx;
237 * The normal exception handling code can't handle this frame, so just
238 * skip it.
240 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
241 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
242 return ji;
244 default:
245 g_assert_not_reached ();
246 return NULL;
250 /* mono_find_jit_info:
252 * This function is used to gather information from @ctx. It return the
253 * MonoJitInfo of the corresponding function, unwinds one stack frame and
254 * stores the resulting context into @new_ctx. It also stores a string
255 * describing the stack location into @trace (if not NULL), and modifies
256 * the @lmf if necessary. @native_offset return the IP offset from the
257 * start of the function or -1 if that info is not available.
259 MonoJitInfo *
260 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
261 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
262 gboolean *managed)
264 gboolean managed2;
265 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
266 MonoJitInfo *ji;
268 if (trace)
269 *trace = NULL;
271 if (native_offset)
272 *native_offset = -1;
274 if (managed)
275 *managed = FALSE;
277 ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
279 if (ji == (gpointer)-1)
280 return ji;
282 if (managed2 || (ji && ji->method->wrapper_type)) {
283 const char *real_ip, *start;
284 gint32 offset;
286 start = (const char *)ji->code_start;
287 if (!managed2)
288 /* ctx->ip points into native code */
289 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
290 else
291 real_ip = (const char*)ip;
293 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
294 offset = real_ip - start;
295 else
296 offset = -1;
298 if (native_offset)
299 *native_offset = offset;
301 if (managed)
302 if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
303 *managed = TRUE;
305 if (trace)
306 *trace = mono_debug_print_stack_frame (ji->method, offset, domain);
307 } else {
308 if (trace) {
309 char *fname = mono_method_full_name (res->method, TRUE);
310 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
311 g_free (fname);
315 return ji;
319 * mono_find_jit_info_ext:
321 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
322 * structure.
323 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
324 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
325 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
326 * to obtain the last managed frame.
327 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
328 * On return, it will be filled with the locations where callee saved registers are saved
329 * by the current frame. This is returned outside of StackFrameInfo because it can be
330 * quite large on some platforms.
332 gboolean
333 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
334 MonoJitInfo *prev_ji, MonoContext *ctx,
335 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
336 mgreg_t **save_locations,
337 StackFrameInfo *frame)
339 gboolean err;
340 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
341 MonoJitInfo *ji;
342 MonoDomain *target_domain;
344 if (trace)
345 *trace = NULL;
347 /* Avoid costly table lookup during stack overflow */
348 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
349 ji = prev_ji;
350 else
351 ji = mini_jit_info_table_find (domain, ip, &target_domain);
353 if (!target_domain)
354 target_domain = domain;
356 if (save_locations)
357 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (mgreg_t*));
359 err = mono_arch_find_jit_info (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
360 if (!err)
361 return FALSE;
363 if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
365 * This type of frame is just a marker, the caller should unwind once more to get the
366 * last managed frame.
368 frame->ji = NULL;
369 frame->method = NULL;
372 frame->native_offset = -1;
373 frame->domain = target_domain;
375 ji = frame->ji;
377 if (frame->type == FRAME_TYPE_MANAGED)
378 frame->method = ji->method;
380 if (ji && (frame->managed || ji->method->wrapper_type)) {
381 const char *real_ip, *start;
383 start = (const char *)ji->code_start;
384 if (!frame->managed)
385 /* ctx->ip points into native code */
386 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
387 else
388 real_ip = (const char*)ip;
390 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
391 frame->native_offset = real_ip - start;
392 else
393 frame->native_offset = -1;
395 if (trace)
396 *trace = mono_debug_print_stack_frame (ji->method, frame->native_offset, domain);
397 } else {
398 if (trace && frame->method) {
399 char *fname = mono_method_full_name (frame->method, TRUE);
400 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
401 g_free (fname);
405 return TRUE;
408 static gpointer
409 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
411 MonoGenericJitInfo *gi;
412 gpointer info;
414 if (!ji->has_generic_jit_info)
415 return NULL;
416 gi = mono_jit_info_get_generic_jit_info (ji);
417 if (!gi->has_this)
418 return NULL;
420 if (gi->this_in_reg)
421 info = mono_arch_context_get_int_reg (ctx, gi->this_reg);
422 else
423 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
424 gi->this_offset);
425 if (mono_method_get_context (ji->method)->method_inst) {
426 return info;
427 } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
428 return info;
429 } else {
430 /* Avoid returning a managed object */
431 MonoObject *this_obj = info;
433 return this_obj->vtable->klass;
437 static MonoGenericContext
438 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
440 MonoGenericContext context = { NULL, NULL };
441 MonoClass *class, *method_container_class;
443 g_assert (generic_info);
445 g_assert (ji->method->is_inflated);
446 if (mono_method_get_context (ji->method)->method_inst) {
447 MonoMethodRuntimeGenericContext *mrgctx = generic_info;
449 class = mrgctx->class_vtable->klass;
450 context.method_inst = mrgctx->method_inst;
451 g_assert (context.method_inst);
452 } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
453 MonoVTable *vtable = generic_info;
455 class = vtable->klass;
456 } else {
457 class = generic_info;
460 //g_assert (!ji->method->klass->generic_container);
461 if (ji->method->klass->generic_class)
462 method_container_class = ji->method->klass->generic_class->container_class;
463 else
464 method_container_class = ji->method->klass;
466 /* class might refer to a subclass of ji->method's class */
467 while (!(class == ji->method->klass || (class->generic_class && class->generic_class->container_class == method_container_class))) {
468 class = class->parent;
469 g_assert (class);
472 if (class->generic_class || class->generic_container)
473 context.class_inst = mini_class_get_context (class)->class_inst;
475 if (class->generic_class)
476 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class->container_class, method_container_class));
477 else
478 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class));
480 return context;
483 static MonoMethod*
484 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
486 MonoGenericContext context;
487 MonoMethod *method;
489 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
490 return ji->method;
491 context = get_generic_context_from_stack_frame (ji, generic_info);
493 method = mono_method_get_declaring_generic_method (ji->method);
494 method = mono_class_inflate_generic_method (method, &context);
496 return method;
499 MonoString *
500 ves_icall_System_Exception_get_trace (MonoException *ex)
502 MonoDomain *domain = mono_domain_get ();
503 MonoString *res;
504 MonoArray *ta = ex->trace_ips;
505 int i, len;
506 GString *trace_str;
508 if (ta == NULL)
509 /* Exception is not thrown yet */
510 return NULL;
512 len = mono_array_length (ta) >> 1;
513 trace_str = g_string_new ("");
514 for (i = 0; i < len; i++) {
515 MonoJitInfo *ji;
516 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
517 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
519 ji = mono_jit_info_table_find (domain, ip);
520 if (ji == NULL) {
521 /* Unmanaged frame */
522 g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
523 } else {
524 gchar *location;
525 gint32 address;
526 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
528 address = (char *)ip - (char *)ji->code_start;
529 location = mono_debug_print_stack_frame (
530 method, address, ex->object.vtable->domain);
532 g_string_append_printf (trace_str, "%s\n", location);
533 g_free (location);
537 res = mono_string_new (ex->object.vtable->domain, trace_str->str);
538 g_string_free (trace_str, TRUE);
540 return res;
543 MonoArray *
544 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
546 MonoDomain *domain = mono_domain_get ();
547 MonoArray *res;
548 MonoArray *ta = exc->trace_ips;
549 MonoDebugSourceLocation *location;
550 int i, len;
552 if (ta == NULL) {
553 /* Exception is not thrown yet */
554 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
557 len = mono_array_length (ta) >> 1;
559 res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
561 for (i = skip; i < len; i++) {
562 MonoJitInfo *ji;
563 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
564 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
565 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
566 MonoMethod *method;
568 ji = mono_jit_info_table_find (domain, ip);
569 if (ji == NULL) {
570 /* Unmanaged frame */
571 mono_array_setref (res, i, sf);
572 continue;
575 g_assert (ji != NULL);
577 method = get_method_from_stack_frame (ji, generic_info);
578 if (ji->method->wrapper_type) {
579 char *s;
581 sf->method = NULL;
582 s = mono_method_full_name (method, TRUE);
583 MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
584 g_free (s);
586 else
587 MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
588 sf->native_offset = (char *)ip - (char *)ji->code_start;
591 * mono_debug_lookup_source_location() returns both the file / line number information
592 * and the IL offset. Note that computing the IL offset is already an expensive
593 * operation, so we shouldn't call this method twice.
595 location = mono_debug_lookup_source_location (ji->method, sf->native_offset, domain);
596 if (location)
597 sf->il_offset = location->il_offset;
598 else
599 sf->il_offset = 0;
601 if (need_file_info) {
602 if (location && location->source_file) {
603 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
604 sf->line = location->row;
605 sf->column = location->column;
606 } else {
607 sf->line = sf->column = 0;
608 sf->filename = NULL;
612 mono_debug_free_source_location (location);
613 mono_array_setref (res, i, sf);
616 return res;
619 typedef struct {
620 MonoStackWalk func;
621 gpointer user_data;
622 } StackWalkUserData;
624 static gboolean
625 stack_walk_adapter (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
627 StackWalkUserData *d = data;
629 switch (frame->type) {
630 case FRAME_TYPE_DEBUGGER_INVOKE:
631 case FRAME_TYPE_MANAGED_TO_NATIVE:
632 return FALSE;
633 case FRAME_TYPE_MANAGED:
634 g_assert (frame->ji);
635 return d->func (frame->ji->method, frame->native_offset, frame->il_offset, frame->managed, d->user_data);
636 break;
637 default:
638 g_assert_not_reached ();
639 return FALSE;
643 void
644 mono_jit_walk_stack_from_ctx (MonoStackWalk func, MonoContext *start_ctx, gboolean do_il_offset, gpointer user_data)
646 StackWalkUserData d;
648 d.func = func;
649 d.user_data = user_data;
651 mono_walk_stack (stack_walk_adapter, mono_domain_get (), start_ctx, do_il_offset, mono_thread_internal_current (), mono_get_lmf (), &d);
654 void
655 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data)
657 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
659 if (jit_tls && jit_tls->orig_ex_ctx_set)
660 mono_jit_walk_stack_from_ctx (func, &jit_tls->orig_ex_ctx, do_il_offset, user_data);
661 else
662 mono_jit_walk_stack_from_ctx (func, NULL, do_il_offset, user_data);
666 * mono_walk_stack:
667 * @func: callback to call for each stack frame
668 * @domain: starting appdomain, can be NULL to use the current domain
669 * @do_il_offsets: whenever to compute IL offsets
670 * @start_ctx: starting state of the stack walk, can be NULL.
671 * @thread: the thread whose stack to walk, can be NULL to use the current thread
672 * @lmf: the LMF of @thread, can be NULL to use the LMF of the current thread
673 * @user_data: data passed to the callback
675 * This function walks the stack of a thread, starting from the state
676 * represented by start_ctx. For each frame the callback
677 * function is called with the relevant info. The walk ends when no more
678 * managed stack frames are found or when the callback returns a TRUE value.
680 void
681 mono_walk_stack (MonoJitStackWalk func, MonoDomain *domain, MonoContext *start_ctx, gboolean do_il_offset, MonoInternalThread *thread, MonoLMF *lmf, gpointer user_data)
683 MonoJitTlsData *jit_tls;
684 gint il_offset;
685 MonoContext ctx, new_ctx;
686 StackFrameInfo frame;
687 gboolean res;
689 MONO_ARCH_CONTEXT_DEF
691 mono_arch_flush_register_windows ();
693 if (!thread) {
694 thread = mono_thread_internal_current ();
695 lmf = mono_get_lmf ();
698 /* A NULL thread->jit_data can happen in a small window during thread startup: the thread
699 * allocation happens, we do a stack walk (for example with
700 * --profile=log:nocalls and xsp) but the jit is not fully setup for the thread
701 * yet. Of course there are no stack frames, so just returning is ok.
702 * A NULL thread can happen during domain unload with the same test.
704 if (!thread || !thread->jit_data)
705 return;
706 jit_tls = thread->jit_data;
708 if (start_ctx) {
709 memcpy (&ctx, start_ctx, sizeof (MonoContext));
710 } else {
711 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
712 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
713 #else
714 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_jit_walk_stack_from_ctx);
715 #endif
716 g_assert (thread == mono_thread_internal_current ());
719 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
720 frame.lmf = lmf;
721 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
722 if (!res)
723 return;
725 if (do_il_offset && frame.ji) {
726 MonoDebugSourceLocation *source;
728 source = mono_debug_lookup_source_location (frame.ji->method, frame.native_offset, domain);
729 il_offset = source ? source->il_offset : -1;
730 mono_debug_free_source_location (source);
731 } else
732 il_offset = -1;
734 frame.il_offset = il_offset;
736 if (frame.ji) {
737 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
738 } else {
739 frame.actual_method = frame.method;
742 if (func (&frame, &ctx, user_data))
743 return;
745 ctx = new_ctx;
749 MonoBoolean
750 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
751 MonoReflectionMethod **method,
752 gint32 *iloffset, gint32 *native_offset,
753 MonoString **file, gint32 *line, gint32 *column)
755 MonoDomain *domain = mono_domain_get ();
756 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
757 MonoLMF *lmf = mono_get_lmf ();
758 MonoJitInfo *ji = NULL;
759 MonoContext ctx, new_ctx;
760 MonoDebugSourceLocation *location;
761 MonoMethod *actual_method;
762 StackFrameInfo frame;
763 gboolean res;
765 MONO_ARCH_CONTEXT_DEF;
767 mono_arch_flush_register_windows ();
769 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
770 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
771 #else
772 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
773 #endif
775 new_ctx = ctx;
776 do {
777 ctx = new_ctx;
778 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
779 if (!res)
780 return FALSE;
782 if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || frame.type == FRAME_TYPE_DEBUGGER_INVOKE)
783 continue;
785 ji = frame.ji;
786 *native_offset = frame.native_offset;
788 /* skip all wrappers ??*/
789 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
790 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
791 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
792 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
793 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE ||
794 ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
795 continue;
797 skip--;
798 } while (skip >= 0);
800 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
802 mono_gc_wbarrier_generic_store (method, (MonoObject*) mono_method_get_object (domain, actual_method, NULL));
804 location = mono_debug_lookup_source_location (ji->method, *native_offset, domain);
805 if (location)
806 *iloffset = location->il_offset;
807 else
808 *iloffset = 0;
810 if (need_file_info) {
811 if (location) {
812 mono_gc_wbarrier_generic_store (file, (MonoObject*) mono_string_new (domain, location->source_file));
813 *line = location->row;
814 *column = location->column;
815 } else {
816 *file = NULL;
817 *line = *column = 0;
821 mono_debug_free_source_location (location);
823 return TRUE;
826 typedef struct {
827 guint32 skips;
828 MonoSecurityFrame *frame;
829 } MonoFrameSecurityInfo;
831 static gboolean
832 callback_get_first_frame_security_info (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
834 MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
835 MonoJitInfo *ji = frame->ji;
837 if (!ji)
838 return FALSE;
840 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
841 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
842 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
843 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
844 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
845 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
846 return FALSE;
849 if (si->skips > 0) {
850 si->skips--;
851 return FALSE;
854 si->frame = mono_declsec_create_frame (frame->domain, ji);
856 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
857 return TRUE;
861 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
862 * @skip: the number of stack frames to skip
864 * This function returns a the security informations of a single stack frame
865 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
866 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
867 * evaluated.
869 MonoSecurityFrame*
870 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
872 MonoDomain *domain = mono_domain_get ();
873 MonoFrameSecurityInfo si;
875 si.skips = skip;
876 si.frame = NULL;
878 mono_walk_stack (callback_get_first_frame_security_info, domain, NULL, FALSE, NULL, NULL, &si);
880 return (si.skips == 0) ? si.frame : NULL;
884 typedef struct {
885 guint32 skips;
886 MonoArray *stack;
887 guint32 count;
888 guint32 maximum;
889 } MonoSecurityStack;
891 static void
892 grow_array (MonoSecurityStack *stack)
894 MonoDomain *domain = mono_domain_get ();
895 guint32 newsize = (stack->maximum << 1);
896 MonoArray *newstack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, newsize);
897 int i;
898 for (i=0; i < stack->maximum; i++) {
899 gpointer frame = mono_array_get (stack->stack, gpointer, i);
900 mono_array_setref (newstack, i, frame);
902 stack->maximum = newsize;
903 stack->stack = newstack;
906 static gboolean
907 callback_get_stack_frames_security_info (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
909 MonoSecurityStack *ss = (MonoSecurityStack*) data;
910 MonoJitInfo *ji = frame->ji;
912 if (!ji)
913 return FALSE;
915 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
916 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
917 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
918 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
919 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
920 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
921 return FALSE;
924 if (ss->skips > 0) {
925 ss->skips--;
926 return FALSE;
929 if (ss->count == ss->maximum)
930 grow_array (ss);
932 mono_array_setref (ss->stack, ss->count++, mono_declsec_create_frame (frame->domain, ji));
934 /* continue down the stack */
935 return FALSE;
938 static MonoArray *
939 glist_to_array (GList *list, MonoClass *eclass)
941 MonoDomain *domain = mono_domain_get ();
942 MonoArray *res;
943 int len, i;
945 if (!list)
946 return NULL;
948 len = g_list_length (list);
949 res = mono_array_new (domain, eclass, len);
951 for (i = 0; list; list = list->next, i++)
952 mono_array_set (res, gpointer, i, list->data);
954 return res;
958 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
959 * @skip: the number of stack frames to skip
961 * This function returns an managed array of containing the security
962 * informations for each frame (after the skipped ones). This is used for
963 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
964 * required.
966 MonoArray*
967 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
969 MonoDomain *domain = mono_domain_get ();
970 MonoSecurityStack ss;
972 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
973 skip--;
974 #endif
976 ss.skips = skip;
977 ss.count = 0;
978 ss.maximum = MONO_CAS_INITIAL_STACK_SIZE;
979 ss.stack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, ss.maximum);
980 mono_walk_stack (callback_get_stack_frames_security_info, domain, NULL, FALSE, NULL, NULL, &ss);
981 /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
982 return ss.stack;
985 static MonoClass*
986 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
988 MonoClass *catch_class = ei->data.catch_class;
989 MonoType *inflated_type;
990 MonoGenericContext context;
992 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
993 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
994 return NULL;
996 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
997 return catch_class;
998 context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1000 /* FIXME: we shouldn't inflate but instead put the
1001 type in the rgctx and fetch it from there. It
1002 might be a good idea to do this lazily, i.e. only
1003 when the exception is actually thrown, so as not to
1004 waste space for exception clauses which might never
1005 be encountered. */
1006 inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
1007 catch_class = mono_class_from_mono_type (inflated_type);
1008 mono_metadata_free_type (inflated_type);
1010 return catch_class;
1014 * mini_jit_info_table_find:
1016 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1017 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1018 * OUT_DOMAIN if it is not NULL.
1020 MonoJitInfo*
1021 mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
1023 MonoJitInfo *ji;
1024 MonoInternalThread *t = mono_thread_internal_current ();
1025 GSList *l;
1027 if (out_domain)
1028 *out_domain = NULL;
1030 ji = mono_jit_info_table_find (domain, addr);
1031 if (ji) {
1032 if (out_domain)
1033 *out_domain = domain;
1034 return ji;
1037 /* maybe it is shared code, so we also search in the root domain */
1038 if (domain != mono_get_root_domain ()) {
1039 ji = mono_jit_info_table_find (mono_get_root_domain (), addr);
1040 if (ji) {
1041 if (out_domain)
1042 *out_domain = mono_get_root_domain ();
1043 return ji;
1047 for (l = t->appdomain_refs; l; l = l->next) {
1048 if (l->data != domain) {
1049 ji = mono_jit_info_table_find ((MonoDomain*)l->data, addr);
1050 if (ji) {
1051 if (out_domain)
1052 *out_domain = (MonoDomain*)l->data;
1053 return ji;
1058 return NULL;
1062 * wrap_non_exception_throws:
1064 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
1065 * WrapNonExceptionThrows flag set.
1067 static gboolean
1068 wrap_non_exception_throws (MonoMethod *m)
1070 MonoAssembly *ass = m->klass->image->assembly;
1071 MonoCustomAttrInfo* attrs;
1072 static MonoClass *klass;
1073 int i;
1074 gboolean val = FALSE;
1076 g_assert (ass);
1077 if (ass->wrap_non_exception_throws_inited)
1078 return ass->wrap_non_exception_throws;
1080 klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1082 attrs = mono_custom_attrs_from_assembly (ass);
1083 if (attrs) {
1084 for (i = 0; i < attrs->num_attrs; ++i) {
1085 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1086 const gchar *p;
1087 int len, num_named, named_type, data_type, name_len;
1088 char *name;
1090 if (!attr->ctor || attr->ctor->klass != klass)
1091 continue;
1092 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
1093 len = attr->data_size;
1094 p = (const char*)attr->data;
1095 g_assert (read16 (p) == 0x0001);
1096 p += 2;
1097 num_named = read16 (p);
1098 if (num_named != 1)
1099 continue;
1100 p += 2;
1101 named_type = *p;
1102 p ++;
1103 data_type = *p;
1104 p ++;
1105 /* Property */
1106 if (named_type != 0x54)
1107 continue;
1108 name_len = mono_metadata_decode_blob_size (p, &p);
1109 name = g_malloc (name_len + 1);
1110 memcpy (name, p, name_len);
1111 name [name_len] = 0;
1112 p += name_len;
1113 g_assert (!strcmp (name, "WrapNonExceptionThrows"));
1114 g_free (name);
1115 /* The value is a BOOLEAN */
1116 val = *p;
1118 mono_custom_attrs_free (attrs);
1121 ass->wrap_non_exception_throws = val;
1122 mono_memory_barrier ();
1123 ass->wrap_non_exception_throws_inited = TRUE;
1125 return val;
1128 #ifndef MONO_ARCH_STACK_GROWS_UP
1129 #define DOES_STACK_GROWS_UP 1
1130 #else
1131 #define DOES_STACK_GROWS_UP 0
1132 #endif
1135 * mono_handle_exception_internal_first_pass:
1137 * The first pass of exception handling. Unwind the stack until a catch clause which can catch
1138 * OBJ is found. Run the index of the filter clause which caught the exception into
1139 * OUT_FILTER_IDX. Return TRUE if the exception is caught, FALSE otherwise.
1141 static gboolean
1142 mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gpointer original_ip, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoObject *non_exception)
1144 MonoDomain *domain = mono_domain_get ();
1145 MonoJitInfo *ji;
1146 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1147 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1148 MonoLMF *lmf = mono_get_lmf ();
1149 MonoArray *initial_trace_ips = NULL;
1150 GList *trace_ips = NULL;
1151 MonoException *mono_ex;
1152 gboolean stack_overflow = FALSE;
1153 MonoContext initial_ctx;
1154 int frame_count = 0;
1155 gboolean has_dynamic_methods = FALSE;
1156 gint32 filter_idx;
1157 int i;
1158 MonoObject *ex_obj;
1160 g_assert (ctx != NULL);
1162 if (obj == domain->stack_overflow_ex)
1163 stack_overflow = TRUE;
1165 mono_ex = (MonoException*)obj;
1166 initial_trace_ips = mono_ex->trace_ips;
1168 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1169 mono_ex = (MonoException*)obj;
1170 initial_trace_ips = mono_ex->trace_ips;
1171 } else {
1172 mono_ex = NULL;
1175 if (!call_filter)
1176 call_filter = mono_get_call_filter ();
1178 g_assert (jit_tls->end_of_stack);
1179 g_assert (jit_tls->abort_func);
1181 if (out_filter_idx)
1182 *out_filter_idx = -1;
1183 if (out_ji)
1184 *out_ji = NULL;
1185 filter_idx = 0;
1186 initial_ctx = *ctx;
1188 while (1) {
1189 MonoContext new_ctx;
1190 guint32 free_stack;
1191 int clause_index_start = 0;
1192 gboolean unwind_res = TRUE;
1194 StackFrameInfo frame;
1196 unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1197 if (unwind_res) {
1198 if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
1199 *ctx = new_ctx;
1200 continue;
1202 g_assert (frame.type == FRAME_TYPE_MANAGED);
1203 ji = frame.ji;
1206 if (!unwind_res) {
1207 if (mono_ex && !initial_trace_ips) {
1208 trace_ips = g_list_reverse (trace_ips);
1209 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1210 if (has_dynamic_methods)
1211 /* These methods could go away anytime, so compute the stack trace now */
1212 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1214 g_list_free (trace_ips);
1215 return FALSE;
1218 frame_count ++;
1219 //printf ("M: %s %d.\n", mono_method_full_name (ji->method, TRUE), frame_count);
1221 if (mini_get_debug_options ()->reverse_pinvoke_exceptions && ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
1222 g_error ("A native frame was found while unwinding the stack after an exception.\n"
1223 "The native frame called the managed method:\n%s\n",
1224 mono_method_full_name (ji->method, TRUE));
1227 if (ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1229 * Avoid overwriting the stack trace if the exception is
1230 * rethrown. Also avoid giant stack traces during a stack
1231 * overflow.
1233 if (!initial_trace_ips && (frame_count < 1000)) {
1234 trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1235 trace_ips = g_list_prepend (trace_ips,
1236 get_generic_info_from_stack_frame (ji, ctx));
1240 if (ji->method->dynamic)
1241 has_dynamic_methods = TRUE;
1243 if (stack_overflow) {
1244 if (DOES_STACK_GROWS_UP)
1245 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1246 else
1247 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1248 } else {
1249 free_stack = 0xffffff;
1252 for (i = clause_index_start; i < ji->num_clauses; i++) {
1253 MonoJitExceptionInfo *ei = &ji->clauses [i];
1254 gboolean filtered = FALSE;
1257 * During stack overflow, wait till the unwinding frees some stack
1258 * space before running handlers/finalizers.
1260 if (free_stack <= (64 * 1024))
1261 continue;
1263 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1264 /* catch block */
1265 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1268 * Have to unwrap RuntimeWrappedExceptions if the
1269 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1271 if (non_exception && !wrap_non_exception_throws (ji->method))
1272 ex_obj = non_exception;
1273 else
1274 ex_obj = obj;
1276 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1277 mono_perfcounters->exceptions_filters++;
1278 mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1279 if (mono_ex && !initial_trace_ips) {
1280 trace_ips = g_list_reverse (trace_ips);
1281 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1283 if (has_dynamic_methods)
1284 /* These methods could go away anytime, so compute the stack trace now */
1285 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1287 g_list_free (trace_ips);
1288 trace_ips = NULL;
1290 if (ji->from_llvm) {
1291 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1292 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1293 #else
1294 g_assert_not_reached ();
1295 #endif
1296 } else {
1297 /* store the exception object in bp + ei->exvar_offset */
1298 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1301 mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx);
1302 filtered = call_filter (ctx, ei->data.filter);
1303 mono_debugger_agent_end_exception_filter (mono_ex, ctx, &initial_ctx);
1304 if (filtered && out_filter_idx)
1305 *out_filter_idx = filter_idx;
1306 if (out_ji)
1307 *out_ji = ji;
1308 filter_idx ++;
1310 if (filtered) {
1311 /* mono_debugger_agent_handle_exception () needs this */
1312 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1313 return TRUE;
1317 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (ex_obj, catch_class)) {
1318 if (mono_ex && !initial_trace_ips) {
1319 trace_ips = g_list_reverse (trace_ips);
1320 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1321 if (has_dynamic_methods)
1322 /* These methods could go away anytime, so compute the stack trace now */
1323 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1325 g_list_free (trace_ips);
1327 /* mono_debugger_agent_handle_exception () needs this */
1328 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1329 return TRUE;
1334 *ctx = new_ctx;
1337 g_assert_not_reached ();
1341 * mono_handle_exception_internal:
1342 * @ctx: saved processor state
1343 * @obj: the exception object
1344 * @resume: whenever to resume unwinding based on the state in MonoJitTlsData.
1346 static gboolean
1347 mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean resume, MonoJitInfo **out_ji)
1349 MonoDomain *domain = mono_domain_get ();
1350 MonoJitInfo *ji;
1351 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1352 static void (*restore_context) (void *);
1353 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1354 MonoLMF *lmf = mono_get_lmf ();
1355 MonoException *mono_ex;
1356 gboolean stack_overflow = FALSE;
1357 MonoContext initial_ctx;
1358 int frame_count = 0;
1359 gint32 filter_idx, first_filter_idx;
1360 int i;
1361 MonoObject *ex_obj;
1362 MonoObject *non_exception = NULL;
1364 g_assert (ctx != NULL);
1365 if (!obj) {
1366 MonoException *ex = mono_get_exception_null_reference ();
1367 MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object"));
1368 obj = (MonoObject *)ex;
1372 * Allocate a new exception object instead of the preconstructed ones.
1374 if (obj == domain->stack_overflow_ex) {
1376 * It is not a good idea to try and put even more pressure on the little stack available.
1377 * obj = mono_get_exception_stack_overflow ();
1379 stack_overflow = TRUE;
1381 else if (obj == domain->null_reference_ex) {
1382 obj = mono_get_exception_null_reference ();
1385 if (!mono_object_isinst (obj, mono_defaults.exception_class)) {
1386 non_exception = obj;
1387 obj = mono_get_exception_runtime_wrapped (obj);
1390 mono_ex = (MonoException*)obj;
1392 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1393 mono_ex = (MonoException*)obj;
1394 } else {
1395 mono_ex = NULL;
1398 if (mono_ex && jit_tls->class_cast_from) {
1399 if (!strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) {
1400 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1401 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1402 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
1403 mono_ex->message = mono_string_new (domain, msg);
1404 g_free (from_name);
1405 g_free (to_name);
1406 g_free (msg);
1408 if (!strcmp (mono_ex->object.vtable->klass->name, "ArrayTypeMismatchException")) {
1409 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1410 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1411 char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
1412 mono_ex->message = mono_string_new (domain, msg);
1413 g_free (from_name);
1414 g_free (to_name);
1415 g_free (msg);
1419 if (!call_filter)
1420 call_filter = mono_get_call_filter ();
1422 if (!restore_context)
1423 restore_context = mono_get_restore_context ();
1425 g_assert (jit_tls->end_of_stack);
1426 g_assert (jit_tls->abort_func);
1429 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
1430 * end up being TRUE on any code path.
1432 memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
1434 if (!resume) {
1435 gboolean res;
1437 MonoContext ctx_cp = *ctx;
1438 if (mono_trace_is_enabled ()) {
1439 MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0);
1440 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message);
1441 MonoObject *message;
1442 const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
1443 char *msg = NULL;
1444 MonoObject *exc = NULL;
1445 if (get_message == NULL) {
1446 message = NULL;
1447 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
1448 message = NULL;
1449 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
1450 } else {
1451 message = mono_runtime_invoke (get_message, obj, NULL, &exc);
1454 if (msg == NULL) {
1455 msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
1457 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
1458 g_free (msg);
1459 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
1460 mono_print_thread_dump_from_ctx (ctx);
1462 jit_tls->orig_ex_ctx_set = TRUE;
1463 mono_profiler_exception_thrown (obj);
1464 jit_tls->orig_ex_ctx_set = FALSE;
1466 res = mono_handle_exception_internal_first_pass (&ctx_cp, obj, original_ip, &first_filter_idx, out_ji, non_exception);
1468 if (!res) {
1469 if (mono_break_on_exc)
1470 G_BREAKPOINT ();
1471 mono_debugger_agent_handle_exception (obj, ctx, NULL);
1472 // FIXME: This runs managed code so it might cause another stack overflow when
1473 // we are handling a stack overflow
1474 mono_unhandled_exception (obj);
1475 } else {
1476 mono_debugger_agent_handle_exception (obj, ctx, &ctx_cp);
1480 if (out_ji)
1481 *out_ji = NULL;
1482 filter_idx = 0;
1483 initial_ctx = *ctx;
1485 while (1) {
1486 MonoContext new_ctx;
1487 guint32 free_stack;
1488 int clause_index_start = 0;
1489 gboolean unwind_res = TRUE;
1491 if (resume) {
1492 resume = FALSE;
1493 ji = jit_tls->resume_state.ji;
1494 new_ctx = jit_tls->resume_state.new_ctx;
1495 clause_index_start = jit_tls->resume_state.clause_index;
1496 lmf = jit_tls->resume_state.lmf;
1497 first_filter_idx = jit_tls->resume_state.first_filter_idx;
1498 filter_idx = jit_tls->resume_state.filter_idx;
1499 } else {
1500 StackFrameInfo frame;
1502 unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1503 if (unwind_res) {
1504 if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
1505 *ctx = new_ctx;
1506 continue;
1508 g_assert (frame.type == FRAME_TYPE_MANAGED);
1509 ji = frame.ji;
1513 if (!unwind_res) {
1514 *(mono_get_lmf_addr ()) = lmf;
1516 jit_tls->abort_func (obj);
1517 g_assert_not_reached ();
1520 frame_count ++;
1521 //printf ("M: %s %d.\n", mono_method_full_name (ji->method, TRUE), frame_count);
1523 if (stack_overflow) {
1524 if (DOES_STACK_GROWS_UP)
1525 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1526 else
1527 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1528 } else {
1529 free_stack = 0xffffff;
1532 for (i = clause_index_start; i < ji->num_clauses; i++) {
1533 MonoJitExceptionInfo *ei = &ji->clauses [i];
1534 gboolean filtered = FALSE;
1537 * During stack overflow, wait till the unwinding frees some stack
1538 * space before running handlers/finalizers.
1540 if (free_stack <= (64 * 1024))
1541 continue;
1543 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1544 /* catch block */
1545 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1548 * Have to unwrap RuntimeWrappedExceptions if the
1549 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1551 if (non_exception && !wrap_non_exception_throws (ji->method))
1552 ex_obj = non_exception;
1553 else
1554 ex_obj = obj;
1556 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
1557 if (ji->from_llvm) {
1558 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1559 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1560 #else
1561 g_assert_not_reached ();
1562 #endif
1563 } else {
1564 /* store the exception object in bp + ei->exvar_offset */
1565 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1569 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1571 * Filter clauses should only be run in the
1572 * first pass of exception handling.
1574 filtered = (filter_idx == first_filter_idx);
1575 filter_idx ++;
1578 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
1579 mono_object_isinst (ex_obj, catch_class)) || filtered) {
1581 * This guards against the situation that we abort a thread that is executing a finally clause
1582 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
1583 * check for this situation here and resume interruption if we are below the guarded block.
1585 if (G_UNLIKELY (jit_tls->handler_block_return_address)) {
1586 gboolean is_outside = FALSE;
1587 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
1588 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
1589 //FIXME make this stack direction aware
1590 if (catch_bp > prot_bp) {
1591 is_outside = TRUE;
1592 } else if (catch_bp == prot_bp) {
1593 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
1594 * So we check if the catch handler_start is protected by the guarded handler protected region
1596 * Assumptions:
1597 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
1598 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
1599 * There aren't any further finally/fault handler blocks down the stack over this exception.
1600 * This must be ensured by the code that installs the guard trampoline.
1602 g_assert (ji == mini_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
1604 if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
1605 is_outside = TRUE;
1608 if (is_outside) {
1609 jit_tls->handler_block_return_address = NULL;
1610 jit_tls->handler_block = NULL;
1611 mono_thread_resume_interruption (); /*We ignore the exception here, it will be raised later*/
1615 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1616 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1617 jit_tls->orig_ex_ctx_set = TRUE;
1618 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1619 jit_tls->orig_ex_ctx_set = FALSE;
1620 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1621 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1622 *(mono_get_lmf_addr ()) = lmf;
1623 mono_perfcounters->exceptions_depth += frame_count;
1624 if (obj == domain->stack_overflow_ex)
1625 jit_tls->handling_stack_ovf = FALSE;
1627 return 0;
1629 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1630 (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
1631 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1632 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1633 jit_tls->orig_ex_ctx_set = TRUE;
1634 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1635 jit_tls->orig_ex_ctx_set = FALSE;
1636 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1637 call_filter (ctx, ei->handler_start);
1639 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1640 (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
1641 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1642 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1643 jit_tls->orig_ex_ctx_set = TRUE;
1644 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1645 jit_tls->orig_ex_ctx_set = FALSE;
1646 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1647 mono_perfcounters->exceptions_finallys++;
1648 *(mono_get_lmf_addr ()) = lmf;
1649 if (ji->from_llvm) {
1651 * LLVM compiled finally handlers follow the design
1652 * of the c++ ehabi, i.e. they call a resume function
1653 * at the end instead of returning to the caller.
1654 * So save the exception handling state,
1655 * mono_resume_unwind () will call us again to continue
1656 * the unwinding.
1658 jit_tls->resume_state.ex_obj = obj;
1659 jit_tls->resume_state.ji = ji;
1660 jit_tls->resume_state.clause_index = i + 1;
1661 jit_tls->resume_state.ctx = *ctx;
1662 jit_tls->resume_state.new_ctx = new_ctx;
1663 jit_tls->resume_state.lmf = lmf;
1664 jit_tls->resume_state.first_filter_idx = first_filter_idx;
1665 jit_tls->resume_state.filter_idx = filter_idx;
1666 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1667 return 0;
1668 } else {
1669 call_filter (ctx, ei->handler_start);
1675 jit_tls->orig_ex_ctx_set = TRUE;
1676 mono_profiler_exception_method_leave (ji->method);
1677 jit_tls->orig_ex_ctx_set = FALSE;
1679 *ctx = new_ctx;
1682 g_assert_not_reached ();
1686 * mono_debugger_handle_exception:
1688 * Notify the debugger about exceptions. Returns TRUE if the debugger wants us to stop
1689 * at the exception and FALSE to resume with the normal exception handling.
1691 * The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
1692 * MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
1693 * `callq throw' instruction.
1695 gboolean
1696 mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
1698 MonoDebuggerExceptionAction action;
1700 if (!mono_debug_using_mono_debugger ())
1701 return FALSE;
1703 if (!obj) {
1704 MonoException *ex = mono_get_exception_null_reference ();
1705 MONO_OBJECT_SETREF (ex, message, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
1706 obj = (MonoObject *)ex;
1709 action = _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1711 if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP) {
1713 * The debugger wants us to stop on the `throw' instruction.
1714 * By the time we get here, it already inserted a breakpoint there.
1716 return TRUE;
1717 } else if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED) {
1718 MonoContext ctx_cp = *ctx;
1719 MonoJitInfo *ji = NULL;
1720 gboolean ret;
1723 * The debugger wants us to stop only if this exception is user-unhandled.
1726 ret = mono_handle_exception_internal_first_pass (&ctx_cp, obj, MONO_CONTEXT_GET_IP (ctx), NULL, &ji, NULL);
1727 if (ret && (ji != NULL) && (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
1729 * The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
1730 * inside the method being invoked, so we handle it like a user-unhandled exception.
1732 ret = FALSE;
1735 if (!ret) {
1737 * The exception is user-unhandled - tell the debugger to stop.
1739 return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1743 * The exception is catched somewhere - resume with the normal exception handling and don't
1744 * stop in the debugger.
1748 return FALSE;
1752 * mono_debugger_run_finally:
1753 * @start_ctx: saved processor state
1755 * This method is called by the Mono Debugger to call all `finally' clauses of the
1756 * current stack frame. It's used when the user issues a `return' command to make
1757 * the current stack frame return. After returning from this method, the debugger
1758 * unwinds the stack one frame and gives control back to the user.
1760 * NOTE: This method is only used when running inside the Mono Debugger.
1762 void
1763 mono_debugger_run_finally (MonoContext *start_ctx)
1765 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1766 MonoDomain *domain = mono_domain_get ();
1767 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1768 MonoLMF *lmf = mono_get_lmf ();
1769 MonoContext ctx, new_ctx;
1770 MonoJitInfo *ji, rji;
1771 int i;
1773 ctx = *start_ctx;
1775 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1776 if (!ji || ji == (gpointer)-1)
1777 return;
1779 if (!call_filter)
1780 call_filter = mono_get_call_filter ();
1782 for (i = 0; i < ji->num_clauses; i++) {
1783 MonoJitExceptionInfo *ei = &ji->clauses [i];
1785 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
1786 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1787 call_filter (&ctx, ei->handler_start);
1793 * mono_handle_exception:
1794 * @ctx: saved processor state
1795 * @obj: the exception object
1796 * @test_only: only test if the exception is caught, but dont call handlers
1798 gboolean
1799 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
1801 if (!test_only)
1802 mono_perfcounters->exceptions_thrown++;
1804 g_assert (!test_only);
1805 return mono_handle_exception_internal (ctx, obj, original_ip, FALSE, NULL);
1808 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1810 #ifndef MONO_ARCH_USE_SIGACTION
1811 #error "Can't use sigaltstack without sigaction"
1812 #endif
1814 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1816 void
1817 mono_setup_altstack (MonoJitTlsData *tls)
1819 size_t stsize = 0;
1820 struct sigaltstack sa;
1821 guint8 *staddr = NULL;
1823 if (mono_running_on_valgrind ())
1824 return;
1826 mono_thread_get_stack_bounds (&staddr, &stsize);
1828 g_assert (staddr);
1830 tls->end_of_stack = staddr + stsize;
1831 tls->stack_size = stsize;
1833 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1835 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1836 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
1838 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
1840 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1841 /* mprotect can fail for the main thread stack */
1842 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);
1843 g_assert (gaddr == tls->stack_ovf_guard_base);
1844 tls->stack_ovf_valloced = TRUE;
1847 /* Setup an alternate signal stack */
1848 tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
1849 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1851 g_assert (tls->signal_stack);
1853 sa.ss_sp = tls->signal_stack;
1854 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1855 sa.ss_flags = SS_ONSTACK;
1856 sigaltstack (&sa, NULL);
1859 void
1860 mono_free_altstack (MonoJitTlsData *tls)
1862 struct sigaltstack sa;
1863 int err;
1865 sa.ss_sp = tls->signal_stack;
1866 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1867 sa.ss_flags = SS_DISABLE;
1868 err = sigaltstack (&sa, NULL);
1869 g_assert (err == 0);
1871 if (tls->signal_stack)
1872 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1873 if (tls->stack_ovf_valloced)
1874 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size);
1875 else
1876 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1879 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1881 void
1882 mono_setup_altstack (MonoJitTlsData *tls)
1886 void
1887 mono_free_altstack (MonoJitTlsData *tls)
1891 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1893 static gboolean
1894 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
1896 gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
1897 /* we need to leave some room for throwing the exception */
1898 while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
1899 unprotect_size -= mono_pagesize ();
1900 /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1901 * is sufficient stack
1903 //fprintf (stderr, "restoring stack protection: %p-%p (%d)\n", jit_tls->stack_ovf_guard_base, (char*)jit_tls->stack_ovf_guard_base + unprotect_size, unprotect_size);
1904 if (unprotect_size)
1905 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
1906 return unprotect_size == jit_tls->stack_ovf_guard_size;
1909 static void
1910 try_more_restore (void)
1912 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1913 if (try_restore_stack_protection (jit_tls, 500))
1914 jit_tls->restore_stack_prot = NULL;
1917 static void
1918 restore_stack_protection (void)
1920 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1921 MonoException *ex = mono_domain_get ()->stack_overflow_ex;
1922 /* if we can't restore the stack protection, keep a callback installed so
1923 * we'll try to restore as much stack as we can at each return from unmanaged
1924 * code.
1926 if (try_restore_stack_protection (jit_tls, 4096))
1927 jit_tls->restore_stack_prot = NULL;
1928 else
1929 jit_tls->restore_stack_prot = try_more_restore_tramp;
1930 /* here we also throw a stack overflow exception */
1931 ex->trace_ips = NULL;
1932 ex->stack_trace = NULL;
1933 mono_raise_exception (ex);
1936 gpointer
1937 mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
1939 void (*func)(void) = (gpointer)tramp_data;
1940 func ();
1941 return NULL;
1944 gboolean
1945 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
1947 /* we got a stack overflow in the soft-guard pages
1948 * There are two cases:
1949 * 1) managed code caused the overflow: we unprotect the soft-guard page
1950 * and let the arch-specific code trigger the exception handling mechanism
1951 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1952 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1953 * and hope we can continue with those enabled, at least until the hard-guard page
1954 * is hit. The alternative to continuing here is to just print a message and abort.
1955 * We may add in the future the code to protect the pages again in the codepath
1956 * when we return from unmanaged to managed code.
1958 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
1959 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
1960 /* we unprotect the minimum amount we can */
1961 guint32 guard_size;
1962 gboolean handled = FALSE;
1964 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
1965 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
1966 guard_size -= mono_pagesize ();
1968 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
1969 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
1970 mono_mprotect ((char*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size - guard_size, guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1971 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1972 if (ji) {
1973 mono_arch_handle_altstack_exception (ctx, fault_addr, TRUE);
1974 handled = TRUE;
1976 #endif
1977 if (!handled) {
1978 /* We print a message: after this even managed stack overflows
1979 * may crash the runtime
1981 fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), fault_addr);
1982 if (!jit_tls->handling_stack_ovf) {
1983 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
1984 jit_tls->handling_stack_ovf = 1;
1985 } else {
1986 /*fprintf (stderr, "Already handling stack overflow\n");*/
1989 return TRUE;
1991 return FALSE;
1994 static gboolean
1995 print_stack_frame (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed, gpointer data)
1997 FILE *stream = (FILE*)data;
1999 if (method) {
2000 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
2001 fprintf (stream, " %s\n", location);
2002 g_free (location);
2003 } else
2004 fprintf (stream, " at <unknown> <0x%05x>\n", native_offset);
2006 return FALSE;
2009 static G_GNUC_UNUSED gboolean
2010 print_stack_frame_to_string (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed,
2011 gpointer data)
2013 GString *p = (GString*)data;
2015 if (method) {
2016 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
2017 g_string_append_printf (p, " %s\n", location);
2018 g_free (location);
2019 } else
2020 g_string_append_printf (p, " at <unknown> <0x%05x>\n", native_offset);
2022 return FALSE;
2025 static gboolean handling_sigsegv = FALSE;
2028 * mono_handle_native_sigsegv:
2030 * Handle a SIGSEGV received while in native code by printing diagnostic
2031 * information and aborting.
2033 void
2034 mono_handle_native_sigsegv (int signal, void *ctx)
2036 #ifdef MONO_ARCH_USE_SIGACTION
2037 struct sigaction sa;
2038 #endif
2039 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2041 if (handling_sigsegv)
2042 return;
2044 if (mini_get_debug_options ()->suspend_on_sigsegv) {
2045 fprintf (stderr, "Received SIGSEGV, suspending...");
2046 while (1)
2050 /* To prevent infinite loops when the stack walk causes a crash */
2051 handling_sigsegv = TRUE;
2053 /* !jit_tls means the thread was not registered with the runtime */
2054 if (jit_tls && mono_thread_internal_current ()) {
2055 fprintf (stderr, "Stacktrace:\n\n");
2057 mono_jit_walk_stack (print_stack_frame, TRUE, stderr);
2059 fflush (stderr);
2062 #ifdef HAVE_BACKTRACE_SYMBOLS
2064 void *array [256];
2065 char **names;
2066 int i, size;
2067 const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
2069 fprintf (stderr, "\nNative stacktrace:\n\n");
2071 size = backtrace (array, 256);
2072 names = backtrace_symbols (array, size);
2073 for (i =0; i < size; ++i) {
2074 fprintf (stderr, "\t%s\n", names [i]);
2076 free (names);
2078 fflush (stderr);
2080 /* Try to get more meaningful information using gdb */
2082 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
2083 if (!mini_get_debug_options ()->no_gdb_backtrace && !mono_debug_using_mono_debugger ()) {
2084 /* From g_spawn_command_line_sync () in eglib */
2085 int res;
2086 int stdout_pipe [2] = { -1, -1 };
2087 pid_t pid;
2088 int status;
2089 char buffer [1024];
2091 res = pipe (stdout_pipe);
2092 g_assert (res != -1);
2094 //pid = fork ();
2096 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
2097 * it will deadlock. Call the syscall directly instead.
2099 pid = mono_runtime_syscall_fork ();
2101 if (pid == 0) {
2102 close (stdout_pipe [0]);
2103 dup2 (stdout_pipe [1], STDOUT_FILENO);
2105 for (i = getdtablesize () - 1; i >= 3; i--)
2106 close (i);
2108 if (!mono_gdb_render_native_backtraces ())
2109 close (STDOUT_FILENO);
2111 exit (1);
2114 close (stdout_pipe [1]);
2116 fprintf (stderr, "\nDebug info from gdb:\n\n");
2118 while (1) {
2119 int nread = read (stdout_pipe [0], buffer, 1024);
2121 if (nread <= 0)
2122 break;
2123 write (STDERR_FILENO, buffer, nread);
2126 waitpid (pid, &status, WNOHANG);
2128 #endif
2130 * A SIGSEGV indicates something went very wrong so we can no longer depend
2131 * on anything working. So try to print out lots of diagnostics, starting
2132 * with ones which have a greater chance of working.
2134 fprintf (stderr,
2135 "\n"
2136 "=================================================================\n"
2137 "Got a %s while executing native code. This usually indicates\n"
2138 "a fatal error in the mono runtime or one of the native libraries \n"
2139 "used by your application.\n"
2140 "=================================================================\n"
2141 "\n", signal_str);
2144 #endif
2146 #ifdef MONO_ARCH_USE_SIGACTION
2148 /* Remove our SIGABRT handler */
2149 sa.sa_handler = SIG_DFL;
2150 sigemptyset (&sa.sa_mask);
2151 sa.sa_flags = 0;
2153 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
2155 #endif
2157 abort ();
2160 static void
2161 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
2163 MonoInternalThread *thread = mono_thread_internal_current ();
2164 #if defined(__i386__) || defined(__x86_64__)
2165 MonoContext ctx;
2166 #endif
2167 GString* text = g_string_new (0);
2168 char *name, *wapi_desc;
2169 GError *error = NULL;
2171 if (thread->name) {
2172 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
2173 g_assert (!error);
2174 g_string_append_printf (text, "\n\"%s\"", name);
2175 g_free (name);
2177 else if (thread->threadpool_thread)
2178 g_string_append (text, "\n\"<threadpool thread>\"");
2179 else
2180 g_string_append (text, "\n\"<unnamed thread>\"");
2182 #ifndef HOST_WIN32
2183 wapi_desc = wapi_current_thread_desc ();
2184 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
2185 free (wapi_desc);
2186 #endif
2188 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2189 if (start_ctx) {
2190 memcpy (&ctx, start_ctx, sizeof (MonoContext));
2191 } else if (!sigctx)
2192 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
2193 else
2194 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
2196 mono_jit_walk_stack_from_ctx (print_stack_frame_to_string, &ctx, TRUE, text);
2197 #else
2198 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
2199 #endif
2201 fprintf (stdout, "%s", text->str);
2202 g_string_free (text, TRUE);
2203 fflush (stdout);
2207 * mono_print_thread_dump:
2209 * Print information about the current thread to stdout.
2210 * SIGCTX can be NULL, allowing this to be called from gdb.
2212 void
2213 mono_print_thread_dump (void *sigctx)
2215 mono_print_thread_dump_internal (sigctx, NULL);
2218 void
2219 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2221 mono_print_thread_dump_internal (NULL, ctx);
2225 * mono_resume_unwind:
2227 * This is called by a trampoline from LLVM compiled finally clauses to continue
2228 * unwinding.
2230 void
2231 mono_resume_unwind (MonoContext *ctx)
2233 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2234 static void (*restore_context) (MonoContext *);
2235 MonoContext new_ctx;
2237 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
2238 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
2239 new_ctx = *ctx;
2241 mono_handle_exception_internal (&new_ctx, jit_tls->resume_state.ex_obj, NULL, TRUE, NULL);
2243 if (!restore_context)
2244 restore_context = mono_get_restore_context ();
2246 restore_context (&new_ctx);
2249 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
2251 typedef struct {
2252 MonoJitInfo *ji;
2253 MonoContext ctx;
2254 MonoJitExceptionInfo *ei;
2255 } FindHandlerBlockData;
2257 static gboolean
2258 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2260 int i;
2261 gpointer ip;
2262 FindHandlerBlockData *pdata = data;
2263 MonoJitInfo *ji = frame->ji;
2265 if (!ji)
2266 return FALSE;
2268 if (ji->method->wrapper_type)
2269 return FALSE;
2271 ip = MONO_CONTEXT_GET_IP (ctx);
2273 for (i = 0; i < ji->num_clauses; ++i) {
2274 MonoJitExceptionInfo *ei = ji->clauses + i;
2275 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2276 continue;
2277 /*If ip points to the first instruction it means the handler block didn't start
2278 so we can leave its execution to the EH machinery*/
2279 if (ei->handler_start < ip && ip < ei->data.handler_end) {
2280 pdata->ji = ji;
2281 pdata->ei = ei;
2282 pdata->ctx = *ctx;
2283 break;
2286 return FALSE;
2290 static gpointer
2291 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
2293 int i;
2294 MonoJitExceptionInfo *clause = NULL;
2295 gpointer ip;
2297 ip = MONO_CONTEXT_GET_IP (ctx);
2299 for (i = 0; i < ji->num_clauses; ++i) {
2300 clause = &ji->clauses [i];
2301 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2302 continue;
2303 if (clause->handler_start < ip && clause->data.handler_end > ip)
2304 break;
2307 /*no matching finally */
2308 if (i == ji->num_clauses)
2309 return NULL;
2311 /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
2312 if (ip == clause->handler_start)
2313 return NULL;
2315 return mono_arch_install_handler_block_guard (ji, clause, ctx, mono_create_handler_block_trampoline ());
2319 * Finds the bottom handler block running and install a block guard if needed.
2321 gboolean
2322 mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx)
2324 FindHandlerBlockData data = { 0 };
2325 MonoDomain *domain = mono_domain_get ();
2326 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2327 gpointer resume_ip;
2329 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
2330 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
2332 if (!jit_tls || jit_tls->handler_block_return_address)
2333 return FALSE;
2335 mono_walk_stack (find_last_handler_block, domain, ctx, FALSE, NULL, NULL, &data);
2337 if (!data.ji)
2338 return FALSE;
2340 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
2342 resume_ip = install_handler_block_guard (data.ji, &data.ctx);
2343 if (resume_ip == NULL)
2344 return FALSE;
2346 jit_tls->handler_block_return_address = resume_ip;
2347 jit_tls->handler_block = data.ei;
2349 #ifndef HOST_WIN32
2350 /*Clear current thread from been wapi interrupted otherwise things can go south*/
2351 wapi_clear_interruption ();
2352 #endif
2353 return TRUE;
2356 #else
2357 gboolean
2358 mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx)
2360 return FALSE;
2363 #endif