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"
52 #ifndef MONO_ARCH_CONTEXT_DEF
53 #define MONO_ARCH_CONTEXT_DEF
56 static gpointer restore_context_func
, call_filter_func
;
57 static gpointer throw_exception_func
, rethrow_exception_func
;
58 static gpointer throw_exception_by_name_func
, throw_corlib_exception_func
;
60 static gpointer try_more_restore_tramp
= NULL
;
61 static gpointer restore_stack_protection_tramp
= NULL
;
63 static void try_more_restore (void);
64 static void restore_stack_protection (void);
67 mono_exceptions_init (void)
69 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
74 restore_context_func
= mono_aot_get_named_code ("restore_context");
75 call_filter_func
= mono_aot_get_named_code ("call_filter");
76 throw_exception_func
= mono_aot_get_named_code ("throw_exception");
77 rethrow_exception_func
= mono_aot_get_named_code ("rethrow_exception");
79 restore_context_func
= mono_arch_get_restore_context_full (&code_size
, &ji
, FALSE
);
80 call_filter_func
= mono_arch_get_call_filter_full (&code_size
, &ji
, FALSE
);
81 throw_exception_func
= mono_arch_get_throw_exception_full (&code_size
, &ji
, FALSE
);
82 rethrow_exception_func
= mono_arch_get_rethrow_exception_full (&code_size
, &ji
, FALSE
);
85 restore_context_func
= mono_arch_get_restore_context ();
86 call_filter_func
= mono_arch_get_call_filter ();
87 throw_exception_func
= mono_arch_get_throw_exception ();
88 rethrow_exception_func
= mono_arch_get_rethrow_exception ();
90 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
91 try_more_restore_tramp
= mono_create_specific_trampoline (try_more_restore
, MONO_TRAMPOLINE_RESTORE_STACK_PROT
, mono_domain_get (), NULL
);
92 restore_stack_protection_tramp
= mono_create_specific_trampoline (restore_stack_protection
, MONO_TRAMPOLINE_RESTORE_STACK_PROT
, mono_domain_get (), NULL
);
95 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
96 mono_arch_exceptions_init ();
101 mono_get_throw_exception (void)
103 g_assert (throw_exception_func
);
104 return throw_exception_func
;
108 mono_get_rethrow_exception (void)
110 g_assert (rethrow_exception_func
);
111 return rethrow_exception_func
;
115 mono_get_call_filter (void)
117 g_assert (call_filter_func
);
118 return call_filter_func
;
122 mono_get_restore_context (void)
124 g_assert (restore_context_func
);
125 return restore_context_func
;
129 mono_get_throw_exception_by_name (void)
131 gpointer code
= NULL
;
132 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
137 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
138 if (throw_exception_by_name_func
)
139 return throw_exception_by_name_func
;
141 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
143 code
= mono_aot_get_named_code ("throw_exception_by_name");
145 code
= mono_arch_get_throw_exception_by_name_full (&code_size
, &ji
, FALSE
);
147 code
= mono_arch_get_throw_exception_by_name ();
150 mono_memory_barrier ();
152 throw_exception_by_name_func
= code
;
154 return throw_exception_by_name_func
;
158 mono_get_throw_corlib_exception (void)
160 gpointer code
= NULL
;
161 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
166 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
167 if (throw_corlib_exception_func
)
168 return throw_corlib_exception_func
;
170 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
171 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
173 code
= mono_aot_get_named_code ("throw_corlib_exception");
175 code
= mono_arch_get_throw_corlib_exception_full (&code_size
, &ji
, FALSE
);
177 code
= mono_arch_get_throw_corlib_exception ();
180 g_assert_not_reached ();
183 mono_memory_barrier ();
185 throw_corlib_exception_func
= code
;
187 return throw_corlib_exception_func
;
190 /* mono_find_jit_info:
192 * This function is used to gather information from @ctx. It return the
193 * MonoJitInfo of the corresponding function, unwinds one stack frame and
194 * stores the resulting context into @new_ctx. It also stores a string
195 * describing the stack location into @trace (if not NULL), and modifies
196 * the @lmf if necessary. @native_offset return the IP offset from the
197 * start of the function or -1 if that info is not available.
200 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
201 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
205 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
217 ji
= mono_arch_find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
219 if (ji
== (gpointer
)-1)
222 if (managed2
|| ji
->method
->wrapper_type
) {
223 const char *real_ip
, *start
;
226 start
= (const char *)ji
->code_start
;
228 /* ctx->ip points into native code */
229 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
231 real_ip
= (const char*)ip
;
233 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
234 offset
= real_ip
- start
;
239 *native_offset
= offset
;
242 if (!ji
->method
->wrapper_type
)
246 *trace
= mono_debug_print_stack_frame (ji
->method
, offset
, domain
);
249 char *fname
= mono_method_full_name (res
->method
, TRUE
);
250 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
259 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
261 MonoGenericJitInfo
*gi
;
263 if (!ji
->has_generic_jit_info
)
265 gi
= mono_jit_info_get_generic_jit_info (ji
);
270 return mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
272 return *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
276 static MonoGenericContext
277 get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
279 MonoGenericContext context
= { NULL
, NULL
};
280 MonoClass
*class, *method_container_class
;
282 g_assert (generic_info
);
284 g_assert (ji
->method
->is_inflated
);
285 if (mono_method_get_context (ji
->method
)->method_inst
) {
286 MonoMethodRuntimeGenericContext
*mrgctx
= generic_info
;
288 class = mrgctx
->class_vtable
->klass
;
289 context
.method_inst
= mrgctx
->method_inst
;
290 g_assert (context
.method_inst
);
291 } else if ((ji
->method
->flags
& METHOD_ATTRIBUTE_STATIC
) || ji
->method
->klass
->valuetype
) {
292 MonoVTable
*vtable
= generic_info
;
294 class = vtable
->klass
;
296 MonoObject
*this = generic_info
;
298 class = this->vtable
->klass
;
301 if (class->generic_class
|| class->generic_container
)
302 context
.class_inst
= mini_class_get_context (class)->class_inst
;
304 g_assert (!ji
->method
->klass
->generic_container
);
305 if (ji
->method
->klass
->generic_class
)
306 method_container_class
= ji
->method
->klass
->generic_class
->container_class
;
308 method_container_class
= ji
->method
->klass
;
310 if (class->generic_class
)
311 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class
->container_class
, method_container_class
));
313 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class
));
319 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
321 MonoGenericContext context
;
324 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
326 context
= get_generic_context_from_stack_frame (ji
, generic_info
);
328 method
= mono_method_get_declaring_generic_method (ji
->method
);
329 method
= mono_class_inflate_generic_method (method
, &context
);
335 ves_icall_System_Exception_get_trace (MonoException
*ex
)
337 MonoDomain
*domain
= mono_domain_get ();
339 MonoArray
*ta
= ex
->trace_ips
;
344 /* Exception is not thrown yet */
347 len
= mono_array_length (ta
) >> 1;
348 trace_str
= g_string_new ("");
349 for (i
= 0; i
< len
; i
++) {
351 gpointer ip
= mono_array_get (ta
, gpointer
, i
* 2 + 0);
352 gpointer generic_info
= mono_array_get (ta
, gpointer
, i
* 2 + 1);
354 ji
= mono_jit_info_table_find (domain
, ip
);
356 /* Unmanaged frame */
357 g_string_append_printf (trace_str
, "in (unmanaged) %p\n", ip
);
361 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
363 address
= (char *)ip
- (char *)ji
->code_start
;
364 location
= mono_debug_print_stack_frame (
365 method
, address
, ex
->object
.vtable
->domain
);
367 g_string_append_printf (trace_str
, "%s\n", location
);
372 res
= mono_string_new (ex
->object
.vtable
->domain
, trace_str
->str
);
373 g_string_free (trace_str
, TRUE
);
379 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
381 MonoDomain
*domain
= mono_domain_get ();
383 MonoArray
*ta
= exc
->trace_ips
;
384 MonoDebugSourceLocation
*location
;
388 /* Exception is not thrown yet */
389 return mono_array_new (domain
, mono_defaults
.stack_frame_class
, 0);
392 len
= mono_array_length (ta
) >> 1;
394 res
= mono_array_new (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0);
396 for (i
= skip
; i
< len
; i
++) {
398 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new (domain
, mono_defaults
.stack_frame_class
);
399 gpointer ip
= mono_array_get (ta
, gpointer
, i
* 2 + 0);
400 gpointer generic_info
= mono_array_get (ta
, gpointer
, i
* 2 + 1);
403 ji
= mono_jit_info_table_find (domain
, ip
);
405 /* Unmanaged frame */
406 mono_array_setref (res
, i
, sf
);
410 g_assert (ji
!= NULL
);
412 method
= get_method_from_stack_frame (ji
, generic_info
);
413 if (ji
->method
->wrapper_type
) {
417 s
= mono_method_full_name (method
, TRUE
);
418 MONO_OBJECT_SETREF (sf
, internal_method_name
, mono_string_new (domain
, s
));
422 MONO_OBJECT_SETREF (sf
, method
, mono_method_get_object (domain
, method
, NULL
));
423 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
426 * mono_debug_lookup_source_location() returns both the file / line number information
427 * and the IL offset. Note that computing the IL offset is already an expensive
428 * operation, so we shouldn't call this method twice.
430 location
= mono_debug_lookup_source_location (ji
->method
, sf
->native_offset
, domain
);
432 sf
->il_offset
= location
->il_offset
;
436 if (need_file_info
) {
437 if (location
&& location
->source_file
) {
438 MONO_OBJECT_SETREF (sf
, filename
, mono_string_new (domain
, location
->source_file
));
439 sf
->line
= location
->row
;
440 sf
->column
= location
->column
;
442 sf
->line
= sf
->column
= 0;
447 mono_debug_free_source_location (location
);
448 mono_array_setref (res
, i
, sf
);
456 * @domain: starting appdomain
457 * @jit_tls: JIT data for the thread
458 * @start_ctx: starting state of the stack frame
459 * @func: callback to call for each stack frame
460 * @user_data: data passed to the callback
462 * This function walks the stack of a thread, starting from the state
463 * represented by jit_tls and start_ctx. For each frame the callback
464 * function is called with the relevant info. The walk ends when no more
465 * managed stack frames are found or when the callback returns a TRUE value.
466 * Note that the function can be used to walk the stack of a thread
467 * different from the current.
470 mono_walk_stack (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoContext
*start_ctx
, MonoStackFrameWalk func
, gpointer user_data
)
472 MonoLMF
*lmf
= mono_get_lmf ();
473 MonoJitInfo
*ji
, rji
;
476 MonoContext ctx
, new_ctx
;
480 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
482 * FIXME: mono_find_jit_info () will need to be able to return a different
483 * MonoDomain when apddomain transitions are found on the stack.
485 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
486 if (!ji
|| ji
== (gpointer
)-1)
489 if (func (domain
, &new_ctx
, ji
, user_data
))
497 mono_jit_walk_stack_from_ctx (MonoStackWalk func
, MonoContext
*start_ctx
, gboolean do_il_offset
, gpointer user_data
)
499 MonoDomain
*domain
= mono_domain_get ();
500 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
501 MonoLMF
*lmf
= mono_get_lmf ();
502 MonoJitInfo
*ji
, rji
;
503 gint native_offset
, il_offset
;
505 MonoContext ctx
, new_ctx
;
507 MONO_ARCH_CONTEXT_DEF
509 mono_arch_flush_register_windows ();
512 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
514 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
515 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
517 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_jit_walk_stack_from_ctx
);
521 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
522 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
525 if (ji
== (gpointer
)-1)
529 MonoDebugSourceLocation
*source
;
531 source
= mono_debug_lookup_source_location (ji
->method
, native_offset
, domain
);
532 il_offset
= source
? source
->il_offset
: -1;
533 mono_debug_free_source_location (source
);
537 if (func (ji
->method
, native_offset
, il_offset
, managed
, user_data
))
545 mono_jit_walk_stack (MonoStackWalk func
, gboolean do_il_offset
, gpointer user_data
)
547 mono_jit_walk_stack_from_ctx (func
, NULL
, do_il_offset
, user_data
);
551 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
552 MonoReflectionMethod
**method
,
553 gint32
*iloffset
, gint32
*native_offset
,
554 MonoString
**file
, gint32
*line
, gint32
*column
)
556 MonoDomain
*domain
= mono_domain_get ();
557 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
558 MonoLMF
*lmf
= mono_get_lmf ();
559 MonoJitInfo
*ji
, rji
;
560 MonoContext ctx
, new_ctx
, ji_ctx
;
561 MonoDebugSourceLocation
*location
;
562 MonoMethod
*last_method
= NULL
, *actual_method
;
564 MONO_ARCH_CONTEXT_DEF
;
566 mono_arch_flush_register_windows ();
568 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
569 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
571 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
576 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, (int*) native_offset
, NULL
);
579 if (ji
&& ji
!= (gpointer
)-1 &&
580 MONO_CONTEXT_GET_IP (&ctx
) >= ji
->code_start
&&
581 (guint8
*)MONO_CONTEXT_GET_IP (&ctx
) < (guint8
*)ji
->code_start
+ ji
->code_size
) {
585 if (!ji
|| ji
== (gpointer
)-1 || MONO_CONTEXT_GET_SP (&ctx
) >= jit_tls
->end_of_stack
)
588 /* skip all wrappers ??*/
589 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
590 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
591 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
592 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
593 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
||
594 ji
->method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
)
597 if (ji
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
&& ji
->method
== last_method
) {
599 * FIXME: Native-to-managed wrappers sometimes show up twice.
600 * Probably the whole mono_find_jit_info () stuff needs to be fixed so this
606 last_method
= ji
->method
;
612 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &ji_ctx
));
614 *method
= mono_method_get_object (domain
, actual_method
, NULL
);
616 location
= mono_debug_lookup_source_location (ji
->method
, *native_offset
, domain
);
618 *iloffset
= location
->il_offset
;
622 if (need_file_info
) {
624 *file
= mono_string_new (domain
, location
->source_file
);
625 *line
= location
->row
;
626 *column
= location
->column
;
633 mono_debug_free_source_location (location
);
640 MonoSecurityFrame
*frame
;
641 } MonoFrameSecurityInfo
;
644 callback_get_first_frame_security_info (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
646 MonoFrameSecurityInfo
*si
= (MonoFrameSecurityInfo
*) data
;
648 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
649 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
650 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
651 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
652 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
653 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
) {
662 si
->frame
= mono_declsec_create_frame (domain
, ji
);
664 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
669 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
670 * @skip: the number of stack frames to skip
672 * This function returns a the security informations of a single stack frame
673 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
674 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
678 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip
)
680 MonoDomain
*domain
= mono_domain_get ();
681 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
682 MonoFrameSecurityInfo si
;
685 MONO_ARCH_CONTEXT_DEF
687 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
688 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
690 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_System_Security_SecurityFrame_GetSecurityFrame
);
693 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
699 mono_walk_stack (domain
, jit_tls
, &ctx
, callback_get_first_frame_security_info
, (gpointer
)&si
);
701 return (si
.skips
== 0) ? si
.frame
: NULL
;
713 grow_array (MonoSecurityStack
*stack
)
715 MonoDomain
*domain
= mono_domain_get ();
716 guint32 newsize
= (stack
->maximum
<< 1);
717 MonoArray
*newstack
= mono_array_new (domain
, mono_defaults
.runtimesecurityframe_class
, newsize
);
719 for (i
=0; i
< stack
->maximum
; i
++) {
720 gpointer frame
= mono_array_get (stack
->stack
, gpointer
, i
);
721 mono_array_setref (newstack
, i
, frame
);
723 stack
->maximum
= newsize
;
724 stack
->stack
= newstack
;
728 callback_get_stack_frames_security_info (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
730 MonoSecurityStack
*ss
= (MonoSecurityStack
*) data
;
732 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
733 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
734 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
735 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
736 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
737 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
) {
746 if (ss
->count
== ss
->maximum
)
749 mono_array_setref (ss
->stack
, ss
->count
++, mono_declsec_create_frame (domain
, ji
));
751 /* continue down the stack */
756 glist_to_array (GList
*list
, MonoClass
*eclass
)
758 MonoDomain
*domain
= mono_domain_get ();
765 len
= g_list_length (list
);
766 res
= mono_array_new (domain
, eclass
, len
);
768 for (i
= 0; list
; list
= list
->next
, i
++)
769 mono_array_set (res
, gpointer
, i
, list
->data
);
775 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
776 * @skip: the number of stack frames to skip
778 * This function returns an managed array of containing the security
779 * informations for each frame (after the skipped ones). This is used for
780 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
784 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip
)
786 MonoDomain
*domain
= mono_domain_get ();
787 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
788 MonoSecurityStack ss
;
791 MONO_ARCH_CONTEXT_DEF
793 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
794 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
796 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_System_Security_SecurityFrame_GetSecurityStack
);
799 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
805 ss
.maximum
= MONO_CAS_INITIAL_STACK_SIZE
;
806 ss
.stack
= mono_array_new (domain
, mono_defaults
.runtimesecurityframe_class
, ss
.maximum
);
807 mono_walk_stack (domain
, jit_tls
, &ctx
, callback_get_stack_frames_security_info
, (gpointer
)&ss
);
808 /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
813 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
815 MonoClass
*catch_class
= ei
->data
.catch_class
;
816 MonoType
*inflated_type
;
817 MonoGenericContext context
;
822 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
824 context
= get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
826 /* FIXME: we shouldn't inflate but instead put the
827 type in the rgctx and fetch it from there. It
828 might be a good idea to do this lazily, i.e. only
829 when the exception is actually thrown, so as not to
830 waste space for exception clauses which might never
832 inflated_type
= mono_class_inflate_generic_type (&catch_class
->byval_arg
, &context
);
833 catch_class
= mono_class_from_mono_type (inflated_type
);
834 mono_metadata_free_type (inflated_type
);
840 * mono_handle_exception_internal:
841 * @ctx: saved processor state
842 * @obj: the exception object
843 * @test_only: only test if the exception is caught, but dont call handlers
844 * @out_filter_idx: out parameter. if test_only is true, set to the index of
845 * the first filter clause which caught the exception.
848 mono_handle_exception_internal (MonoContext
*ctx
, gpointer obj
, gpointer original_ip
, gboolean test_only
, gint32
*out_filter_idx
)
850 MonoDomain
*domain
= mono_domain_get ();
851 MonoJitInfo
*ji
, rji
;
852 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
853 static void (*restore_context
) (void *);
854 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
855 MonoLMF
*lmf
= mono_get_lmf ();
856 MonoArray
*initial_trace_ips
= NULL
;
857 GList
*trace_ips
= NULL
;
858 MonoException
*mono_ex
;
859 gboolean stack_overflow
= FALSE
;
860 MonoContext initial_ctx
;
862 gboolean has_dynamic_methods
= FALSE
;
863 gint32 filter_idx
, first_filter_idx
;
865 g_assert (ctx
!= NULL
);
867 MonoException
*ex
= mono_get_exception_null_reference ();
868 MONO_OBJECT_SETREF (ex
, message
, mono_string_new (domain
, "Object reference not set to an instance of an object"));
869 obj
= (MonoObject
*)ex
;
873 * Allocate a new exception object instead of the preconstructed ones.
875 if (obj
== domain
->stack_overflow_ex
) {
877 * It is not a good idea to try and put even more pressure on the little stack available.
878 * obj = mono_get_exception_stack_overflow ();
880 stack_overflow
= TRUE
;
882 else if (obj
== domain
->null_reference_ex
) {
883 obj
= mono_get_exception_null_reference ();
886 if (mono_object_isinst (obj
, mono_defaults
.exception_class
)) {
887 mono_ex
= (MonoException
*)obj
;
888 initial_trace_ips
= mono_ex
->trace_ips
;
893 if (mono_ex
&& jit_tls
->class_cast_from
&& !strcmp (mono_ex
->object
.vtable
->klass
->name
, "InvalidCastException")) {
894 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
895 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
896 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
897 mono_ex
->message
= mono_string_new (domain
, msg
);
904 call_filter
= mono_get_call_filter ();
906 if (!restore_context
)
907 restore_context
= mono_get_restore_context ();
909 g_assert (jit_tls
->end_of_stack
);
910 g_assert (jit_tls
->abort_func
);
913 MonoContext ctx_cp
= *ctx
;
914 if (mono_trace_is_enabled ())
915 g_print ("EXCEPTION handling: %s\n", mono_object_class (obj
)->name
);
916 mono_profiler_exception_thrown (obj
);
917 if (!mono_handle_exception_internal (&ctx_cp
, obj
, original_ip
, TRUE
, &first_filter_idx
)) {
918 if (mono_break_on_exc
)
920 // FIXME: This runs managed code so it might cause another stack overflow when
921 // we are handling a stack overflow
922 mono_unhandled_exception (obj
);
927 *out_filter_idx
= -1;
930 memset (&rji
, 0, sizeof (rji
));
936 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, &rji
, ctx
, &new_ctx
,
937 NULL
, &lmf
, NULL
, NULL
);
939 g_warning ("Exception inside function without unwind info");
940 g_assert_not_reached ();
943 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
))))) {
945 * The exception was raised in native code and we got back to managed code
952 if (ji
!= (gpointer
)-1) {
954 //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
956 if (test_only
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
958 * Avoid overwriting the stack trace if the exception is
959 * rethrown. Also avoid giant stack traces during a stack
962 if (!initial_trace_ips
&& (frame_count
< 1000)) {
963 trace_ips
= g_list_prepend (trace_ips
, MONO_CONTEXT_GET_IP (ctx
));
964 trace_ips
= g_list_prepend (trace_ips
,
965 get_generic_info_from_stack_frame (ji
, ctx
));
969 if (ji
->method
->dynamic
)
970 has_dynamic_methods
= TRUE
;
973 #ifndef MONO_ARCH_STACK_GROWS_UP
974 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
976 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (ctx
));
979 free_stack
= 0xffffff;
982 * During stack overflow, wait till the unwinding frees some stack
983 * space before running handlers/finalizers.
985 if ((free_stack
> (64 * 1024)) && ji
->num_clauses
) {
988 for (i
= 0; i
< ji
->num_clauses
; i
++) {
989 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
990 gboolean filtered
= FALSE
;
992 #if defined(__s390__)
994 * This is required in cases where a try block starts immediately after
995 * a call which causes an exception. Testcase: tests/exception8.cs.
996 * FIXME: Clean this up.
998 if (ei
->try_start
< MONO_CONTEXT_GET_IP (ctx
) &&
1000 if (ei
->try_start
<= MONO_CONTEXT_GET_IP (ctx
) &&
1002 MONO_CONTEXT_GET_IP (ctx
) <= ei
->try_end
) {
1004 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
1006 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
)) {
1007 /* store the exception object in bp + ei->exvar_offset */
1008 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = obj
;
1011 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
1012 // mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
1014 mono_perfcounters
->exceptions_filters
++;
1015 filtered
= call_filter (ctx
, ei
->data
.filter
);
1016 if (filtered
&& out_filter_idx
)
1017 *out_filter_idx
= filter_idx
;
1021 * Filter clauses should only be run in the
1022 * first pass of exception handling.
1024 filtered
= (filter_idx
== first_filter_idx
);
1029 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
1030 mono_object_isinst (obj
, catch_class
)) || filtered
) {
1032 if (mono_ex
&& !initial_trace_ips
) {
1033 trace_ips
= g_list_reverse (trace_ips
);
1034 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, glist_to_array (trace_ips
, mono_defaults
.int_class
));
1035 if (has_dynamic_methods
)
1036 /* These methods could go away anytime, so compute the stack trace now */
1037 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, ves_icall_System_Exception_get_trace (mono_ex
));
1039 g_list_free (trace_ips
);
1043 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1044 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1045 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1046 mono_debugger_call_exception_handler (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1047 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
1048 *(mono_get_lmf_addr ()) = lmf
;
1049 mono_perfcounters
->exceptions_depth
+= frame_count
;
1050 if (obj
== domain
->stack_overflow_ex
)
1051 jit_tls
->handling_stack_ovf
= FALSE
;
1055 if (!test_only
&& ei
->try_start
<= MONO_CONTEXT_GET_IP (ctx
) &&
1056 MONO_CONTEXT_GET_IP (ctx
) < ei
->try_end
&&
1057 (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
)) {
1058 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1059 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1060 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1061 mono_debugger_call_exception_handler (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1062 call_filter (ctx
, ei
->handler_start
);
1064 if (!test_only
&& ei
->try_start
<= MONO_CONTEXT_GET_IP (ctx
) &&
1065 MONO_CONTEXT_GET_IP (ctx
) < ei
->try_end
&&
1066 (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
)) {
1067 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1068 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1069 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1070 mono_debugger_call_exception_handler (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1071 mono_perfcounters
->exceptions_finallys
++;
1072 call_filter (ctx
, ei
->handler_start
);
1079 mono_profiler_exception_method_leave (ji
->method
);
1084 if (ji
== (gpointer
)-1) {
1087 *(mono_get_lmf_addr ()) = lmf
;
1089 jit_tls
->abort_func (obj
);
1090 g_assert_not_reached ();
1092 if (mono_ex
&& !initial_trace_ips
) {
1093 trace_ips
= g_list_reverse (trace_ips
);
1094 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, glist_to_array (trace_ips
, mono_defaults
.int_class
));
1095 if (has_dynamic_methods
)
1096 /* These methods could go away anytime, so compute the stack trace now */
1097 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, ves_icall_System_Exception_get_trace (mono_ex
));
1099 g_list_free (trace_ips
);
1105 g_assert_not_reached ();
1109 * mono_debugger_run_finally:
1110 * @start_ctx: saved processor state
1112 * This method is called by the Mono Debugger to call all `finally' clauses of the
1113 * current stack frame. It's used when the user issues a `return' command to make
1114 * the current stack frame return. After returning from this method, the debugger
1115 * unwinds the stack one frame and gives control back to the user.
1117 * NOTE: This method is only used when running inside the Mono Debugger.
1120 mono_debugger_run_finally (MonoContext
*start_ctx
)
1122 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
1123 MonoDomain
*domain
= mono_domain_get ();
1124 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1125 MonoLMF
*lmf
= mono_get_lmf ();
1126 MonoContext ctx
, new_ctx
;
1127 MonoJitInfo
*ji
, rji
;
1132 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
1133 if (!ji
|| ji
== (gpointer
)-1)
1137 call_filter
= mono_get_call_filter ();
1139 for (i
= 0; i
< ji
->num_clauses
; i
++) {
1140 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
1142 if ((ei
->try_start
<= MONO_CONTEXT_GET_IP (&ctx
)) &&
1143 (MONO_CONTEXT_GET_IP (&ctx
) < ei
->try_end
) &&
1144 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
1145 call_filter (&ctx
, ei
->handler_start
);
1151 * mono_handle_exception:
1152 * @ctx: saved processor state
1153 * @obj: the exception object
1154 * @test_only: only test if the exception is caught, but dont call handlers
1157 mono_handle_exception (MonoContext
*ctx
, gpointer obj
, gpointer original_ip
, gboolean test_only
)
1160 mono_perfcounters
->exceptions_thrown
++;
1161 return mono_handle_exception_internal (ctx
, obj
, original_ip
, test_only
, NULL
);
1164 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1166 #ifndef MONO_ARCH_USE_SIGACTION
1167 #error "Can't use sigaltstack without sigaction"
1170 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1173 mono_setup_altstack (MonoJitTlsData
*tls
)
1176 struct sigaltstack sa
;
1177 guint8
*staddr
= NULL
;
1179 if (mono_running_on_valgrind ())
1182 mono_thread_get_stack_bounds (&staddr
, &stsize
);
1186 tls
->end_of_stack
= staddr
+ stsize
;
1188 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1190 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
1191 tls
->stack_ovf_guard_size
= ALIGN_TO (8 * 4096, mono_pagesize ());
1193 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
1194 /* mprotect can fail for the main thread stack */
1195 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
);
1196 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
1200 * threads created by nptl does not seem to have a guard page, and
1201 * since the main thread is not created by us, we can't even set one.
1202 * Increasing stsize fools the SIGSEGV signal handler into thinking this
1203 * is a stack overflow exception.
1205 tls
->stack_size
= stsize
+ mono_pagesize ();
1207 /* Setup an alternate signal stack */
1208 tls
->signal_stack
= mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MMAP_READ
|MONO_MMAP_WRITE
|MONO_MMAP_PRIVATE
|MONO_MMAP_ANON
);
1209 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1211 g_assert (tls
->signal_stack
);
1213 sa
.ss_sp
= tls
->signal_stack
;
1214 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1215 sa
.ss_flags
= SS_ONSTACK
;
1216 sigaltstack (&sa
, NULL
);
1220 mono_free_altstack (MonoJitTlsData
*tls
)
1222 struct sigaltstack sa
;
1225 sa
.ss_sp
= tls
->signal_stack
;
1226 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1227 sa
.ss_flags
= SS_DISABLE
;
1228 err
= sigaltstack (&sa
, NULL
);
1229 g_assert (err
== 0);
1231 if (tls
->signal_stack
)
1232 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
);
1235 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1238 mono_setup_altstack (MonoJitTlsData
*tls
)
1243 mono_free_altstack (MonoJitTlsData
*tls
)
1247 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1250 try_restore_stack_protection (MonoJitTlsData
*jit_tls
, int extra_bytes
)
1252 gint32 unprotect_size
= jit_tls
->stack_ovf_guard_size
;
1253 /* we need to leave some room for throwing the exception */
1254 while (unprotect_size
>= 0 && (char*)jit_tls
->stack_ovf_guard_base
+ unprotect_size
> ((char*)&unprotect_size
- extra_bytes
))
1255 unprotect_size
-= mono_pagesize ();
1256 /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1257 * is sufficient stack
1259 //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);
1261 mono_mprotect (jit_tls
->stack_ovf_guard_base
, unprotect_size
, MONO_MMAP_NONE
);
1262 return unprotect_size
== jit_tls
->stack_ovf_guard_size
;
1266 try_more_restore (void)
1268 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1269 if (try_restore_stack_protection (jit_tls
, 500))
1270 jit_tls
->restore_stack_prot
= NULL
;
1274 restore_stack_protection (void)
1276 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1277 MonoException
*ex
= mono_domain_get ()->stack_overflow_ex
;
1278 /* if we can't restore the stack protection, keep a callback installed so
1279 * we'll try to restore as much stack as we can at each return from unmanaged
1282 if (try_restore_stack_protection (jit_tls
, 4096))
1283 jit_tls
->restore_stack_prot
= NULL
;
1285 jit_tls
->restore_stack_prot
= try_more_restore_tramp
;
1286 /* here we also throw a stack overflow exception */
1287 ex
->trace_ips
= NULL
;
1288 ex
->stack_trace
= NULL
;
1289 mono_raise_exception (ex
);
1293 mono_altstack_restore_prot (gssize
*regs
, guint8
*code
, gpointer
*tramp_data
, guint8
* tramp
)
1295 void (*func
)(void) = (gpointer
)tramp_data
;
1301 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, guint8
* fault_addr
)
1303 /* we got a stack overflow in the soft-guard pages
1304 * There are two cases:
1305 * 1) managed code caused the overflow: we unprotect the soft-guard page
1306 * and let the arch-specific code trigger the exception handling mechanism
1307 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1308 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1309 * and hope we can continue with those enabled, at least until the hard-guard page
1310 * is hit. The alternative to continuing here is to just print a message and abort.
1311 * We may add in the future the code to protect the pages again in the codepath
1312 * when we return from unmanaged to managed code.
1314 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
1315 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
1316 /* we unprotect the minimum amount we can */
1318 gboolean handled
= FALSE
;
1320 guard_size
= jit_tls
->stack_ovf_guard_size
- (mono_pagesize () * SIZEOF_VOID_P
/ 4);
1321 while (guard_size
&& fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ guard_size
) {
1322 guard_size
-= mono_pagesize ();
1324 guard_size
= jit_tls
->stack_ovf_guard_size
- guard_size
;
1325 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
1326 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
);
1327 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1329 mono_arch_handle_altstack_exception (ctx
, fault_addr
, TRUE
);
1334 /* We print a message: after this even managed stack overflows
1335 * may crash the runtime
1337 fprintf (stderr
, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx
), fault_addr
);
1338 if (!jit_tls
->handling_stack_ovf
) {
1339 jit_tls
->restore_stack_prot
= restore_stack_protection_tramp
;
1340 jit_tls
->handling_stack_ovf
= 1;
1342 /*fprintf (stderr, "Already handling stack overflow\n");*/
1351 print_stack_frame (MonoMethod
*method
, gint32 native_offset
, gint32 il_offset
, gboolean managed
, gpointer data
)
1353 FILE *stream
= (FILE*)data
;
1356 gchar
*location
= mono_debug_print_stack_frame (method
, native_offset
, mono_domain_get ());
1357 fprintf (stream
, " %s\n", location
);
1360 fprintf (stream
, " at <unknown> <0x%05x>\n", native_offset
);
1365 static G_GNUC_UNUSED gboolean
1366 print_stack_frame_to_string (MonoMethod
*method
, gint32 native_offset
, gint32 il_offset
, gboolean managed
,
1369 GString
*p
= (GString
*)data
;
1372 gchar
*location
= mono_debug_print_stack_frame (method
, native_offset
, mono_domain_get ());
1373 g_string_append_printf (p
, " %s\n", location
);
1376 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", native_offset
);
1381 static gboolean handling_sigsegv
= FALSE
;
1384 * mono_handle_native_sigsegv:
1386 * Handle a SIGSEGV received while in native code by printing diagnostic
1387 * information and aborting.
1390 mono_handle_native_sigsegv (int signal
, void *ctx
)
1392 #ifdef MONO_ARCH_USE_SIGACTION
1393 struct sigaction sa
;
1395 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1397 if (handling_sigsegv
)
1400 if (mini_get_debug_options ()->suspend_on_sigsegv
) {
1401 fprintf (stderr
, "Received SIGSEGV, suspending...");
1406 /* To prevent infinite loops when the stack walk causes a crash */
1407 handling_sigsegv
= TRUE
;
1409 /* !jit_tls means the thread was not registered with the runtime */
1411 fprintf (stderr
, "Stacktrace:\n\n");
1413 mono_jit_walk_stack (print_stack_frame
, TRUE
, stderr
);
1418 #ifdef HAVE_BACKTRACE_SYMBOLS
1423 const char *signal_str
= (signal
== SIGSEGV
) ? "SIGSEGV" : "SIGABRT";
1425 fprintf (stderr
, "\nNative stacktrace:\n\n");
1427 size
= backtrace (array
, 256);
1428 names
= backtrace_symbols (array
, size
);
1429 for (i
=0; i
< size
; ++i
) {
1430 fprintf (stderr
, "\t%s\n", names
[i
]);
1436 /* Try to get more meaningful information using gdb */
1438 #if !defined(PLATFORM_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
1439 if (!mini_get_debug_options ()->no_gdb_backtrace
&& !mono_debug_using_mono_debugger ()) {
1440 /* From g_spawn_command_line_sync () in eglib */
1442 int stdout_pipe
[2] = { -1, -1 };
1444 const char *argv
[16];
1449 res
= pipe (stdout_pipe
);
1450 g_assert (res
!= -1);
1454 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1455 * it will deadlock. Call the syscall directly instead.
1457 pid
= syscall (SYS_fork
);
1459 close (stdout_pipe
[0]);
1460 dup2 (stdout_pipe
[1], STDOUT_FILENO
);
1462 for (i
= getdtablesize () - 1; i
>= 3; i
--)
1465 argv
[0] = g_find_program_in_path ("gdb");
1466 if (argv
[0] == NULL
) {
1467 close (STDOUT_FILENO
);
1472 sprintf (buf1
, "attach %ld", (long)getpid ());
1475 argv
[4] = "info threads";
1477 argv
[6] = "thread apply all bt";
1478 argv
[7] = "--batch";
1481 execv (argv
[0], (char**)argv
);
1485 close (stdout_pipe
[1]);
1487 fprintf (stderr
, "\nDebug info from gdb:\n\n");
1490 int nread
= read (stdout_pipe
[0], buffer
, 1024);
1494 write (STDERR_FILENO
, buffer
, nread
);
1497 waitpid (pid
, &status
, WNOHANG
);
1501 * A SIGSEGV indicates something went very wrong so we can no longer depend
1502 * on anything working. So try to print out lots of diagnostics, starting
1503 * with ones which have a greater chance of working.
1507 "=================================================================\n"
1508 "Got a %s while executing native code. This usually indicates\n"
1509 "a fatal error in the mono runtime or one of the native libraries \n"
1510 "used by your application.\n"
1511 "=================================================================\n"
1517 #ifdef MONO_ARCH_USE_SIGACTION
1519 /* Remove our SIGABRT handler */
1520 sa
.sa_handler
= SIG_DFL
;
1521 sigemptyset (&sa
.sa_mask
);
1524 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
1532 * mono_print_thread_dump:
1534 * Print information about the current thread to stdout.
1535 * SIGCTX can be NULL, allowing this to be called from gdb.
1538 mono_print_thread_dump (void *sigctx
)
1540 MonoThread
*thread
= mono_thread_current ();
1541 #if defined(__i386__) || defined(__x86_64__)
1544 GString
* text
= g_string_new (0);
1545 char *name
, *wapi_desc
;
1546 GError
*error
= NULL
;
1549 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &error
);
1551 g_string_append_printf (text
, "\n\"%s\"", name
);
1554 else if (thread
->threadpool_thread
)
1555 g_string_append (text
, "\n\"<threadpool thread>\"");
1557 g_string_append (text
, "\n\"<unnamed thread>\"");
1559 #ifndef PLATFORM_WIN32
1560 wapi_desc
= wapi_current_thread_desc ();
1561 g_string_append_printf (text
, " tid=0x%p this=0x%p %s\n", (gpointer
)(gsize
)thread
->tid
, thread
, wapi_desc
);
1565 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
1567 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
1569 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
1571 mono_jit_walk_stack_from_ctx (print_stack_frame_to_string
, &ctx
, TRUE
, text
);
1573 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
1576 fprintf (stdout
, text
->str
);
1577 g_string_free (text
, TRUE
);