2 * mini-exceptions.c: generic exception support
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
15 #ifdef HAVE_EXECINFO_H
19 #ifndef PLATFORM_WIN32
20 #include <sys/types.h>
29 #ifdef HAVE_SYS_SYSCALL_H
30 #include <sys/syscall.h>
33 #include <mono/metadata/appdomain.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/debug-helpers.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/gc-internal.h>
40 #include <mono/metadata/mono-debug.h>
41 #include <mono/metadata/profiler.h>
42 #include <mono/utils/mono-mmap.h>
47 #ifndef MONO_ARCH_CONTEXT_DEF
48 #define MONO_ARCH_CONTEXT_DEF
51 static gpointer restore_context_func
, call_filter_func
;
52 static gpointer throw_exception_func
, rethrow_exception_func
;
53 static gpointer throw_exception_by_name_func
, throw_corlib_exception_func
;
55 static gpointer try_more_restore_tramp
= NULL
;
56 static gpointer restore_stack_protection_tramp
= NULL
;
58 static void try_more_restore (void);
59 static void restore_stack_protection (void);
62 mono_exceptions_init (void)
64 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
69 restore_context_func
= mono_aot_get_named_code ("restore_context");
70 call_filter_func
= mono_aot_get_named_code ("call_filter");
71 throw_exception_func
= mono_aot_get_named_code ("throw_exception");
72 rethrow_exception_func
= mono_aot_get_named_code ("rethrow_exception");
74 restore_context_func
= mono_arch_get_restore_context_full (&code_size
, &ji
, FALSE
);
75 call_filter_func
= mono_arch_get_call_filter_full (&code_size
, &ji
, FALSE
);
76 throw_exception_func
= mono_arch_get_throw_exception_full (&code_size
, &ji
, FALSE
);
77 rethrow_exception_func
= mono_arch_get_rethrow_exception_full (&code_size
, &ji
, FALSE
);
80 restore_context_func
= mono_arch_get_restore_context ();
81 call_filter_func
= mono_arch_get_call_filter ();
82 throw_exception_func
= mono_arch_get_throw_exception ();
83 rethrow_exception_func
= mono_arch_get_rethrow_exception ();
85 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
86 try_more_restore_tramp
= mono_create_specific_trampoline (try_more_restore
, MONO_TRAMPOLINE_RESTORE_STACK_PROT
, mono_domain_get (), NULL
);
87 restore_stack_protection_tramp
= mono_create_specific_trampoline (restore_stack_protection
, MONO_TRAMPOLINE_RESTORE_STACK_PROT
, mono_domain_get (), NULL
);
92 mono_get_throw_exception (void)
94 g_assert (throw_exception_func
);
95 return throw_exception_func
;
99 mono_get_rethrow_exception (void)
101 g_assert (rethrow_exception_func
);
102 return rethrow_exception_func
;
106 mono_get_call_filter (void)
108 g_assert (call_filter_func
);
109 return call_filter_func
;
113 mono_get_restore_context (void)
115 g_assert (restore_context_func
);
116 return restore_context_func
;
120 mono_get_throw_exception_by_name (void)
122 gpointer code
= NULL
;
123 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
128 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
129 if (throw_exception_by_name_func
)
130 return throw_exception_by_name_func
;
132 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
134 code
= mono_aot_get_named_code ("throw_exception_by_name");
136 code
= mono_arch_get_throw_exception_by_name_full (&code_size
, &ji
, FALSE
);
138 code
= mono_arch_get_throw_exception_by_name ();
141 mono_memory_barrier ();
143 throw_exception_by_name_func
= code
;
145 return throw_exception_by_name_func
;
149 mono_get_throw_corlib_exception (void)
151 gpointer code
= NULL
;
152 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
157 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
158 if (throw_corlib_exception_func
)
159 return throw_corlib_exception_func
;
161 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
162 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
164 code
= mono_aot_get_named_code ("throw_corlib_exception");
166 code
= mono_arch_get_throw_corlib_exception_full (&code_size
, &ji
, FALSE
);
168 code
= mono_arch_get_throw_corlib_exception ();
171 g_assert_not_reached ();
174 mono_memory_barrier ();
176 throw_corlib_exception_func
= code
;
178 return throw_corlib_exception_func
;
181 /* mono_find_jit_info:
183 * This function is used to gather information from @ctx. It return the
184 * MonoJitInfo of the corresponding function, unwinds one stack frame and
185 * stores the resulting context into @new_ctx. It also stores a string
186 * describing the stack location into @trace (if not NULL), and modifies
187 * the @lmf if necessary. @native_offset return the IP offset from the
188 * start of the function or -1 if that info is not available.
191 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
192 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
196 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
208 ji
= mono_arch_find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, lmf
, &managed2
);
210 if (ji
== (gpointer
)-1)
213 if (managed2
|| ji
->method
->wrapper_type
) {
214 const char *real_ip
, *start
;
217 start
= (const char *)ji
->code_start
;
219 /* ctx->ip points into native code */
220 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
222 real_ip
= (const char*)ip
;
224 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
225 offset
= real_ip
- start
;
230 *native_offset
= offset
;
233 if (!ji
->method
->wrapper_type
)
237 *trace
= mono_debug_print_stack_frame (ji
->method
, offset
, domain
);
240 char *fname
= mono_method_full_name (res
->method
, TRUE
);
241 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
250 get_generic_info_from_stack_frame (MonoJitInfo
*ji
, MonoContext
*ctx
)
252 MonoGenericJitInfo
*gi
;
254 if (!ji
->has_generic_jit_info
)
256 gi
= mono_jit_info_get_generic_jit_info (ji
);
261 return mono_arch_context_get_int_reg (ctx
, gi
->this_reg
);
263 return *(gpointer
*)(gpointer
)((char*)mono_arch_context_get_int_reg (ctx
, gi
->this_reg
) +
267 static MonoGenericContext
268 get_generic_context_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
270 MonoGenericContext context
= { NULL
, NULL
};
271 MonoClass
*class, *method_container_class
;
273 g_assert (generic_info
);
275 g_assert (ji
->method
->is_inflated
);
276 if (mono_method_get_context (ji
->method
)->method_inst
) {
277 MonoMethodRuntimeGenericContext
*mrgctx
= generic_info
;
279 class = mrgctx
->class_vtable
->klass
;
280 context
.method_inst
= mrgctx
->method_inst
;
281 g_assert (context
.method_inst
);
282 } else if ((ji
->method
->flags
& METHOD_ATTRIBUTE_STATIC
) || ji
->method
->klass
->valuetype
) {
283 MonoVTable
*vtable
= generic_info
;
285 class = vtable
->klass
;
287 MonoObject
*this = generic_info
;
289 class = this->vtable
->klass
;
292 if (class->generic_class
|| class->generic_container
)
293 context
.class_inst
= mini_class_get_context (class)->class_inst
;
295 g_assert (!ji
->method
->klass
->generic_container
);
296 if (ji
->method
->klass
->generic_class
)
297 method_container_class
= ji
->method
->klass
->generic_class
->container_class
;
299 method_container_class
= ji
->method
->klass
;
301 if (class->generic_class
)
302 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class
->container_class
, method_container_class
));
304 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class
));
310 get_method_from_stack_frame (MonoJitInfo
*ji
, gpointer generic_info
)
312 MonoGenericContext context
;
315 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
317 context
= get_generic_context_from_stack_frame (ji
, generic_info
);
319 method
= mono_method_get_declaring_generic_method (ji
->method
);
320 method
= mono_class_inflate_generic_method (method
, &context
);
326 ves_icall_System_Exception_get_trace (MonoException
*ex
)
328 MonoDomain
*domain
= mono_domain_get ();
330 MonoArray
*ta
= ex
->trace_ips
;
335 /* Exception is not thrown yet */
338 len
= mono_array_length (ta
) >> 1;
339 trace_str
= g_string_new ("");
340 for (i
= 0; i
< len
; i
++) {
342 gpointer ip
= mono_array_get (ta
, gpointer
, i
* 2 + 0);
343 gpointer generic_info
= mono_array_get (ta
, gpointer
, i
* 2 + 1);
345 ji
= mono_jit_info_table_find (domain
, ip
);
347 /* Unmanaged frame */
348 g_string_append_printf (trace_str
, "in (unmanaged) %p\n", ip
);
352 MonoMethod
*method
= get_method_from_stack_frame (ji
, generic_info
);
354 address
= (char *)ip
- (char *)ji
->code_start
;
355 location
= mono_debug_print_stack_frame (
356 method
, address
, ex
->object
.vtable
->domain
);
358 g_string_append_printf (trace_str
, "%s\n", location
);
363 res
= mono_string_new (ex
->object
.vtable
->domain
, trace_str
->str
);
364 g_string_free (trace_str
, TRUE
);
370 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
372 MonoDomain
*domain
= mono_domain_get ();
374 MonoArray
*ta
= exc
->trace_ips
;
375 MonoDebugSourceLocation
*location
;
379 /* Exception is not thrown yet */
380 return mono_array_new (domain
, mono_defaults
.stack_frame_class
, 0);
383 len
= mono_array_length (ta
) >> 1;
385 res
= mono_array_new (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0);
387 for (i
= skip
; i
< len
; i
++) {
389 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new (domain
, mono_defaults
.stack_frame_class
);
390 gpointer ip
= mono_array_get (ta
, gpointer
, i
* 2 + 0);
391 gpointer generic_info
= mono_array_get (ta
, gpointer
, i
* 2 + 1);
394 ji
= mono_jit_info_table_find (domain
, ip
);
396 /* Unmanaged frame */
397 mono_array_setref (res
, i
, sf
);
401 g_assert (ji
!= NULL
);
403 method
= get_method_from_stack_frame (ji
, generic_info
);
404 if (ji
->method
->wrapper_type
) {
408 s
= mono_method_full_name (method
, TRUE
);
409 MONO_OBJECT_SETREF (sf
, internal_method_name
, mono_string_new (domain
, s
));
413 MONO_OBJECT_SETREF (sf
, method
, mono_method_get_object (domain
, method
, NULL
));
414 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
417 * mono_debug_lookup_source_location() returns both the file / line number information
418 * and the IL offset. Note that computing the IL offset is already an expensive
419 * operation, so we shouldn't call this method twice.
421 location
= mono_debug_lookup_source_location (ji
->method
, sf
->native_offset
, domain
);
423 sf
->il_offset
= location
->il_offset
;
427 if (need_file_info
) {
428 if (location
&& location
->source_file
) {
429 MONO_OBJECT_SETREF (sf
, filename
, mono_string_new (domain
, location
->source_file
));
430 sf
->line
= location
->row
;
431 sf
->column
= location
->column
;
433 sf
->line
= sf
->column
= 0;
438 mono_debug_free_source_location (location
);
439 mono_array_setref (res
, i
, sf
);
447 * @domain: starting appdomain
448 * @jit_tls: JIT data for the thread
449 * @start_ctx: starting state of the stack frame
450 * @func: callback to call for each stack frame
451 * @user_data: data passed to the callback
453 * This function walks the stack of a thread, starting from the state
454 * represented by jit_tls and start_ctx. For each frame the callback
455 * function is called with the relevant info. The walk ends when no more
456 * managed stack frames are found or when the callback returns a TRUE value.
457 * Note that the function can be used to walk the stack of a thread
458 * different from the current.
461 mono_walk_stack (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoContext
*start_ctx
, MonoStackFrameWalk func
, gpointer user_data
)
463 MonoLMF
*lmf
= mono_get_lmf ();
464 MonoJitInfo
*ji
, rji
;
467 MonoContext ctx
, new_ctx
;
471 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
473 * FIXME: mono_find_jit_info () will need to be able to return a different
474 * MonoDomain when apddomain transitions are found on the stack.
476 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
477 if (!ji
|| ji
== (gpointer
)-1)
480 if (func (domain
, &new_ctx
, ji
, user_data
))
488 mono_jit_walk_stack_from_ctx (MonoStackWalk func
, MonoContext
*start_ctx
, gboolean do_il_offset
, gpointer user_data
)
490 MonoDomain
*domain
= mono_domain_get ();
491 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
492 MonoLMF
*lmf
= mono_get_lmf ();
493 MonoJitInfo
*ji
, rji
;
494 gint native_offset
, il_offset
;
496 MonoContext ctx
, new_ctx
;
498 MONO_ARCH_CONTEXT_DEF
500 mono_arch_flush_register_windows ();
503 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
505 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
506 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
508 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_jit_walk_stack_from_ctx
);
512 while (MONO_CONTEXT_GET_SP (&ctx
) < jit_tls
->end_of_stack
) {
513 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
516 if (ji
== (gpointer
)-1)
520 MonoDebugSourceLocation
*source
;
522 source
= mono_debug_lookup_source_location (ji
->method
, native_offset
, domain
);
523 il_offset
= source
? source
->il_offset
: -1;
524 mono_debug_free_source_location (source
);
528 if (func (ji
->method
, native_offset
, il_offset
, managed
, user_data
))
536 mono_jit_walk_stack (MonoStackWalk func
, gboolean do_il_offset
, gpointer user_data
)
538 mono_jit_walk_stack_from_ctx (func
, NULL
, do_il_offset
, user_data
);
542 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
543 MonoReflectionMethod
**method
,
544 gint32
*iloffset
, gint32
*native_offset
,
545 MonoString
**file
, gint32
*line
, gint32
*column
)
547 MonoDomain
*domain
= mono_domain_get ();
548 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
549 MonoLMF
*lmf
= mono_get_lmf ();
550 MonoJitInfo
*ji
, rji
;
551 MonoContext ctx
, new_ctx
, old_ctx
;
552 MonoDebugSourceLocation
*location
;
553 MonoMethod
*last_method
= NULL
, *actual_method
;
555 MONO_ARCH_CONTEXT_DEF
;
557 mono_arch_flush_register_windows ();
559 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
560 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
562 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
567 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, native_offset
, NULL
);
570 if (!ji
|| ji
== (gpointer
)-1 || MONO_CONTEXT_GET_SP (&ctx
) >= jit_tls
->end_of_stack
)
573 /* skip all wrappers ??*/
574 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
575 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
576 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
577 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
578 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
||
579 ji
->method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
)
582 if (ji
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
&& ji
->method
== last_method
) {
584 * FIXME: Native-to-managed wrappers sometimes show up twice.
585 * Probably the whole mono_find_jit_info () stuff needs to be fixed so this
591 last_method
= ji
->method
;
597 actual_method
= get_method_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, &old_ctx
));
599 *method
= mono_method_get_object (domain
, actual_method
, NULL
);
601 location
= mono_debug_lookup_source_location (ji
->method
, *native_offset
, domain
);
603 *iloffset
= location
->il_offset
;
607 if (need_file_info
) {
609 *file
= mono_string_new (domain
, location
->source_file
);
610 *line
= location
->row
;
611 *column
= location
->column
;
618 mono_debug_free_source_location (location
);
625 MonoSecurityFrame
*frame
;
626 } MonoFrameSecurityInfo
;
629 callback_get_first_frame_security_info (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
631 MonoFrameSecurityInfo
*si
= (MonoFrameSecurityInfo
*) data
;
633 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
634 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
635 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
636 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
637 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
638 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
) {
647 si
->frame
= mono_declsec_create_frame (domain
, ji
);
649 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
654 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
655 * @skip: the number of stack frames to skip
657 * This function returns a the security informations of a single stack frame
658 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
659 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
663 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip
)
665 MonoDomain
*domain
= mono_domain_get ();
666 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
667 MonoFrameSecurityInfo si
;
670 MONO_ARCH_CONTEXT_DEF
672 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
673 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
675 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_System_Security_SecurityFrame_GetSecurityFrame
);
678 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
684 mono_walk_stack (domain
, jit_tls
, &ctx
, callback_get_first_frame_security_info
, (gpointer
)&si
);
686 return (si
.skips
== 0) ? si
.frame
: NULL
;
698 grow_array (MonoSecurityStack
*stack
)
700 MonoDomain
*domain
= mono_domain_get ();
701 guint32 newsize
= (stack
->maximum
<< 1);
702 MonoArray
*newstack
= mono_array_new (domain
, mono_defaults
.runtimesecurityframe_class
, newsize
);
704 for (i
=0; i
< stack
->maximum
; i
++) {
705 gpointer frame
= mono_array_get (stack
->stack
, gpointer
, i
);
706 mono_array_setref (newstack
, i
, frame
);
708 stack
->maximum
= newsize
;
709 stack
->stack
= newstack
;
713 callback_get_stack_frames_security_info (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
715 MonoSecurityStack
*ss
= (MonoSecurityStack
*) data
;
717 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
718 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
719 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
720 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
721 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
722 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
) {
731 if (ss
->count
== ss
->maximum
)
734 mono_array_setref (ss
->stack
, ss
->count
++, mono_declsec_create_frame (domain
, ji
));
736 /* continue down the stack */
741 glist_to_array (GList
*list
, MonoClass
*eclass
)
743 MonoDomain
*domain
= mono_domain_get ();
750 len
= g_list_length (list
);
751 res
= mono_array_new (domain
, eclass
, len
);
753 for (i
= 0; list
; list
= list
->next
, i
++)
754 mono_array_set (res
, gpointer
, i
, list
->data
);
760 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
761 * @skip: the number of stack frames to skip
763 * This function returns an managed array of containing the security
764 * informations for each frame (after the skipped ones). This is used for
765 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
769 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip
)
771 MonoDomain
*domain
= mono_domain_get ();
772 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
773 MonoSecurityStack ss
;
776 MONO_ARCH_CONTEXT_DEF
778 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
779 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
781 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_System_Security_SecurityFrame_GetSecurityStack
);
784 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
790 ss
.maximum
= MONO_CAS_INITIAL_STACK_SIZE
;
791 ss
.stack
= mono_array_new (domain
, mono_defaults
.runtimesecurityframe_class
, ss
.maximum
);
792 mono_walk_stack (domain
, jit_tls
, &ctx
, callback_get_stack_frames_security_info
, (gpointer
)&ss
);
793 /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
798 get_exception_catch_class (MonoJitExceptionInfo
*ei
, MonoJitInfo
*ji
, MonoContext
*ctx
)
800 MonoClass
*catch_class
= ei
->data
.catch_class
;
801 MonoType
*inflated_type
;
802 MonoGenericContext context
;
807 if (!ji
->has_generic_jit_info
|| !mono_jit_info_get_generic_jit_info (ji
)->has_this
)
809 context
= get_generic_context_from_stack_frame (ji
, get_generic_info_from_stack_frame (ji
, ctx
));
811 /* FIXME: we shouldn't inflate but instead put the
812 type in the rgctx and fetch it from there. It
813 might be a good idea to do this lazily, i.e. only
814 when the exception is actually thrown, so as not to
815 waste space for exception clauses which might never
817 inflated_type
= mono_class_inflate_generic_type (&catch_class
->byval_arg
, &context
);
818 catch_class
= mono_class_from_mono_type (inflated_type
);
819 mono_metadata_free_type (inflated_type
);
825 * mono_handle_exception_internal:
826 * @ctx: saved processor state
827 * @obj: the exception object
828 * @test_only: only test if the exception is caught, but dont call handlers
829 * @out_filter_idx: out parameter. if test_only is true, set to the index of
830 * the first filter clause which caught the exception.
833 mono_handle_exception_internal (MonoContext
*ctx
, gpointer obj
, gpointer original_ip
, gboolean test_only
, gint32
*out_filter_idx
)
835 MonoDomain
*domain
= mono_domain_get ();
836 MonoJitInfo
*ji
, rji
;
837 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
838 static void (*restore_context
) (void *);
839 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
840 MonoLMF
*lmf
= mono_get_lmf ();
841 MonoArray
*initial_trace_ips
= NULL
;
842 GList
*trace_ips
= NULL
;
843 MonoException
*mono_ex
;
844 gboolean stack_overflow
= FALSE
;
845 MonoContext initial_ctx
;
847 gboolean has_dynamic_methods
= FALSE
;
848 gint32 filter_idx
, first_filter_idx
;
850 g_assert (ctx
!= NULL
);
852 MonoException
*ex
= mono_get_exception_null_reference ();
853 MONO_OBJECT_SETREF (ex
, message
, mono_string_new (domain
, "Object reference not set to an instance of an object"));
854 obj
= (MonoObject
*)ex
;
858 * Allocate a new exception object instead of the preconstructed ones.
860 if (obj
== domain
->stack_overflow_ex
) {
862 * It is not a good idea to try and put even more pressure on the little stack available.
863 * obj = mono_get_exception_stack_overflow ();
865 stack_overflow
= TRUE
;
867 else if (obj
== domain
->null_reference_ex
) {
868 obj
= mono_get_exception_null_reference ();
871 if (mono_object_isinst (obj
, mono_defaults
.exception_class
)) {
872 mono_ex
= (MonoException
*)obj
;
873 initial_trace_ips
= mono_ex
->trace_ips
;
878 if (mono_ex
&& jit_tls
->class_cast_from
&& !strcmp (mono_ex
->object
.vtable
->klass
->name
, "InvalidCastException")) {
879 char *from_name
= mono_type_get_full_name (jit_tls
->class_cast_from
);
880 char *to_name
= mono_type_get_full_name (jit_tls
->class_cast_to
);
881 char *msg
= g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name
, to_name
);
882 mono_ex
->message
= mono_string_new (domain
, msg
);
889 call_filter
= mono_get_call_filter ();
891 if (!restore_context
)
892 restore_context
= mono_get_restore_context ();
894 g_assert (jit_tls
->end_of_stack
);
895 g_assert (jit_tls
->abort_func
);
898 MonoContext ctx_cp
= *ctx
;
899 if (mono_trace_is_enabled ())
900 g_print ("EXCEPTION handling: %s\n", mono_object_class (obj
)->name
);
901 mono_profiler_exception_thrown (obj
);
902 if (!mono_handle_exception_internal (&ctx_cp
, obj
, original_ip
, TRUE
, &first_filter_idx
)) {
903 if (mono_break_on_exc
)
905 // FIXME: This runs managed code so it might cause another stack overflow when
906 // we are handling a stack overflow
907 mono_unhandled_exception (obj
);
909 if (mono_debugger_unhandled_exception (original_ip
, MONO_CONTEXT_GET_SP (ctx
), obj
)) {
911 * If this returns true, then we're running inside the
912 * Mono Debugger and the debugger wants us to restore the
913 * context and continue (normally, the debugger inserts
914 * a breakpoint on the `original_ip', so it regains control
915 * immediately after restoring the context).
917 MONO_CONTEXT_SET_IP (ctx
, original_ip
);
918 restore_context (ctx
);
919 g_assert_not_reached ();
925 *out_filter_idx
= -1;
928 memset (&rji
, 0, sizeof (rji
));
934 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, &rji
, ctx
, &new_ctx
,
935 NULL
, &lmf
, NULL
, NULL
);
937 g_warning ("Exception inside function without unwind info");
938 g_assert_not_reached ();
941 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
))))) {
943 * The exception was raised in native code and we got back to managed code
950 if (ji
!= (gpointer
)-1) {
952 //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
954 if (test_only
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
956 * Avoid overwriting the stack trace if the exception is
957 * rethrown. Also avoid giant stack traces during a stack
960 if (!initial_trace_ips
&& (frame_count
< 1000)) {
961 trace_ips
= g_list_prepend (trace_ips
, MONO_CONTEXT_GET_IP (ctx
));
962 trace_ips
= g_list_prepend (trace_ips
,
963 get_generic_info_from_stack_frame (ji
, ctx
));
967 if (ji
->method
->dynamic
)
968 has_dynamic_methods
= TRUE
;
971 #ifndef MONO_ARCH_STACK_GROWS_UP
972 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
));
974 free_stack
= (guint8
*)(MONO_CONTEXT_GET_SP (&initial_ctx
)) - (guint8
*)(MONO_CONTEXT_GET_SP (ctx
));
977 free_stack
= 0xffffff;
980 * During stack overflow, wait till the unwinding frees some stack
981 * space before running handlers/finalizers.
983 if ((free_stack
> (64 * 1024)) && ji
->num_clauses
) {
986 for (i
= 0; i
< ji
->num_clauses
; i
++) {
987 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
988 gboolean filtered
= FALSE
;
990 #if defined(__s390__)
992 * This is required in cases where a try block starts immediately after
993 * a call which causes an exception. Testcase: tests/exception8.cs.
994 * FIXME: Clean this up.
996 if (ei
->try_start
< MONO_CONTEXT_GET_IP (ctx
) &&
998 if (ei
->try_start
<= MONO_CONTEXT_GET_IP (ctx
) &&
1000 MONO_CONTEXT_GET_IP (ctx
) <= ei
->try_end
) {
1002 MonoClass
*catch_class
= get_exception_catch_class (ei
, ji
, ctx
);
1004 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
)) {
1005 /* store the exception object in bp + ei->exvar_offset */
1006 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = obj
;
1009 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
1010 // mono_debugger_handle_exception (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
1012 mono_perfcounters
->exceptions_filters
++;
1013 filtered
= call_filter (ctx
, ei
->data
.filter
);
1014 if (filtered
&& out_filter_idx
)
1015 *out_filter_idx
= filter_idx
;
1019 * Filter clauses should only be run in the
1020 * first pass of exception handling.
1022 filtered
= (filter_idx
== first_filter_idx
);
1027 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
1028 mono_object_isinst (obj
, catch_class
)) || filtered
) {
1030 if (mono_ex
&& !initial_trace_ips
) {
1031 trace_ips
= g_list_reverse (trace_ips
);
1032 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, glist_to_array (trace_ips
, mono_defaults
.int_class
));
1033 if (has_dynamic_methods
)
1034 /* These methods could go away anytime, so compute the stack trace now */
1035 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, ves_icall_System_Exception_get_trace (mono_ex
));
1037 g_list_free (trace_ips
);
1041 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1042 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1043 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1044 mono_debugger_handle_exception (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1045 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
1046 *(mono_get_lmf_addr ()) = lmf
;
1047 mono_perfcounters
->exceptions_depth
+= frame_count
;
1048 if (obj
== domain
->stack_overflow_ex
)
1049 jit_tls
->handling_stack_ovf
= FALSE
;
1053 if (!test_only
&& ei
->try_start
<= MONO_CONTEXT_GET_IP (ctx
) &&
1054 MONO_CONTEXT_GET_IP (ctx
) < ei
->try_end
&&
1055 (ei
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
)) {
1056 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1057 g_print ("EXCEPTION: fault clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1058 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1059 mono_debugger_handle_exception (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1060 call_filter (ctx
, ei
->handler_start
);
1062 if (!test_only
&& ei
->try_start
<= MONO_CONTEXT_GET_IP (ctx
) &&
1063 MONO_CONTEXT_GET_IP (ctx
) < ei
->try_end
&&
1064 (ei
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
)) {
1065 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
1066 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
1067 mono_profiler_exception_clause_handler (ji
->method
, ei
->flags
, i
);
1068 mono_debugger_handle_exception (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
1069 mono_perfcounters
->exceptions_finallys
++;
1070 call_filter (ctx
, ei
->handler_start
);
1077 mono_profiler_exception_method_leave (ji
->method
);
1082 if (ji
== (gpointer
)-1) {
1085 *(mono_get_lmf_addr ()) = lmf
;
1087 jit_tls
->abort_func (obj
);
1088 g_assert_not_reached ();
1090 if (mono_ex
&& !initial_trace_ips
) {
1091 trace_ips
= g_list_reverse (trace_ips
);
1092 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, glist_to_array (trace_ips
, mono_defaults
.int_class
));
1093 if (has_dynamic_methods
)
1094 /* These methods could go away anytime, so compute the stack trace now */
1095 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, ves_icall_System_Exception_get_trace (mono_ex
));
1097 g_list_free (trace_ips
);
1103 g_assert_not_reached ();
1107 * mono_debugger_run_finally:
1108 * @start_ctx: saved processor state
1110 * This method is called by the Mono Debugger to call all `finally' clauses of the
1111 * current stack frame. It's used when the user issues a `return' command to make
1112 * the current stack frame return. After returning from this method, the debugger
1113 * unwinds the stack one frame and gives control back to the user.
1115 * NOTE: This method is only used when running inside the Mono Debugger.
1118 mono_debugger_run_finally (MonoContext
*start_ctx
)
1120 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
1121 MonoDomain
*domain
= mono_domain_get ();
1122 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1123 MonoLMF
*lmf
= mono_get_lmf ();
1124 MonoContext ctx
, new_ctx
;
1125 MonoJitInfo
*ji
, rji
;
1130 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
1131 if (!ji
|| ji
== (gpointer
)-1)
1135 call_filter
= mono_get_call_filter ();
1137 for (i
= 0; i
< ji
->num_clauses
; i
++) {
1138 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
1140 if ((ei
->try_start
<= MONO_CONTEXT_GET_IP (&ctx
)) &&
1141 (MONO_CONTEXT_GET_IP (&ctx
) < ei
->try_end
) &&
1142 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
1143 call_filter (&ctx
, ei
->handler_start
);
1149 * mono_handle_exception:
1150 * @ctx: saved processor state
1151 * @obj: the exception object
1152 * @test_only: only test if the exception is caught, but dont call handlers
1155 mono_handle_exception (MonoContext
*ctx
, gpointer obj
, gpointer original_ip
, gboolean test_only
)
1158 mono_perfcounters
->exceptions_thrown
++;
1159 return mono_handle_exception_internal (ctx
, obj
, original_ip
, test_only
, NULL
);
1162 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1164 #ifndef MONO_ARCH_USE_SIGACTION
1165 #error "Can't use sigaltstack without sigaction"
1169 mono_setup_altstack (MonoJitTlsData
*tls
)
1172 struct sigaltstack sa
;
1173 guint8
*staddr
= NULL
;
1175 if (mono_running_on_valgrind ())
1178 mono_thread_get_stack_bounds (&staddr
, &stsize
);
1182 tls
->end_of_stack
= staddr
+ stsize
;
1184 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1186 tls
->stack_ovf_guard_base
= staddr
+ mono_pagesize ();
1187 tls
->stack_ovf_guard_size
= mono_pagesize () * 8;
1189 if (mono_mprotect (tls
->stack_ovf_guard_base
, tls
->stack_ovf_guard_size
, MONO_MMAP_NONE
)) {
1190 /* mprotect can fail for the main thread stack */
1191 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
);
1192 g_assert (gaddr
== tls
->stack_ovf_guard_base
);
1196 * threads created by nptl does not seem to have a guard page, and
1197 * since the main thread is not created by us, we can't even set one.
1198 * Increasing stsize fools the SIGSEGV signal handler into thinking this
1199 * is a stack overflow exception.
1201 tls
->stack_size
= stsize
+ mono_pagesize ();
1203 /* Setup an alternate signal stack */
1204 tls
->signal_stack
= mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE
, MONO_MMAP_READ
|MONO_MMAP_WRITE
|MONO_MMAP_PRIVATE
|MONO_MMAP_ANON
);
1205 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1207 g_assert (tls
->signal_stack
);
1209 sa
.ss_sp
= tls
->signal_stack
;
1210 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1211 sa
.ss_flags
= SS_ONSTACK
;
1212 sigaltstack (&sa
, NULL
);
1216 mono_free_altstack (MonoJitTlsData
*tls
)
1218 struct sigaltstack sa
;
1221 sa
.ss_sp
= tls
->signal_stack
;
1222 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
1223 sa
.ss_flags
= SS_DISABLE
;
1224 err
= sigaltstack (&sa
, NULL
);
1225 g_assert (err
== 0);
1227 if (tls
->signal_stack
)
1228 mono_vfree (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
);
1231 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1234 mono_setup_altstack (MonoJitTlsData
*tls
)
1239 mono_free_altstack (MonoJitTlsData
*tls
)
1243 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1246 try_restore_stack_protection (MonoJitTlsData
*jit_tls
, int extra_bytes
)
1248 gint32 unprotect_size
= jit_tls
->stack_ovf_guard_size
;
1249 /* we need to leave some room for throwing the exception */
1250 while (unprotect_size
>= 0 && (char*)jit_tls
->stack_ovf_guard_base
+ unprotect_size
> ((char*)&unprotect_size
- extra_bytes
))
1251 unprotect_size
-= mono_pagesize ();
1252 /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1253 * is sufficient stack
1255 //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);
1257 mono_mprotect (jit_tls
->stack_ovf_guard_base
, unprotect_size
, MONO_MMAP_NONE
);
1258 return unprotect_size
== jit_tls
->stack_ovf_guard_size
;
1262 try_more_restore (void)
1264 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1265 if (try_restore_stack_protection (jit_tls
, 500))
1266 jit_tls
->restore_stack_prot
= NULL
;
1270 restore_stack_protection (void)
1272 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1273 MonoException
*ex
= mono_domain_get ()->stack_overflow_ex
;
1274 /* if we can't restore the stack protection, keep a callback installed so
1275 * we'll try to restore as much stack as we can at each return from unmanaged
1278 if (try_restore_stack_protection (jit_tls
, 4096))
1279 jit_tls
->restore_stack_prot
= NULL
;
1281 jit_tls
->restore_stack_prot
= try_more_restore_tramp
;
1282 /* here we also throw a stack overflow exception */
1283 ex
->trace_ips
= NULL
;
1284 ex
->stack_trace
= NULL
;
1285 mono_raise_exception (ex
);
1289 mono_altstack_restore_prot (gssize
*regs
, guint8
*code
, gpointer
*tramp_data
, guint8
* tramp
)
1291 void (*func
)(void) = (gpointer
)tramp_data
;
1297 mono_handle_soft_stack_ovf (MonoJitTlsData
*jit_tls
, MonoJitInfo
*ji
, void *ctx
, guint8
* fault_addr
)
1299 /* we got a stack overflow in the soft-guard pages
1300 * There are two cases:
1301 * 1) managed code caused the overflow: we unprotect the soft-guard page
1302 * and let the arch-specific code trigger the exception handling mechanism
1303 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1304 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1305 * and hope we can continue with those enabled, at least until the hard-guard page
1306 * is hit. The alternative to continuing here is to just print a message and abort.
1307 * We may add in the future the code to protect the pages again in the codepath
1308 * when we return from unmanaged to managed code.
1310 if (jit_tls
->stack_ovf_guard_size
&& fault_addr
>= (guint8
*)jit_tls
->stack_ovf_guard_base
&&
1311 fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ jit_tls
->stack_ovf_guard_size
) {
1312 /* we unprotect the minimum amount we can */
1314 gboolean handled
= FALSE
;
1316 guard_size
= jit_tls
->stack_ovf_guard_size
- (mono_pagesize () * SIZEOF_VOID_P
/ 4);
1317 while (guard_size
&& fault_addr
< (guint8
*)jit_tls
->stack_ovf_guard_base
+ guard_size
) {
1318 guard_size
-= mono_pagesize ();
1320 guard_size
= jit_tls
->stack_ovf_guard_size
- guard_size
;
1321 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
1322 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
);
1323 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1325 mono_arch_handle_altstack_exception (ctx
, fault_addr
, TRUE
);
1330 /* We print a message: after this even managed stack overflows
1331 * may crash the runtime
1333 fprintf (stderr
, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx
), fault_addr
);
1334 if (!jit_tls
->handling_stack_ovf
) {
1335 jit_tls
->restore_stack_prot
= restore_stack_protection_tramp
;
1336 jit_tls
->handling_stack_ovf
= 1;
1338 /*fprintf (stderr, "Already handling stack overflow\n");*/
1347 print_stack_frame (MonoMethod
*method
, gint32 native_offset
, gint32 il_offset
, gboolean managed
, gpointer data
)
1349 FILE *stream
= (FILE*)data
;
1352 gchar
*location
= mono_debug_print_stack_frame (method
, native_offset
, mono_domain_get ());
1353 fprintf (stream
, " %s\n", location
);
1356 fprintf (stream
, " at <unknown> <0x%05x>\n", native_offset
);
1361 static G_GNUC_UNUSED gboolean
1362 print_stack_frame_to_string (MonoMethod
*method
, gint32 native_offset
, gint32 il_offset
, gboolean managed
,
1365 GString
*p
= (GString
*)data
;
1368 gchar
*location
= mono_debug_print_stack_frame (method
, native_offset
, mono_domain_get ());
1369 g_string_append_printf (p
, " %s\n", location
);
1372 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", native_offset
);
1377 static gboolean handling_sigsegv
= FALSE
;
1380 * mono_handle_native_sigsegv:
1382 * Handle a SIGSEGV received while in native code by printing diagnostic
1383 * information and aborting.
1386 mono_handle_native_sigsegv (int signal
, void *ctx
)
1388 #ifndef PLATFORM_WIN32
1389 struct sigaction sa
;
1391 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
1393 if (handling_sigsegv
)
1396 /* To prevent infinite loops when the stack walk causes a crash */
1397 handling_sigsegv
= TRUE
;
1399 /* !jit_tls means the thread was not registered with the runtime */
1401 fprintf (stderr
, "Stacktrace:\n\n");
1403 mono_jit_walk_stack (print_stack_frame
, TRUE
, stderr
);
1408 #ifdef HAVE_BACKTRACE_SYMBOLS
1413 const char *signal_str
= (signal
== SIGSEGV
) ? "SIGSEGV" : "SIGABRT";
1415 fprintf (stderr
, "\nNative stacktrace:\n\n");
1417 size
= backtrace (array
, 256);
1418 names
= backtrace_symbols (array
, size
);
1419 for (i
=0; i
< size
; ++i
) {
1420 fprintf (stderr
, "\t%s\n", names
[i
]);
1426 /* Try to get more meaningful information using gdb */
1428 #if !defined(PLATFORM_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
1429 if (!mini_get_debug_options ()->no_gdb_backtrace
&& !mono_debug_using_mono_debugger ()) {
1430 /* From g_spawn_command_line_sync () in eglib */
1432 int stdout_pipe
[2] = { -1, -1 };
1434 const char *argv
[16];
1439 res
= pipe (stdout_pipe
);
1440 g_assert (res
!= -1);
1444 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1445 * it will deadlock. Call the syscall directly instead.
1447 pid
= syscall (SYS_fork
);
1449 close (stdout_pipe
[0]);
1450 dup2 (stdout_pipe
[1], STDOUT_FILENO
);
1452 for (i
= getdtablesize () - 1; i
>= 3; i
--)
1455 argv
[0] = g_find_program_in_path ("gdb");
1456 if (argv
[0] == NULL
) {
1457 close (STDOUT_FILENO
);
1462 sprintf (buf1
, "attach %ld", (long)getpid ());
1465 argv
[4] = "info threads";
1467 argv
[6] = "thread apply all bt";
1468 argv
[7] = "--batch";
1471 execv (argv
[0], (char**)argv
);
1475 close (stdout_pipe
[1]);
1477 fprintf (stderr
, "\nDebug info from gdb:\n\n");
1480 int nread
= read (stdout_pipe
[0], buffer
, 1024);
1484 write (STDERR_FILENO
, buffer
, nread
);
1487 waitpid (pid
, &status
, WNOHANG
);
1491 * A SIGSEGV indicates something went very wrong so we can no longer depend
1492 * on anything working. So try to print out lots of diagnostics, starting
1493 * with ones which have a greater chance of working.
1497 "=================================================================\n"
1498 "Got a %s while executing native code. This usually indicates\n"
1499 "a fatal error in the mono runtime or one of the native libraries \n"
1500 "used by your application.\n"
1501 "=================================================================\n"
1507 #ifndef PLATFORM_WIN32
1509 /* Remove our SIGABRT handler */
1510 sa
.sa_handler
= SIG_DFL
;
1511 sigemptyset (&sa
.sa_mask
);
1514 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
1522 * mono_print_thread_dump:
1524 * Print information about the current thread to stdout.
1525 * SIGCTX can be NULL, allowing this to be called from gdb.
1528 mono_print_thread_dump (void *sigctx
)
1530 MonoThread
*thread
= mono_thread_current ();
1531 #if defined(__i386__) || defined(__x86_64__)
1534 GString
* text
= g_string_new (0);
1535 char *name
, *wapi_desc
;
1536 GError
*error
= NULL
;
1539 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &error
);
1541 g_string_append_printf (text
, "\n\"%s\"", name
);
1544 else if (thread
->threadpool_thread
)
1545 g_string_append (text
, "\n\"<threadpool thread>\"");
1547 g_string_append (text
, "\n\"<unnamed thread>\"");
1549 #ifndef PLATFORM_WIN32
1550 wapi_desc
= wapi_current_thread_desc ();
1551 g_string_append_printf (text
, " tid=0x%p this=0x%p %s\n", (gpointer
)(gsize
)thread
->tid
, thread
, wapi_desc
);
1556 #if defined(__i386__) || defined(__x86_64__)
1558 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_print_thread_dump
);
1560 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
1562 mono_jit_walk_stack_from_ctx (print_stack_frame_to_string
, &ctx
, TRUE
, text
);
1564 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
1567 fprintf (stdout
, text
->str
);
1568 g_string_free (text
, TRUE
);