2 * mini-exceptions.c: generic exception support
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.
17 #ifdef HAVE_EXECINFO_H
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
25 #ifdef HAVE_SYS_WAIT_H
33 #ifdef HAVE_SYS_SYSCALL_H
34 #include <sys/syscall.h>
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/utils/mono-mmap.h>
49 #include "debug-mini.h"
51 #include "debugger-agent.h"
53 #ifndef MONO_ARCH_CONTEXT_DEF
54 #define MONO_ARCH_CONTEXT_DEF
57 static gpointer restore_context_func
, call_filter_func
;
58 static gpointer throw_exception_func
, rethrow_exception_func
;
59 static gpointer throw_exception_by_name_func
, throw_corlib_exception_func
;
61 static gpointer try_more_restore_tramp
= NULL
;
62 static gpointer restore_stack_protection_tramp
= NULL
;
64 static void try_more_restore (void);
65 static void restore_stack_protection (void);
68 mono_exceptions_init (void)
70 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
75 restore_context_func
= mono_aot_get_named_code ("restore_context");
76 call_filter_func
= mono_aot_get_named_code ("call_filter");
77 throw_exception_func
= mono_aot_get_named_code ("throw_exception");
78 rethrow_exception_func
= mono_aot_get_named_code ("rethrow_exception");
80 restore_context_func
= mono_arch_get_restore_context_full (&code_size
, &ji
, FALSE
);
81 call_filter_func
= mono_arch_get_call_filter_full (&code_size
, &ji
, FALSE
);
82 throw_exception_func
= mono_arch_get_throw_exception_full (&code_size
, &ji
, FALSE
);
83 rethrow_exception_func
= mono_arch_get_rethrow_exception_full (&code_size
, &ji
, FALSE
);
86 restore_context_func
= mono_arch_get_restore_context ();
87 call_filter_func
= mono_arch_get_call_filter ();
88 throw_exception_func
= mono_arch_get_throw_exception ();
89 rethrow_exception_func
= mono_arch_get_rethrow_exception ();
91 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
92 try_more_restore_tramp
= mono_create_specific_trampoline (try_more_restore
, MONO_TRAMPOLINE_RESTORE_STACK_PROT
, mono_domain_get (), NULL
);
93 restore_stack_protection_tramp
= mono_create_specific_trampoline (restore_stack_protection
, MONO_TRAMPOLINE_RESTORE_STACK_PROT
, mono_domain_get (), NULL
);
96 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
97 mono_arch_exceptions_init ();
102 mono_get_throw_exception (void)
104 g_assert (throw_exception_func
);
105 return throw_exception_func
;
109 mono_get_rethrow_exception (void)
111 g_assert (rethrow_exception_func
);
112 return rethrow_exception_func
;
116 mono_get_call_filter (void)
118 g_assert (call_filter_func
);
119 return call_filter_func
;
123 mono_get_restore_context (void)
125 g_assert (restore_context_func
);
126 return restore_context_func
;
130 mono_get_throw_exception_by_name (void)
132 #ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME
134 gpointer code
= NULL
;
135 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
140 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
141 if (throw_exception_by_name_func
)
142 return throw_exception_by_name_func
;
144 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
146 code
= mono_aot_get_named_code ("throw_exception_by_name");
148 code
= mono_arch_get_throw_exception_by_name_full (&code_size
, &ji
, FALSE
);
150 code
= mono_arch_get_throw_exception_by_name ();
153 mono_memory_barrier ();
155 throw_exception_by_name_func
= code
;
159 throw_exception_by_name_func
= NULL
;
161 g_assert_not_reached ();
164 return throw_exception_by_name_func
;
168 mono_get_throw_corlib_exception (void)
170 gpointer code
= NULL
;
171 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
176 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
177 if (throw_corlib_exception_func
)
178 return throw_corlib_exception_func
;
180 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
181 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
183 code
= mono_aot_get_named_code ("throw_corlib_exception");
185 code
= mono_arch_get_throw_corlib_exception_full (&code_size
, &ji
, FALSE
);
187 code
= mono_arch_get_throw_corlib_exception ();
190 g_assert_not_reached ();
193 mono_memory_barrier ();
195 throw_corlib_exception_func
= code
;
197 return throw_corlib_exception_func
;
201 is_address_protected (MonoJitInfo
*ji
, MonoJitExceptionInfo
*ei
, gpointer ip
)
203 MonoTryBlockHoleTableJitInfo
*table
;
208 /*FIXME check if under s390 it should be ei->try_start >= ip*/
209 if (ei
->try_start
> ip
|| ip
>= ei
->try_end
)
212 if (!ji
->has_try_block_holes
)
215 table
= mono_jit_info_get_try_block_hole_table_info (ji
);
216 offset
= (guint32
)((char*)ip
- (char*)ji
->code_start
);
217 clause
= (guint16
)(ei
- ji
->clauses
);
218 g_assert (clause
< ji
->num_clauses
);
220 for (i
= 0; i
< table
->num_holes
; ++i
) {
221 MonoTryBlockHoleJitInfo
*hole
= &table
->holes
[i
];
222 if (hole
->clause
== clause
&& hole
->offset
<= offset
&& hole
->offset
+ hole
->length
> offset
)
228 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
231 * find_jit_info_no_ext:
233 * If the target has the find_jit_info_ext version of this function, define the old
234 * version here which translates between the old and new APIs.
237 find_jit_info_no_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
238 MonoContext
*new_ctx
, MonoLMF
**lmf
, gboolean
*managed
)
240 StackFrameInfo frame
;
243 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
245 /* Avoid costly table lookup during stack overflow */
246 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
249 ji
= mini_jit_info_table_find (domain
, ip
, NULL
);
254 err
= mono_arch_find_jit_info_ext (domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, &frame
);
258 /* Convert between the new and the old APIs */
259 switch (frame
.type
) {
260 case FRAME_TYPE_MANAGED
:
264 case FRAME_TYPE_MANAGED_TO_NATIVE
:
268 memset (res
, 0, sizeof (MonoJitInfo
));
269 res
->method
= frame
.method
;
272 case FRAME_TYPE_DEBUGGER_INVOKE
: {
276 * The normal exception handling code can't handle this frame, so just
279 ji
= find_jit_info_no_ext (domain
, jit_tls
, res
, NULL
, new_ctx
, &tmp_ctx
, lmf
, managed
);
280 memcpy (new_ctx
, &tmp_ctx
, sizeof (MonoContext
));
284 g_assert_not_reached ();
291 /* mono_find_jit_info:
293 * This function is used to gather information from @ctx. It return the
294 * MonoJitInfo of the corresponding function, unwinds one stack frame and
295 * stores the resulting context into @new_ctx. It also stores a string
296 * describing the stack location into @trace (if not NULL), and modifies
297 * the @lmf if necessary. @native_offset return the IP offset from the
298 * start of the function or -1 if that info is not available.
301 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
302 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
306 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
318 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
319 ji
= find_jit_info_no_ext (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
321 ji
= mono_arch_find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
324 if (ji
== (gpointer
)-1)
327 if (managed2
|| (ji
&& ji
->method
->wrapper_type
)) {
328 const char *real_ip
, *start
;
331 start
= (const char *)ji
->code_start
;
333 /* ctx->ip points into native code */
334 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
336 real_ip
= (const char*)ip
;
338 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
339 offset
= real_ip
- start
;
344 *native_offset
= offset
;
347 if (!ji
->method
->wrapper_type
)
351 *trace
= mono_debug_print_stack_frame (ji
->method
, offset
, domain
);
354 char *fname
= mono_method_full_name (res
->method
, TRUE
);
355 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
363 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
366 * mono_find_jit_info_ext:
368 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
372 mono_find_jit_info_ext (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
373 MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
374 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
,
375 StackFrameInfo
*frame
)
378 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
380 MonoDomain
*target_domain
;
385 /* Avoid costly table lookup during stack overflow */
386 if (prev_ji
&& (ip
> prev_ji
->code_start
&& ((guint8
*)ip
< ((guint8
*)prev_ji
->code_start
) + prev_ji
->code_size
)))
389 ji
= mini_jit_info_table_find (domain
, ip
, &target_domain
);
392 target_domain
= domain
;
394 err
= mono_arch_find_jit_info_ext (target_domain
, jit_tls
, ji
, ctx
, new_ctx
, lmf
, frame
);
398 frame
->native_offset
= -1;
399 frame
->domain
= target_domain
;
403 if (ji
&& (frame
->managed
|| ji
->method
->wrapper_type
)) {
404 const char *real_ip
, *start
;
406 start
= (const char *)ji
->code_start
;
408 /* ctx->ip points into native code */
409 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
411 real_ip
= (const char*)ip
;
413 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
414 frame
->native_offset
= real_ip
- start
;
416 frame
->native_offset
= -1;
419 *trace
= mono_debug_print_stack_frame (ji
->method
, frame
->native_offset
, domain
);
421 if (trace
&& frame
->method
) {
422 char *fname
= mono_method_full_name (frame
->method
, TRUE
);
423 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
431 #endif /* MONO_ARCH_HAVE_FIND_JIT_INFO_EXT */
434 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
436 MonoGenericJitInfo
*gi
;
439 if (!ji
->has_generic_jit_info
)
441 gi
= mono_jit_info_get_generic_jit_info (ji
);
446 info
= mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
448 info
= *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
450 if (mono_method_get_context (ji
->method
)->method_inst
) {
452 } else if ((ji
->method
->flags
& METHOD_ATTRIBUTE_STATIC
) || ji
->method
->klass
->valuetype
) {
455 /* Avoid returning a managed object */
456 MonoObject
*this_obj
= info
;
458 return this_obj
->vtable
->klass
;
462 static MonoGenericContext
463 get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
465 MonoGenericContext context
= { NULL
, NULL
};
466 MonoClass
*class, *method_container_class
;
468 g_assert (generic_info
);
470 g_assert (ji
->method
->is_inflated
);
471 if (mono_method_get_context (ji
->method
)->method_inst
) {
472 MonoMethodRuntimeGenericContext
*mrgctx
= generic_info
;
474 class = mrgctx
->class_vtable
->klass
;
475 context
.method_inst
= mrgctx
->method_inst
;
476 g_assert (context
.method_inst
);
477 } else if ((ji
->method
->flags
& METHOD_ATTRIBUTE_STATIC
) || ji
->method
->klass
->valuetype
) {
478 MonoVTable
*vtable
= generic_info
;
480 class = vtable
->klass
;
482 class = generic_info
;
485 //g_assert (!ji->method->klass->generic_container);
486 if (ji
->method
->klass
->generic_class
)
487 method_container_class
= ji
->method
->klass
->generic_class
->container_class
;
489 method_container_class
= ji
->method
->klass
;
491 /* class might refer to a subclass of ji->method's class */
492 while (class->generic_class
&& class->generic_class
->container_class
!= method_container_class
) {
493 class = class->parent
;
497 if (class->generic_class
|| class->generic_container
)
498 context
.class_inst
= mini_class_get_context (class)->class_inst
;
500 if (class->generic_class
)
501 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class
->container_class
, method_container_class
));
503 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class
));
509 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
511 MonoGenericContext context
;
514 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
516 context
= get_generic_context_from_stack_frame (ji
, generic_info
);
518 method
= mono_method_get_declaring_generic_method (ji
->method
);
519 method
= mono_class_inflate_generic_method (method
, &context
);
525 ves_icall_System_Exception_get_trace (MonoException
*ex
)
527 MonoDomain
*domain
= mono_domain_get ();
529 MonoArray
*ta
= ex
->trace_ips
;
534 /* Exception is not thrown yet */
537 len
= mono_array_length (ta
) >> 1;
538 trace_str
= g_string_new ("");
539 for (i
= 0; i
< len
; i
++) {
541 gpointer ip
= mono_array_get (ta
, gpointer
, i
* 2 + 0);
542 gpointer generic_info
= mono_array_get (ta
, gpointer
, i
* 2 + 1);
544 ji
= mono_jit_info_table_find (domain
, ip
);
546 /* Unmanaged frame */
547 g_string_append_printf (trace_str
, "in (unmanaged) %p\n", ip
);
551 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
553 address
= (char *)ip
- (char *)ji
->code_start
;
554 location
= mono_debug_print_stack_frame (
555 method
, address
, ex
->object
.vtable
->domain
);
557 g_string_append_printf (trace_str
, "%s\n", location
);
562 res
= mono_string_new (ex
->object
.vtable
->domain
, trace_str
->str
);
563 g_string_free (trace_str
, TRUE
);
569 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
571 MonoDomain
*domain
= mono_domain_get ();
573 MonoArray
*ta
= exc
->trace_ips
;
574 MonoDebugSourceLocation
*location
;
578 /* Exception is not thrown yet */
579 return mono_array_new (domain
, mono_defaults
.stack_frame_class
, 0);
582 len
= mono_array_length (ta
) >> 1;
584 res
= mono_array_new (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0);
586 for (i
= skip
; i
< len
; i
++) {
588 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new (domain
, mono_defaults
.stack_frame_class
);
589 gpointer ip
= mono_array_get (ta
, gpointer
, i
* 2 + 0);
590 gpointer generic_info
= mono_array_get (ta
, gpointer
, i
* 2 + 1);
593 ji
= mono_jit_info_table_find (domain
, ip
);
595 /* Unmanaged frame */
596 mono_array_setref (res
, i
, sf
);
600 g_assert (ji
!= NULL
);
602 method
= get_method_from_stack_frame (ji
, generic_info
);
603 if (ji
->method
->wrapper_type
) {
607 s
= mono_method_full_name (method
, TRUE
);
608 MONO_OBJECT_SETREF (sf
, internal_method_name
, mono_string_new (domain
, s
));
612 MONO_OBJECT_SETREF (sf
, method
, mono_method_get_object (domain
, method
, NULL
));
613 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
616 * mono_debug_lookup_source_location() returns both the file / line number information
617 * and the IL offset. Note that computing the IL offset is already an expensive
618 * operation, so we shouldn't call this method twice.
620 location
= mono_debug_lookup_source_location (ji
->method
, sf
->native_offset
, domain
);
622 sf
->il_offset
= location
->il_offset
;
626 if (need_file_info
) {
627 if (location
&& location
->source_file
) {
628 MONO_OBJECT_SETREF (sf
, filename
, mono_string_new (domain
, location
->source_file
));
629 sf
->line
= location
->row
;
630 sf
->column
= location
->column
;
632 sf
->line
= sf
->column
= 0;
637 mono_debug_free_source_location (location
);
638 mono_array_setref (res
, i
, sf
);
646 * @domain: starting appdomain
647 * @jit_tls: JIT data for the thread
648 * @start_ctx: starting state of the stack frame
649 * @func: callback to call for each stack frame
650 * @user_data: data passed to the callback
652 * This function walks the stack of a thread, starting from the state
653 * represented by jit_tls and start_ctx. For each frame the callback
654 * function is called with the relevant info. The walk ends when no more
655 * managed stack frames are found or when the callback returns a TRUE value.
656 * Note that the function can be used to walk the stack of a thread
657 * different from the current.
660 mono_walk_stack (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoContext
*start_ctx
, MonoStackFrameWalk func
, gpointer user_data
)
662 MonoLMF
*lmf
= mono_get_lmf ();
663 MonoJitInfo
*ji
, rji
;
666 MonoContext ctx
, new_ctx
;
670 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
672 * FIXME: mono_find_jit_info () will need to be able to return a different
673 * MonoDomain when apddomain transitions are found on the stack.
675 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
676 if (!ji
|| ji
== (gpointer
)-1)
679 if (func (domain
, &new_ctx
, ji
, user_data
))
687 mono_jit_walk_stack_from_ctx (MonoStackWalk func
, MonoContext
*start_ctx
, gboolean do_il_offset
, gpointer user_data
)
689 MonoDomain
*domain
= mono_domain_get ();
690 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
691 MonoLMF
*lmf
= mono_get_lmf ();
692 MonoJitInfo
*ji
, rji
;
693 gint native_offset
, il_offset
;
695 MonoContext ctx
, new_ctx
;
697 MONO_ARCH_CONTEXT_DEF
699 mono_arch_flush_register_windows ();
702 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
704 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
705 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
707 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_jit_walk_stack_from_ctx
);
711 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
712 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
715 if (ji
== (gpointer
)-1)
719 MonoDebugSourceLocation
*source
;
721 source
= mono_debug_lookup_source_location (ji
->method
, native_offset
, domain
);
722 il_offset
= source
? source
->il_offset
: -1;
723 mono_debug_free_source_location (source
);
727 if (func (ji
->method
, native_offset
, il_offset
, managed
, user_data
))
735 mono_jit_walk_stack (MonoStackWalk func
, gboolean do_il_offset
, gpointer user_data
)
737 mono_jit_walk_stack_from_ctx (func
, NULL
, do_il_offset
, user_data
);
741 mono_jit_walk_stack_from_ctx_in_thread (MonoJitStackWalk func
, MonoDomain
*domain
, MonoContext
*start_ctx
, gboolean do_il_offset
, MonoInternalThread
*thread
, MonoLMF
*lmf
, gpointer user_data
)
743 MonoJitTlsData
*jit_tls
= thread
->jit_data
;
745 MonoContext ctx
, new_ctx
;
746 StackFrameInfo frame
;
747 #ifndef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
750 MonoJitInfo
*ji
, rji
;
755 MONO_ARCH_CONTEXT_DEF
757 mono_arch_flush_register_windows ();
760 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
762 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
763 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
765 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_jit_walk_stack_from_ctx
);
767 g_assert (thread
== mono_thread_internal_current ());
770 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
772 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
773 res
= mono_find_jit_info_ext (domain
, jit_tls
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &frame
);
777 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
779 frame
.type
= FRAME_TYPE_MANAGED
;
781 frame
.managed
= managed
;
782 frame
.native_offset
= native_offset
;
784 if (ji
== (gpointer
)-1)
788 if (do_il_offset
&& frame
.ji
) {
789 MonoDebugSourceLocation
*source
;
791 source
= mono_debug_lookup_source_location (frame
.ji
->method
, frame
.native_offset
, domain
);
792 il_offset
= source
? source
->il_offset
: -1;
793 mono_debug_free_source_location (source
);
797 frame
.il_offset
= il_offset
;
799 if (func (&frame
, &ctx
, user_data
))
808 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
809 MonoReflectionMethod
**method
,
810 gint32
*iloffset
, gint32
*native_offset
,
811 MonoString
**file
, gint32
*line
, gint32
*column
)
813 MonoDomain
*domain
= mono_domain_get ();
814 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
815 MonoLMF
*lmf
= mono_get_lmf ();
816 MonoJitInfo
*ji
, rji
;
817 MonoContext ctx
, new_ctx
, ji_ctx
;
818 MonoDebugSourceLocation
*location
;
819 MonoMethod
*last_method
= NULL
, *actual_method
;
821 MONO_ARCH_CONTEXT_DEF
;
823 mono_arch_flush_register_windows ();
825 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
826 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
828 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
833 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, (int*) native_offset
, NULL
);
836 if (ji
&& ji
!= (gpointer
)-1 &&
837 MONO_CONTEXT_GET_IP (&ctx
) >= ji
->code_start
&&
838 (guint8
*)MONO_CONTEXT_GET_IP (&ctx
) < (guint8
*)ji
->code_start
+ ji
->code_size
) {
842 if (!ji
|| ji
== (gpointer
)-1 || MONO_CONTEXT_GET_SP (&ctx
) >= jit_tls
->end_of_stack
)
845 /* skip all wrappers ??*/
846 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
847 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
848 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
849 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
850 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
||
851 ji
->method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
)
854 if (ji
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
&& ji
->method
== last_method
) {
856 * FIXME: Native-to-managed wrappers sometimes show up twice.
857 * Probably the whole mono_find_jit_info () stuff needs to be fixed so this
863 last_method
= ji
->method
;
869 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &ji_ctx
));
871 mono_gc_wbarrier_generic_store (method
, (MonoObject
*) mono_method_get_object (domain
, actual_method
, NULL
));
873 location
= mono_debug_lookup_source_location (ji
->method
, *native_offset
, domain
);
875 *iloffset
= location
->il_offset
;
879 if (need_file_info
) {
881 mono_gc_wbarrier_generic_store (file
, (MonoObject
*) mono_string_new (domain
, location
->source_file
));
882 *line
= location
->row
;
883 *column
= location
->column
;
890 mono_debug_free_source_location (location
);
897 MonoSecurityFrame
*frame
;
898 } MonoFrameSecurityInfo
;
901 callback_get_first_frame_security_info (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
903 MonoFrameSecurityInfo
*si
= (MonoFrameSecurityInfo
*) data
;
905 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
906 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
907 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
908 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
909 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
910 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
) {
919 si
->frame
= mono_declsec_create_frame (domain
, ji
);
921 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
926 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
927 * @skip: the number of stack frames to skip
929 * This function returns a the security informations of a single stack frame
930 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
931 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
935 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip
)
937 MonoDomain
*domain
= mono_domain_get ();
938 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
939 MonoFrameSecurityInfo si
;
942 MONO_ARCH_CONTEXT_DEF
944 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
945 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
947 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_System_Security_SecurityFrame_GetSecurityFrame
);
950 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
956 mono_walk_stack (domain
, jit_tls
, &ctx
, callback_get_first_frame_security_info
, (gpointer
)&si
);
958 return (si
.skips
== 0) ? si
.frame
: NULL
;
970 grow_array (MonoSecurityStack
*stack
)
972 MonoDomain
*domain
= mono_domain_get ();
973 guint32 newsize
= (stack
->maximum
<< 1);
974 MonoArray
*newstack
= mono_array_new (domain
, mono_defaults
.runtimesecurityframe_class
, newsize
);
976 for (i
=0; i
< stack
->maximum
; i
++) {
977 gpointer frame
= mono_array_get (stack
->stack
, gpointer
, i
);
978 mono_array_setref (newstack
, i
, frame
);
980 stack
->maximum
= newsize
;
981 stack
->stack
= newstack
;
985 callback_get_stack_frames_security_info (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
987 MonoSecurityStack
*ss
= (MonoSecurityStack
*) data
;
989 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
990 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
991 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
992 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
993 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
994 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
) {
1003 if (ss
->count
== ss
->maximum
)
1006 mono_array_setref (ss
->stack
, ss
->count
++, mono_declsec_create_frame (domain
, ji
));
1008 /* continue down the stack */
1013 glist_to_array (GList
*list
, MonoClass
*eclass
)
1015 MonoDomain
*domain
= mono_domain_get ();
1022 len
= g_list_length (list
);
1023 res
= mono_array_new (domain
, eclass
, len
);
1025 for (i
= 0; list
; list
= list
->next
, i
++)
1026 mono_array_set (res
, gpointer
, i
, list
->data
);
1032 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
1033 * @skip: the number of stack frames to skip
1035 * This function returns an managed array of containing the security
1036 * informations for each frame (after the skipped ones). This is used for
1037 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
1041 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip
)
1043 MonoDomain
*domain
= mono_domain_get ();
1044 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1045 MonoSecurityStack ss
;
1048 MONO_ARCH_CONTEXT_DEF
1050 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1051 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
1053 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_System_Security_SecurityFrame_GetSecurityStack
);
1056 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
1062 ss
.maximum
= MONO_CAS_INITIAL_STACK_SIZE
;
1063 ss
.stack
= mono_array_new (domain
, mono_defaults
.runtimesecurityframe_class
, ss
.maximum
);
1064 mono_walk_stack (domain
, jit_tls
, &ctx
, callback_get_stack_frames_security_info
, (gpointer
)&ss
);
1065 /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
1070 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
1072 MonoClass
*catch_class
= ei
->data
.catch_class
;
1073 MonoType
*inflated_type
;
1074 MonoGenericContext context
;
1079 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
1081 context
= get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
1083 /* FIXME: we shouldn't inflate but instead put the
1084 type in the rgctx and fetch it from there. It
1085 might be a good idea to do this lazily, i.e. only
1086 when the exception is actually thrown, so as not to
1087 waste space for exception clauses which might never
1089 inflated_type
= mono_class_inflate_generic_type (&catch_class
->byval_arg
, &context
);
1090 catch_class
= mono_class_from_mono_type (inflated_type
);
1091 mono_metadata_free_type (inflated_type
);
1097 * mini_jit_info_table_find:
1099 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1100 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1101 * OUT_DOMAIN if it is not NULL.
1104 mini_jit_info_table_find (MonoDomain
*domain
, char *addr
, MonoDomain
**out_domain
)
1107 MonoInternalThread
*t
= mono_thread_internal_current ();
1113 ji
= mono_jit_info_table_find (domain
, addr
);
1116 *out_domain
= domain
;
1120 /* maybe it is shared code, so we also search in the root domain */
1121 if (domain
!= mono_get_root_domain ()) {
1122 ji
= mono_jit_info_table_find (mono_get_root_domain (), addr
);
1125 *out_domain
= mono_get_root_domain ();
1130 for (l
= t
->appdomain_refs
; l
; l
= l
->next
) {
1131 if (l
->data
!= domain
) {
1132 ji
= mono_jit_info_table_find ((MonoDomain
*)l
->data
, addr
);
1135 *out_domain
= (MonoDomain
*)l
->data
;
1145 * mono_handle_exception_internal:
1146 * @ctx: saved processor state
1147 * @obj: the exception object
1148 * @test_only: only test if the exception is caught, but dont call handlers
1149 * @out_filter_idx: out parameter. if test_only is true, set to the index of
1150 * the first filter clause which caught the exception.
1151 * @resume: whenever to resume unwinding based on the state in MonoJitTlsData.
1154 mono_handle_exception_internal (MonoContext
*ctx
, gpointer obj
, gpointer original_ip
, gboolean test_only
, gboolean resume
, gint32
*out_filter_idx
, MonoJitInfo
**out_ji
)
1156 MonoDomain
*domain
= mono_domain_get ();
1157 MonoJitInfo
*ji
, rji
;
1158 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
1159 static void (*restore_context
) (void *);
1160 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1161 MonoLMF
*lmf
= mono_get_lmf ();
1162 MonoArray
*initial_trace_ips
= NULL
;
1163 GList
*trace_ips
= NULL
;
1164 MonoException
*mono_ex
;
1165 gboolean stack_overflow
= FALSE
;
1166 MonoContext initial_ctx
;
1167 int frame_count
= 0;
1168 gboolean has_dynamic_methods
= FALSE
;
1169 gint32 filter_idx
, first_filter_idx
;
1171 g_assert (ctx
!= NULL
);
1173 MonoException
*ex
= mono_get_exception_null_reference ();
1174 MONO_OBJECT_SETREF (ex
, message
, mono_string_new (domain
, "Object reference not set to an instance of an object"));
1175 obj
= (MonoObject
*)ex
;
1179 * Allocate a new exception object instead of the preconstructed ones.
1181 if (obj
== domain
->stack_overflow_ex
) {
1183 * It is not a good idea to try and put even more pressure on the little stack available.
1184 * obj = mono_get_exception_stack_overflow ();
1186 stack_overflow
= TRUE
;
1188 else if (obj
== domain
->null_reference_ex
) {
1189 obj
= mono_get_exception_null_reference ();
1192 if (mono_object_isinst (obj
, mono_defaults
.exception_class
)) {
1193 mono_ex
= (MonoException
*)obj
;
1194 initial_trace_ips
= mono_ex
->trace_ips
;
1199 if (mono_ex
&& jit_tls
->class_cast_from
&& !strcmp (mono_ex
->object
.vtable
->klass
->name
, "InvalidCastException")) {
1200 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
1201 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
1202 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
1203 mono_ex
->message
= mono_string_new (domain
, msg
);
1210 call_filter
= mono_get_call_filter ();
1212 if (!restore_context
)
1213 restore_context
= mono_get_restore_context ();
1215 g_assert (jit_tls
->end_of_stack
);
1216 g_assert (jit_tls
->abort_func
);
1219 MonoContext ctx_cp
= *ctx
;
1220 if (mono_trace_is_enabled ()) {
1221 MonoMethod
*system_exception_get_message
= mono_class_get_method_from_name (mono_defaults
.exception_class
, "get_Message", 0);
1222 MonoMethod
*get_message
= system_exception_get_message
== NULL
? NULL
: mono_object_get_virtual_method (obj
, system_exception_get_message
);
1223 MonoObject
*message
;
1224 const char *type_name
= mono_class_get_name (mono_object_class (mono_ex
));
1226 MonoObject
*exc
= NULL
;
1227 if (get_message
== NULL
) {
1229 } else if (!strcmp (type_name
, "OutOfMemoryException") || !strcmp (type_name
, "StackOverflowException")) {
1231 msg
= g_strdup_printf ("(No exception message for: %s)\n", type_name
);
1233 message
= mono_runtime_invoke (get_message
, obj
, NULL
, &exc
);
1237 msg
= message
? mono_string_to_utf8 ((MonoString
*) message
) : g_strdup ("(System.Exception.Message property not available)");
1239 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj
)->name_space
, mono_object_class (obj
)->name
, msg
);
1241 if (mono_ex
&& mono_trace_eval_exception (mono_object_class (mono_ex
)))
1242 mono_print_thread_dump_from_ctx (ctx
);
1244 mono_profiler_exception_thrown (obj
);
1245 if (!mono_handle_exception_internal (&ctx_cp
, obj
, original_ip
, TRUE
, FALSE
, &first_filter_idx
, out_ji
)) {
1246 if (mono_break_on_exc
)
1248 mono_debugger_agent_handle_exception (obj
, ctx
, NULL
);
1249 // FIXME: This runs managed code so it might cause another stack overflow when
1250 // we are handling a stack overflow
1251 mono_unhandled_exception (obj
);
1253 mono_debugger_agent_handle_exception (obj
, ctx
, &ctx_cp
);
1258 *out_filter_idx
= -1;
1263 memset (&rji
, 0, sizeof (rji
));
1266 MonoContext new_ctx
;
1269 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, &rji
, ctx
, &new_ctx
,
1270 NULL
, &lmf
, NULL
, NULL
);
1272 g_warning ("Exception inside function without unwind info");
1273 g_assert_not_reached ();
1276 if (ji
!= (gpointer
)-1 && !(ji
->code_start
<= MONO_CONTEXT_GET_IP (ctx
) && (((guint8
*)ji
->code_start
+ ji
->code_size
>= (guint8
*)MONO_CONTEXT_GET_IP (ctx
))))) {
1278 * The exception was raised in native code and we got back to managed code
1285 if (ji
!= (gpointer
)-1) {
1287 //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
1289 if (test_only
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
1291 * Avoid overwriting the stack trace if the exception is
1292 * rethrown. Also avoid giant stack traces during a stack
1295 if (!initial_trace_ips
&& (frame_count
< 1000)) {
1296 trace_ips
= g_list_prepend (trace_ips
, MONO_CONTEXT_GET_IP (ctx
));
1297 trace_ips
= g_list_prepend (trace_ips
,
1298 get_generic_info_from_stack_frame (ji
, ctx
));
1302 if (ji
->method
->dynamic
)
1303 has_dynamic_methods
= TRUE
;
1306 #ifndef MONO_ARCH_STACK_GROWS_UP
1307 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
1309 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (ctx
));
1312 free_stack
= 0xffffff;
1315 * During stack overflow, wait till the unwinding frees some stack
1316 * space before running handlers/finalizers.
1318 if ((free_stack
> (64 * 1024)) && ji
->num_clauses
) {
1321 for (i
= 0; i
< ji
->num_clauses
; i
++) {
1322 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
1323 gboolean filtered
= FALSE
;
1325 #if defined(__s390__)
1327 * This is required in cases where a try block starts immediately after
1328 * a call which causes an exception. Testcase: tests/exception8.cs.
1329 * FIXME: Clean this up.
1331 if (ei
->try_start
< MONO_CONTEXT_GET_IP (ctx
) && MONO_CONTEXT_GET_IP (ctx
) <= ei
->try_end
) {
1333 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (ctx
))) {
1336 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
1338 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
)) {
1339 if (ji
->from_llvm
) {
1340 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1341 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx
, obj
);
1343 g_assert_not_reached ();
1346 /* store the exception object in bp + ei->exvar_offset */
1347 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = obj
;
1351 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
1353 mono_perfcounters
->exceptions_filters
++;
1354 mono_debugger_call_exception_handler (ei
->data
.filter
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1355 filtered
= call_filter (ctx
, ei
->data
.filter
);
1356 if (filtered
&& out_filter_idx
)
1357 *out_filter_idx
= filter_idx
;
1363 * Filter clauses should only be run in the
1364 * first pass of exception handling.
1366 filtered
= (filter_idx
== first_filter_idx
);
1371 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
1372 mono_object_isinst (obj
, catch_class
)) || filtered
) {
1374 if (mono_ex
&& !initial_trace_ips
) {
1375 trace_ips
= g_list_reverse (trace_ips
);
1376 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, glist_to_array (trace_ips
, mono_defaults
.int_class
));
1377 if (has_dynamic_methods
)
1378 /* These methods could go away anytime, so compute the stack trace now */
1379 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, ves_icall_System_Exception_get_trace (mono_ex
));
1381 g_list_free (trace_ips
);
1385 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1386 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1387 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1388 mono_debugger_call_exception_handler (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1389 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
1390 *(mono_get_lmf_addr ()) = lmf
;
1391 mono_perfcounters
->exceptions_depth
+= frame_count
;
1392 if (obj
== domain
->stack_overflow_ex
)
1393 jit_tls
->handling_stack_ovf
= FALSE
;
1397 if (!test_only
&& is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (ctx
)) &&
1398 (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
)) {
1399 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1400 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1401 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1402 mono_debugger_call_exception_handler (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1403 call_filter (ctx
, ei
->handler_start
);
1405 if (!test_only
&& is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (ctx
)) &&
1406 (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
)) {
1407 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1408 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1409 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1410 mono_debugger_call_exception_handler (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1411 mono_perfcounters
->exceptions_finallys
++;
1412 *(mono_get_lmf_addr ()) = lmf
;
1413 if (ji
->from_llvm
) {
1415 * LLVM compiled finally handlers follow the design
1416 * of the c++ ehabi, i.e. they call a resume function
1417 * at the end instead of returning to the caller.
1418 * So save the exception handling state,
1419 * mono_resume_unwind () will call us again to continue
1422 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
1423 *(mono_get_lmf_addr ()) = lmf
;
1424 jit_tls
->ex_ctx
= new_ctx
;
1425 jit_tls
->ex_obj
= obj
;
1428 call_filter (ctx
, ei
->handler_start
);
1436 mono_profiler_exception_method_leave (ji
->method
);
1441 if (ji
== (gpointer
)-1) {
1444 *(mono_get_lmf_addr ()) = lmf
;
1446 jit_tls
->abort_func (obj
);
1447 g_assert_not_reached ();
1449 if (mono_ex
&& !initial_trace_ips
) {
1450 trace_ips
= g_list_reverse (trace_ips
);
1451 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, glist_to_array (trace_ips
, mono_defaults
.int_class
));
1452 if (has_dynamic_methods
)
1453 /* These methods could go away anytime, so compute the stack trace now */
1454 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, ves_icall_System_Exception_get_trace (mono_ex
));
1456 g_list_free (trace_ips
);
1462 g_assert_not_reached ();
1466 * mono_debugger_handle_exception:
1468 * Notify the debugger about exceptions. Returns TRUE if the debugger wants us to stop
1469 * at the exception and FALSE to resume with the normal exception handling.
1471 * The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
1472 * MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
1473 * `callq throw' instruction.
1476 mono_debugger_handle_exception (MonoContext
*ctx
, MonoObject
*obj
)
1478 MonoDebuggerExceptionAction action
;
1480 if (!mono_debug_using_mono_debugger ())
1484 MonoException
*ex
= mono_get_exception_null_reference ();
1485 MONO_OBJECT_SETREF (ex
, message
, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
1486 obj
= (MonoObject
*)ex
;
1489 action
= _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx
), MONO_CONTEXT_GET_SP (ctx
), obj
);
1491 if (action
== MONO_DEBUGGER_EXCEPTION_ACTION_STOP
) {
1493 * The debugger wants us to stop on the `throw' instruction.
1494 * By the time we get here, it already inserted a breakpoint there.
1497 } else if (action
== MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED
) {
1498 MonoContext ctx_cp
= *ctx
;
1499 MonoJitInfo
*ji
= NULL
;
1503 * The debugger wants us to stop only if this exception is user-unhandled.
1506 ret
= mono_handle_exception_internal (&ctx_cp
, obj
, MONO_CONTEXT_GET_IP (ctx
), TRUE
, FALSE
, NULL
, &ji
);
1507 if (ret
&& (ji
!= NULL
) && (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
)) {
1509 * The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
1510 * inside the method being invoked, so we handle it like a user-unhandled exception.
1517 * The exception is user-unhandled - tell the debugger to stop.
1519 return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx
), MONO_CONTEXT_GET_SP (ctx
), obj
);
1523 * The exception is catched somewhere - resume with the normal exception handling and don't
1524 * stop in the debugger.
1532 * mono_debugger_run_finally:
1533 * @start_ctx: saved processor state
1535 * This method is called by the Mono Debugger to call all `finally' clauses of the
1536 * current stack frame. It's used when the user issues a `return' command to make
1537 * the current stack frame return. After returning from this method, the debugger
1538 * unwinds the stack one frame and gives control back to the user.
1540 * NOTE: This method is only used when running inside the Mono Debugger.
1543 mono_debugger_run_finally (MonoContext
*start_ctx
)
1545 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
1546 MonoDomain
*domain
= mono_domain_get ();
1547 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1548 MonoLMF
*lmf
= mono_get_lmf ();
1549 MonoContext ctx
, new_ctx
;
1550 MonoJitInfo
*ji
, rji
;
1555 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
1556 if (!ji
|| ji
== (gpointer
)-1)
1560 call_filter
= mono_get_call_filter ();
1562 for (i
= 0; i
< ji
->num_clauses
; i
++) {
1563 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
1565 if (is_address_protected (ji
, ei
, MONO_CONTEXT_GET_IP (&ctx
)) &&
1566 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
1567 call_filter (&ctx
, ei
->handler_start
);
1573 * mono_handle_exception:
1574 * @ctx: saved processor state
1575 * @obj: the exception object
1576 * @test_only: only test if the exception is caught, but dont call handlers
1579 mono_handle_exception (MonoContext
*ctx
, gpointer obj
, gpointer original_ip
, gboolean test_only
)
1582 mono_perfcounters
->exceptions_thrown
++;
1584 return mono_handle_exception_internal (ctx
, obj
, original_ip
, test_only
, FALSE
, NULL
, NULL
);
1587 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1589 #ifndef MONO_ARCH_USE_SIGACTION
1590 #error "Can't use sigaltstack without sigaction"
1593 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1596 mono_setup_altstack (MonoJitTlsData
*tls
)
1599 struct sigaltstack sa
;
1600 guint8
*staddr
= NULL
;
1602 if (mono_running_on_valgrind ())
1605 mono_thread_get_stack_bounds (&staddr
, &stsize
);
1609 tls
->end_of_stack
= staddr
+ stsize
;
1611 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1613 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
1614 tls
->stack_ovf_guard_size
= ALIGN_TO (8 * 4096, mono_pagesize ());
1616 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
1617 /* mprotect can fail for the main thread stack */
1618 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
);
1619 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
1620 tls
->stack_ovf_valloced
= TRUE
;
1624 * threads created by nptl does not seem to have a guard page, and
1625 * since the main thread is not created by us, we can't even set one.
1626 * Increasing stsize fools the SIGSEGV signal handler into thinking this
1627 * is a stack overflow exception.
1629 tls
->stack_size
= stsize
+ mono_pagesize ();
1631 /* Setup an alternate signal stack */
1632 tls
->signal_stack
= mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MMAP_READ
|MONO_MMAP_WRITE
|MONO_MMAP_PRIVATE
|MONO_MMAP_ANON
);
1633 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1635 g_assert (tls
->signal_stack
);
1637 sa
.ss_sp
= tls
->signal_stack
;
1638 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1639 sa
.ss_flags
= SS_ONSTACK
;
1640 sigaltstack (&sa
, NULL
);
1644 mono_free_altstack (MonoJitTlsData
*tls
)
1646 struct sigaltstack sa
;
1649 sa
.ss_sp
= tls
->signal_stack
;
1650 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1651 sa
.ss_flags
= SS_DISABLE
;
1652 err
= sigaltstack (&sa
, NULL
);
1653 g_assert (err
== 0);
1655 if (tls
->signal_stack
)
1656 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
);
1657 if (tls
->stack_ovf_valloced
)
1658 mono_vfree (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
);
1660 mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_READ
|MONO_MMAP_WRITE
);
1663 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1666 mono_setup_altstack (MonoJitTlsData
*tls
)
1671 mono_free_altstack (MonoJitTlsData
*tls
)
1675 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1678 try_restore_stack_protection (MonoJitTlsData
*jit_tls
, int extra_bytes
)
1680 gint32 unprotect_size
= jit_tls
->stack_ovf_guard_size
;
1681 /* we need to leave some room for throwing the exception */
1682 while (unprotect_size
>= 0 && (char*)jit_tls
->stack_ovf_guard_base
+ unprotect_size
> ((char*)&unprotect_size
- extra_bytes
))
1683 unprotect_size
-= mono_pagesize ();
1684 /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1685 * is sufficient stack
1687 //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);
1689 mono_mprotect (jit_tls
->stack_ovf_guard_base
, unprotect_size
, MONO_MMAP_NONE
);
1690 return unprotect_size
== jit_tls
->stack_ovf_guard_size
;
1694 try_more_restore (void)
1696 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1697 if (try_restore_stack_protection (jit_tls
, 500))
1698 jit_tls
->restore_stack_prot
= NULL
;
1702 restore_stack_protection (void)
1704 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1705 MonoException
*ex
= mono_domain_get ()->stack_overflow_ex
;
1706 /* if we can't restore the stack protection, keep a callback installed so
1707 * we'll try to restore as much stack as we can at each return from unmanaged
1710 if (try_restore_stack_protection (jit_tls
, 4096))
1711 jit_tls
->restore_stack_prot
= NULL
;
1713 jit_tls
->restore_stack_prot
= try_more_restore_tramp
;
1714 /* here we also throw a stack overflow exception */
1715 ex
->trace_ips
= NULL
;
1716 ex
->stack_trace
= NULL
;
1717 mono_raise_exception (ex
);
1721 mono_altstack_restore_prot (mgreg_t
*regs
, guint8
*code
, gpointer
*tramp_data
, guint8
* tramp
)
1723 void (*func
)(void) = (gpointer
)tramp_data
;
1729 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, guint8
* fault_addr
)
1731 /* we got a stack overflow in the soft-guard pages
1732 * There are two cases:
1733 * 1) managed code caused the overflow: we unprotect the soft-guard page
1734 * and let the arch-specific code trigger the exception handling mechanism
1735 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1736 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1737 * and hope we can continue with those enabled, at least until the hard-guard page
1738 * is hit. The alternative to continuing here is to just print a message and abort.
1739 * We may add in the future the code to protect the pages again in the codepath
1740 * when we return from unmanaged to managed code.
1742 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
1743 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
1744 /* we unprotect the minimum amount we can */
1746 gboolean handled
= FALSE
;
1748 guard_size
= jit_tls
->stack_ovf_guard_size
- (mono_pagesize () * SIZEOF_VOID_P
/ 4);
1749 while (guard_size
&& fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ guard_size
) {
1750 guard_size
-= mono_pagesize ();
1752 guard_size
= jit_tls
->stack_ovf_guard_size
- guard_size
;
1753 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
1754 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
);
1755 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1757 mono_arch_handle_altstack_exception (ctx
, fault_addr
, TRUE
);
1762 /* We print a message: after this even managed stack overflows
1763 * may crash the runtime
1765 fprintf (stderr
, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx
), fault_addr
);
1766 if (!jit_tls
->handling_stack_ovf
) {
1767 jit_tls
->restore_stack_prot
= restore_stack_protection_tramp
;
1768 jit_tls
->handling_stack_ovf
= 1;
1770 /*fprintf (stderr, "Already handling stack overflow\n");*/
1779 print_stack_frame (MonoMethod
*method
, gint32 native_offset
, gint32 il_offset
, gboolean managed
, gpointer data
)
1781 FILE *stream
= (FILE*)data
;
1784 gchar
*location
= mono_debug_print_stack_frame (method
, native_offset
, mono_domain_get ());
1785 fprintf (stream
, " %s\n", location
);
1788 fprintf (stream
, " at <unknown> <0x%05x>\n", native_offset
);
1793 static G_GNUC_UNUSED gboolean
1794 print_stack_frame_to_string (MonoMethod
*method
, gint32 native_offset
, gint32 il_offset
, gboolean managed
,
1797 GString
*p
= (GString
*)data
;
1800 gchar
*location
= mono_debug_print_stack_frame (method
, native_offset
, mono_domain_get ());
1801 g_string_append_printf (p
, " %s\n", location
);
1804 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", native_offset
);
1809 static gboolean handling_sigsegv
= FALSE
;
1812 * mono_handle_native_sigsegv:
1814 * Handle a SIGSEGV received while in native code by printing diagnostic
1815 * information and aborting.
1818 mono_handle_native_sigsegv (int signal
, void *ctx
)
1820 #ifdef MONO_ARCH_USE_SIGACTION
1821 struct sigaction sa
;
1823 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1825 if (handling_sigsegv
)
1828 if (mini_get_debug_options ()->suspend_on_sigsegv
) {
1829 fprintf (stderr
, "Received SIGSEGV, suspending...");
1834 /* To prevent infinite loops when the stack walk causes a crash */
1835 handling_sigsegv
= TRUE
;
1837 /* !jit_tls means the thread was not registered with the runtime */
1838 if (jit_tls
&& mono_thread_internal_current ()) {
1839 fprintf (stderr
, "Stacktrace:\n\n");
1841 mono_jit_walk_stack (print_stack_frame
, TRUE
, stderr
);
1846 #ifdef HAVE_BACKTRACE_SYMBOLS
1851 const char *signal_str
= (signal
== SIGSEGV
) ? "SIGSEGV" : "SIGABRT";
1853 fprintf (stderr
, "\nNative stacktrace:\n\n");
1855 size
= backtrace (array
, 256);
1856 names
= backtrace_symbols (array
, size
);
1857 for (i
=0; i
< size
; ++i
) {
1858 fprintf (stderr
, "\t%s\n", names
[i
]);
1864 /* Try to get more meaningful information using gdb */
1866 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
1867 if (!mini_get_debug_options ()->no_gdb_backtrace
&& !mono_debug_using_mono_debugger ()) {
1868 /* From g_spawn_command_line_sync () in eglib */
1870 int stdout_pipe
[2] = { -1, -1 };
1875 res
= pipe (stdout_pipe
);
1876 g_assert (res
!= -1);
1880 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1881 * it will deadlock. Call the syscall directly instead.
1883 pid
= mono_runtime_syscall_fork ();
1886 close (stdout_pipe
[0]);
1887 dup2 (stdout_pipe
[1], STDOUT_FILENO
);
1889 for (i
= getdtablesize () - 1; i
>= 3; i
--)
1892 if (!mono_gdb_render_native_backtraces ())
1893 close (STDOUT_FILENO
);
1898 close (stdout_pipe
[1]);
1900 fprintf (stderr
, "\nDebug info from gdb:\n\n");
1903 int nread
= read (stdout_pipe
[0], buffer
, 1024);
1907 write (STDERR_FILENO
, buffer
, nread
);
1910 waitpid (pid
, &status
, WNOHANG
);
1914 * A SIGSEGV indicates something went very wrong so we can no longer depend
1915 * on anything working. So try to print out lots of diagnostics, starting
1916 * with ones which have a greater chance of working.
1920 "=================================================================\n"
1921 "Got a %s while executing native code. This usually indicates\n"
1922 "a fatal error in the mono runtime or one of the native libraries \n"
1923 "used by your application.\n"
1924 "=================================================================\n"
1930 #ifdef MONO_ARCH_USE_SIGACTION
1932 /* Remove our SIGABRT handler */
1933 sa
.sa_handler
= SIG_DFL
;
1934 sigemptyset (&sa
.sa_mask
);
1937 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
1945 mono_print_thread_dump_internal (void *sigctx
, MonoContext
*start_ctx
)
1947 MonoInternalThread
*thread
= mono_thread_internal_current ();
1948 #if defined(__i386__) || defined(__x86_64__)
1951 GString
* text
= g_string_new (0);
1952 char *name
, *wapi_desc
;
1953 GError
*error
= NULL
;
1956 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &error
);
1958 g_string_append_printf (text
, "\n\"%s\"", name
);
1961 else if (thread
->threadpool_thread
)
1962 g_string_append (text
, "\n\"<threadpool thread>\"");
1964 g_string_append (text
, "\n\"<unnamed thread>\"");
1967 wapi_desc
= wapi_current_thread_desc ();
1968 g_string_append_printf (text
, " tid=0x%p this=0x%p %s\n", (gpointer
)(gsize
)thread
->tid
, thread
, wapi_desc
);
1972 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
1974 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
1976 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
1978 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
1980 mono_jit_walk_stack_from_ctx (print_stack_frame_to_string
, &ctx
, TRUE
, text
);
1982 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
1985 fprintf (stdout
, "%s", text
->str
);
1986 g_string_free (text
, TRUE
);
1991 * mono_print_thread_dump:
1993 * Print information about the current thread to stdout.
1994 * SIGCTX can be NULL, allowing this to be called from gdb.
1997 mono_print_thread_dump (void *sigctx
)
1999 mono_print_thread_dump_internal (sigctx
, NULL
);
2003 mono_print_thread_dump_from_ctx (MonoContext
*ctx
)
2005 mono_print_thread_dump_internal (NULL
, ctx
);
2009 * mono_resume_unwind:
2011 * This is called by code at the end of LLVM compiled finally clauses to continue
2015 mono_resume_unwind (void)
2017 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
2018 static void (*restore_context
) (MonoContext
*);
2021 memcpy (&ctx
, &jit_tls
->ex_ctx
, sizeof (MonoContext
));
2023 mono_handle_exception_internal (&ctx
, jit_tls
->ex_obj
, NULL
, FALSE
, TRUE
, NULL
, NULL
);
2025 if (!restore_context
)
2026 restore_context
= mono_get_restore_context ();
2028 restore_context (&ctx
);