2 * mini-exceptions.c: generic exception support
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
15 #ifdef HAVE_EXECINFO_H
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/threads.h>
22 #include <mono/metadata/debug-helpers.h>
23 #include <mono/metadata/exception.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/mono-debug.h>
30 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
35 #define IS_ON_SIGALTSTACK(jit_tls) ((jit_tls) && ((guint8*)&(jit_tls) > (guint8*)(jit_tls)->signal_stack) && ((guint8*)&(jit_tls) < ((guint8*)(jit_tls)->signal_stack + (jit_tls)->signal_stack_size)))
37 #ifndef MONO_ARCH_CONTEXT_DEF
38 #define MONO_ARCH_CONTEXT_DEF
41 #ifndef mono_find_jit_info
43 /* mono_find_jit_info:
45 * This function is used to gather information from @ctx. It return the
46 * MonoJitInfo of the corresponding function, unwinds one stack frame and
47 * stores the resulting context into @new_ctx. It also stores a string
48 * describing the stack location into @trace (if not NULL), and modifies
49 * the @lmf if necessary. @native_offset return the IP offset from the
50 * start of the function or -1 if that info is not available.
53 mono_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoJitInfo
*res
, MonoJitInfo
*prev_ji
, MonoContext
*ctx
,
54 MonoContext
*new_ctx
, char **trace
, MonoLMF
**lmf
, int *native_offset
,
58 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
70 ji
= mono_arch_find_jit_info (domain
, jit_tls
, res
, prev_ji
, ctx
, new_ctx
, NULL
, lmf
, NULL
, &managed2
);
72 if (ji
== (gpointer
)-1)
75 if (managed2
|| ji
->method
->wrapper_type
) {
76 const char *real_ip
, *start
;
79 start
= (const char *)ji
->code_start
;
81 /* ctx->ip points into native code */
82 real_ip
= (const char*)MONO_CONTEXT_GET_IP (new_ctx
);
84 real_ip
= (const char*)ip
;
86 if ((real_ip
>= start
) && (real_ip
<= start
+ ji
->code_size
))
87 offset
= real_ip
- start
;
92 *native_offset
= offset
;
95 if (!ji
->method
->wrapper_type
)
99 *trace
= mono_debug_print_stack_frame (ji
->method
, offset
, domain
);
102 char *fname
= mono_method_full_name (res
->method
, TRUE
);
103 *trace
= g_strdup_printf ("in (unmanaged) %s", fname
);
111 #endif /* mono_find_jit_info */
114 ves_icall_System_Exception_get_trace (MonoException
*ex
)
116 MonoDomain
*domain
= mono_domain_get ();
118 MonoArray
*ta
= ex
->trace_ips
;
123 /* Exception is not thrown yet */
126 len
= mono_array_length (ta
);
127 trace_str
= g_string_new ("");
128 for (i
= 0; i
< len
; i
++) {
130 gpointer ip
= mono_array_get (ta
, gpointer
, i
);
132 ji
= mono_jit_info_table_find (domain
, ip
);
134 /* Unmanaged frame */
135 g_string_append_printf (trace_str
, "in (unmanaged) %p\n", ip
);
140 address
= (char *)ip
- (char *)ji
->code_start
;
141 location
= mono_debug_print_stack_frame (
142 ji
->method
, address
, ex
->object
.vtable
->domain
);
144 g_string_append_printf (trace_str
, "%s\n", location
);
149 res
= mono_string_new (ex
->object
.vtable
->domain
, trace_str
->str
);
150 g_string_free (trace_str
, TRUE
);
156 ves_icall_get_trace (MonoException
*exc
, gint32 skip
, MonoBoolean need_file_info
)
158 MonoDomain
*domain
= mono_domain_get ();
160 MonoArray
*ta
= exc
->trace_ips
;
161 MonoDebugSourceLocation
*location
;
165 /* Exception is not thrown yet */
166 return mono_array_new (domain
, mono_defaults
.stack_frame_class
, 0);
169 len
= mono_array_length (ta
);
171 res
= mono_array_new (domain
, mono_defaults
.stack_frame_class
, len
> skip
? len
- skip
: 0);
173 for (i
= skip
; i
< len
; i
++) {
175 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new (domain
, mono_defaults
.stack_frame_class
);
176 gpointer ip
= mono_array_get (ta
, gpointer
, i
);
178 ji
= mono_jit_info_table_find (domain
, ip
);
180 /* Unmanaged frame */
181 mono_array_setref (res
, i
, sf
);
185 g_assert (ji
!= NULL
);
187 if (ji
->method
->wrapper_type
) {
191 s
= mono_method_full_name (ji
->method
, TRUE
);
192 MONO_OBJECT_SETREF (sf
, internal_method_name
, mono_string_new (domain
, s
));
196 MONO_OBJECT_SETREF (sf
, method
, mono_method_get_object (domain
, ji
->method
, NULL
));
197 sf
->native_offset
= (char *)ip
- (char *)ji
->code_start
;
200 * mono_debug_lookup_source_location() returns both the file / line number information
201 * and the IL offset. Note that computing the IL offset is already an expensive
202 * operation, so we shouldn't call this method twice.
204 location
= mono_debug_lookup_source_location (ji
->method
, sf
->native_offset
, domain
);
206 sf
->il_offset
= location
->il_offset
;
210 if (need_file_info
) {
212 MONO_OBJECT_SETREF (sf
, filename
, mono_string_new (domain
, location
->source_file
));
213 sf
->line
= location
->row
;
214 sf
->column
= location
->column
;
216 sf
->line
= sf
->column
= 0;
221 mono_debug_free_source_location (location
);
222 mono_array_setref (res
, i
, sf
);
230 * @domain: starting appdomain
231 * @jit_tls: JIT data for the thread
232 * @start_ctx: starting state of the stack frame
233 * @func: callback to call for each stack frame
234 * @user_data: data passed to the callback
236 * This function walks the stack of a thread, starting from the state
237 * represented by jit_tls and start_ctx. For each frame the callback
238 * function is called with the relevant info. The walk ends when no more
239 * managed stack frames are found or when the callback returns a TRUE value.
240 * Note that the function can be used to walk the stack of a thread
241 * different from the current.
244 mono_walk_stack (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
, MonoContext
*start_ctx
, MonoStackFrameWalk func
, gpointer user_data
)
246 MonoLMF
*lmf
= jit_tls
->lmf
;
247 MonoJitInfo
*ji
, rji
;
250 MonoContext ctx
, new_ctx
;
254 while (MONO_CONTEXT_GET_BP (&ctx
) < jit_tls
->end_of_stack
) {
256 * FIXME: mono_find_jit_info () will need to be able to return a different
257 * MonoDomain when apddomain transitions are found on the stack.
259 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
260 if (!ji
|| ji
== (gpointer
)-1)
263 if (func (domain
, &new_ctx
, ji
, user_data
))
270 #ifndef CUSTOM_STACK_WALK
273 mono_jit_walk_stack_from_ctx (MonoStackWalk func
, MonoContext
*start_ctx
, gboolean do_il_offset
, gpointer user_data
)
275 MonoDomain
*domain
= mono_domain_get ();
276 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
277 MonoLMF
*lmf
= jit_tls
->lmf
;
278 MonoJitInfo
*ji
, rji
;
279 gint native_offset
, il_offset
;
281 MonoContext ctx
, new_ctx
;
283 MONO_ARCH_CONTEXT_DEF
285 mono_arch_flush_register_windows ();
288 memcpy (&ctx
, start_ctx
, sizeof (MonoContext
));
290 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
291 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
293 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, mono_jit_walk_stack_from_ctx
);
297 while (MONO_CONTEXT_GET_BP (&ctx
) < jit_tls
->end_of_stack
) {
298 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, &native_offset
, &managed
);
301 if (ji
== (gpointer
)-1)
305 MonoDebugSourceLocation
*source
;
307 source
= mono_debug_lookup_source_location (ji
->method
, native_offset
, domain
);
308 il_offset
= source
? source
->il_offset
: -1;
309 mono_debug_free_source_location (source
);
313 if (func (ji
->method
, native_offset
, il_offset
, managed
, user_data
))
321 mono_jit_walk_stack (MonoStackWalk func
, gboolean do_il_offset
, gpointer user_data
)
323 mono_jit_walk_stack_from_ctx (func
, NULL
, do_il_offset
, user_data
);
327 ves_icall_get_frame_info (gint32 skip
, MonoBoolean need_file_info
,
328 MonoReflectionMethod
**method
,
329 gint32
*iloffset
, gint32
*native_offset
,
330 MonoString
**file
, gint32
*line
, gint32
*column
)
332 MonoDomain
*domain
= mono_domain_get ();
333 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
334 MonoLMF
*lmf
= jit_tls
->lmf
;
335 MonoJitInfo
*ji
, rji
;
336 MonoContext ctx
, new_ctx
;
337 MonoDebugSourceLocation
*location
;
339 MONO_ARCH_CONTEXT_DEF
;
341 mono_arch_flush_register_windows ();
343 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
344 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx
);
346 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_get_frame_info
);
350 * FIXME: This is needed because of the LMF stuff which doesn't exist on ia64.
351 * Probably the whole mono_find_jit_info () stuff needs to be fixed so this isn't
352 * needed even on other platforms. This is also true for s390/s390x.
354 #if !defined(__ia64__) && !defined(__s390__) && !defined(__s390x__)
359 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, native_offset
, NULL
);
363 if (!ji
|| ji
== (gpointer
)-1 || MONO_CONTEXT_GET_BP (&ctx
) >= jit_tls
->end_of_stack
)
366 /* skip all wrappers ??*/
367 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
368 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
369 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
370 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
371 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
)
378 *method
= mono_method_get_object (domain
, ji
->method
, NULL
);
380 location
= mono_debug_lookup_source_location (ji
->method
, *native_offset
, domain
);
382 *iloffset
= location
->il_offset
;
386 if (need_file_info
) {
388 *file
= mono_string_new (domain
, location
->source_file
);
389 *line
= location
->row
;
390 *column
= location
->column
;
397 mono_debug_free_source_location (location
);
402 #endif /* CUSTOM_STACK_WALK */
406 MonoSecurityFrame
*frame
;
407 } MonoFrameSecurityInfo
;
410 callback_get_first_frame_security_info (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
412 MonoFrameSecurityInfo
*si
= (MonoFrameSecurityInfo
*) data
;
414 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
415 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
416 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
417 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
418 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
419 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
) {
428 si
->frame
= mono_declsec_create_frame (domain
, ji
);
430 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
435 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
436 * @skip: the number of stack frames to skip
438 * This function returns a the security informations of a single stack frame
439 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
440 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
444 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip
)
446 MonoDomain
*domain
= mono_domain_get ();
447 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
448 MonoFrameSecurityInfo si
;
451 MONO_ARCH_CONTEXT_DEF
453 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_System_Security_SecurityFrame_GetSecurityFrame
);
457 mono_walk_stack (domain
, jit_tls
, &ctx
, callback_get_first_frame_security_info
, (gpointer
)&si
);
459 return (si
.skips
== 0) ? si
.frame
: NULL
;
471 grow_array (MonoSecurityStack
*stack
)
473 MonoDomain
*domain
= mono_domain_get ();
474 guint32 newsize
= (stack
->maximum
<< 1);
475 MonoArray
*newstack
= mono_array_new (domain
, mono_defaults
.runtimesecurityframe_class
, newsize
);
477 for (i
=0; i
< stack
->maximum
; i
++) {
478 gpointer frame
= mono_array_get (stack
->stack
, gpointer
, i
);
479 mono_array_setref (newstack
, i
, frame
);
481 stack
->maximum
= newsize
;
482 stack
->stack
= newstack
;
486 callback_get_stack_frames_security_info (MonoDomain
*domain
, MonoContext
*ctx
, MonoJitInfo
*ji
, gpointer data
)
488 MonoSecurityStack
*ss
= (MonoSecurityStack
*) data
;
490 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
491 if (ji
->method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
492 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
493 ji
->method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
||
494 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
||
495 ji
->method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
) {
504 if (ss
->count
== ss
->maximum
)
507 mono_array_setref (ss
->stack
, ss
->count
++, mono_declsec_create_frame (domain
, ji
));
509 /* continue down the stack */
514 glist_to_array (GList
*list
, MonoClass
*eclass
)
516 MonoDomain
*domain
= mono_domain_get ();
523 len
= g_list_length (list
);
524 res
= mono_array_new (domain
, eclass
, len
);
526 for (i
= 0; list
; list
= list
->next
, i
++)
527 mono_array_set (res
, gpointer
, i
, list
->data
);
533 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
534 * @skip: the number of stack frames to skip
536 * This function returns an managed array of containing the security
537 * informations for each frame (after the skipped ones). This is used for
538 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
542 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip
)
544 MonoDomain
*domain
= mono_domain_get ();
545 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
546 MonoSecurityStack ss
;
549 MONO_ARCH_CONTEXT_DEF
551 MONO_INIT_CONTEXT_FROM_FUNC (&ctx
, ves_icall_System_Security_SecurityFrame_GetSecurityStack
);
555 ss
.maximum
= MONO_CAS_INITIAL_STACK_SIZE
;
556 ss
.stack
= mono_array_new (domain
, mono_defaults
.runtimesecurityframe_class
, ss
.maximum
);
557 mono_walk_stack (domain
, jit_tls
, &ctx
, callback_get_stack_frames_security_info
, (gpointer
)&ss
);
558 /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
562 #ifndef CUSTOM_EXCEPTION_HANDLING
565 * mono_handle_exception_internal:
566 * @ctx: saved processor state
567 * @obj: the exception object
568 * @test_only: only test if the exception is caught, but dont call handlers
569 * @out_filter_idx: out parameter. if test_only is true, set to the index of
570 * the first filter clause which caught the exception.
573 mono_handle_exception_internal (MonoContext
*ctx
, gpointer obj
, gpointer original_ip
, gboolean test_only
, gint32
*out_filter_idx
)
575 MonoDomain
*domain
= mono_domain_get ();
576 MonoJitInfo
*ji
, rji
;
577 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
578 static void (*restore_context
) (void *);
579 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
580 MonoLMF
*lmf
= jit_tls
->lmf
;
581 MonoArray
*initial_trace_ips
= NULL
;
582 GList
*trace_ips
= NULL
;
583 MonoException
*mono_ex
;
584 gboolean stack_overflow
= FALSE
;
585 MonoContext initial_ctx
;
587 gboolean gc_disabled
= FALSE
;
588 gboolean has_dynamic_methods
= FALSE
;
589 gint32 filter_idx
, first_filter_idx
;
592 * This function might execute on an alternate signal stack, and Boehm GC
594 * Also, since the altstack is small, stack space intensive operations like
595 * JIT compilation should be avoided.
597 if (IS_ON_SIGALTSTACK (jit_tls
)) {
599 * FIXME: disabling/enabling GC while already on a signal stack might
600 * not be safe either.
602 /* Have to reenable it later */
607 g_assert (ctx
!= NULL
);
609 MonoException
*ex
= mono_get_exception_null_reference ();
610 MONO_OBJECT_SETREF (ex
, message
, mono_string_new (domain
, "Object reference not set to an instance of an object"));
611 obj
= (MonoObject
*)ex
;
615 * Allocate a new exception object instead of the preconstructed ones.
616 * We can't do this in sigsegv_signal_handler, since GC is not yet
619 if (obj
== domain
->stack_overflow_ex
) {
620 obj
= mono_get_exception_stack_overflow ();
621 stack_overflow
= TRUE
;
623 else if (obj
== domain
->null_reference_ex
) {
624 obj
= mono_get_exception_null_reference ();
627 if (mono_object_isinst (obj
, mono_defaults
.exception_class
)) {
628 mono_ex
= (MonoException
*)obj
;
629 initial_trace_ips
= mono_ex
->trace_ips
;
635 call_filter
= mono_arch_get_call_filter ();
637 if (!restore_context
)
638 restore_context
= mono_arch_get_restore_context ();
640 g_assert (jit_tls
->end_of_stack
);
641 g_assert (jit_tls
->abort_func
);
644 MonoContext ctx_cp
= *ctx
;
645 if (mono_trace_is_enabled ())
646 g_print ("EXCEPTION handling: %s\n", mono_object_class (obj
)->name
);
647 if (!mono_handle_exception_internal (&ctx_cp
, obj
, original_ip
, TRUE
, &first_filter_idx
)) {
648 if (mono_break_on_exc
)
650 mono_unhandled_exception (obj
);
652 if (mono_debugger_unhandled_exception (original_ip
, MONO_CONTEXT_GET_SP (ctx
), obj
)) {
654 * If this returns true, then we're running inside the
655 * Mono Debugger and the debugger wants us to restore the
656 * context and continue (normally, the debugger inserts
657 * a breakpoint on the `original_ip', so it regains control
658 * immediately after restoring the context).
660 MONO_CONTEXT_SET_IP (ctx
, original_ip
);
661 restore_context (ctx
);
662 g_assert_not_reached ();
668 *out_filter_idx
= -1;
671 memset (&rji
, 0, sizeof (rji
));
677 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, &rji
, ctx
, &new_ctx
,
678 NULL
, &lmf
, NULL
, NULL
);
680 g_warning ("Exception inside function without unwind info");
681 g_assert_not_reached ();
684 if (ji
!= (gpointer
)-1) {
686 //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
688 if (test_only
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
&& mono_ex
) {
690 * Avoid overwriting the stack trace if the exception is
691 * rethrown. Also avoid giant stack traces during a stack
694 if (!initial_trace_ips
&& (frame_count
< 1000)) {
695 trace_ips
= g_list_prepend (trace_ips
, MONO_CONTEXT_GET_IP (ctx
));
699 if (ji
->method
->dynamic
)
700 has_dynamic_methods
= TRUE
;
703 free_stack
= (guint8
*)(MONO_CONTEXT_GET_BP (ctx
)) - (guint8
*)(MONO_CONTEXT_GET_BP (&initial_ctx
));
705 free_stack
= 0xffffff;
708 * During stack overflow, wait till the unwinding frees some stack
709 * space before running handlers/finalizers.
711 if ((free_stack
> (64 * 1024)) && ji
->num_clauses
) {
714 for (i
= 0; i
< ji
->num_clauses
; i
++) {
715 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
716 gboolean filtered
= FALSE
;
719 if (ei
->try_start
< MONO_CONTEXT_GET_IP (ctx
) &&
721 if (ei
->try_start
<= MONO_CONTEXT_GET_IP (ctx
) &&
723 MONO_CONTEXT_GET_IP (ctx
) <= ei
->try_end
) {
726 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) || (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
)) {
727 /* store the exception object in cfg->excvar */
728 g_assert (ei
->exvar_offset
);
729 *((gpointer
*)(gpointer
)((char *)MONO_CONTEXT_GET_BP (ctx
) + ei
->exvar_offset
)) = obj
;
732 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
733 // mono_debugger_handle_exception (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
735 filtered
= call_filter (ctx
, ei
->data
.filter
);
736 if (filtered
&& out_filter_idx
)
737 *out_filter_idx
= filter_idx
;
741 * Filter clauses should only be run in the
742 * first pass of exception handling.
744 filtered
= (filter_idx
== first_filter_idx
);
749 if ((ei
->flags
== MONO_EXCEPTION_CLAUSE_NONE
&&
750 mono_object_isinst (obj
, ei
->data
.catch_class
)) || filtered
) {
752 if (mono_ex
&& !initial_trace_ips
) {
753 trace_ips
= g_list_reverse (trace_ips
);
754 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, glist_to_array (trace_ips
, mono_defaults
.int_class
));
755 if (has_dynamic_methods
)
756 /* These methods could go away anytime, so compute the stack trace now */
757 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, ves_icall_System_Exception_get_trace (mono_ex
));
759 g_list_free (trace_ips
);
765 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
766 g_print ("EXCEPTION: catch found at clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
767 mono_debugger_handle_exception (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
768 MONO_CONTEXT_SET_IP (ctx
, ei
->handler_start
);
775 if (!test_only
&& ei
->try_start
<= MONO_CONTEXT_GET_IP (ctx
) &&
776 MONO_CONTEXT_GET_IP (ctx
) < ei
->try_end
&&
777 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
778 if (mono_trace_is_enabled () && mono_trace_eval (ji
->method
))
779 g_print ("EXCEPTION: finally clause %d of %s\n", i
, mono_method_full_name (ji
->method
, TRUE
));
780 mono_debugger_handle_exception (ei
->handler_start
, MONO_CONTEXT_GET_SP (ctx
), obj
);
781 call_filter (ctx
, ei
->handler_start
);
791 if (ji
== (gpointer
)-1) {
798 if (IS_ON_SIGALTSTACK (jit_tls
)) {
799 /* Switch back to normal stack */
800 if (stack_overflow
) {
801 /* Free up some stack space */
802 MONO_CONTEXT_SET_SP (&initial_ctx
, (gssize
)(MONO_CONTEXT_GET_SP (&initial_ctx
)) + (64 * 1024));
803 g_assert ((gssize
)MONO_CONTEXT_GET_SP (&initial_ctx
) < (gssize
)jit_tls
->end_of_stack
);
805 MONO_CONTEXT_SET_IP (&initial_ctx
, (gssize
)jit_tls
->abort_func
);
806 restore_context (&initial_ctx
);
809 jit_tls
->abort_func (obj
);
810 g_assert_not_reached ();
812 if (mono_ex
&& !initial_trace_ips
) {
813 trace_ips
= g_list_reverse (trace_ips
);
814 MONO_OBJECT_SETREF (mono_ex
, trace_ips
, glist_to_array (trace_ips
, mono_defaults
.int_class
));
815 if (has_dynamic_methods
)
816 /* These methods could go away anytime, so compute the stack trace now */
817 MONO_OBJECT_SETREF (mono_ex
, stack_trace
, ves_icall_System_Exception_get_trace (mono_ex
));
819 g_list_free (trace_ips
);
825 g_assert_not_reached ();
829 * mono_debugger_run_finally:
830 * @start_ctx: saved processor state
832 * This method is called by the Mono Debugger to call all `finally' clauses of the
833 * current stack frame. It's used when the user issues a `return' command to make
834 * the current stack frame return. After returning from this method, the debugger
835 * unwinds the stack one frame and gives control back to the user.
837 * NOTE: This method is only used when running inside the Mono Debugger.
840 mono_debugger_run_finally (MonoContext
*start_ctx
)
842 static int (*call_filter
) (MonoContext
*, gpointer
) = NULL
;
843 MonoDomain
*domain
= mono_domain_get ();
844 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
845 MonoLMF
*lmf
= jit_tls
->lmf
;
846 MonoContext ctx
, new_ctx
;
847 MonoJitInfo
*ji
, rji
;
852 ji
= mono_find_jit_info (domain
, jit_tls
, &rji
, NULL
, &ctx
, &new_ctx
, NULL
, &lmf
, NULL
, NULL
);
853 if (!ji
|| ji
== (gpointer
)-1)
857 call_filter
= mono_arch_get_call_filter ();
859 for (i
= 0; i
< ji
->num_clauses
; i
++) {
860 MonoJitExceptionInfo
*ei
= &ji
->clauses
[i
];
862 if ((ei
->try_start
<= MONO_CONTEXT_GET_IP (&ctx
)) &&
863 (MONO_CONTEXT_GET_IP (&ctx
) < ei
->try_end
) &&
864 (ei
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)) {
865 call_filter (&ctx
, ei
->handler_start
);
871 * mono_handle_exception:
872 * @ctx: saved processor state
873 * @obj: the exception object
874 * @test_only: only test if the exception is caught, but dont call handlers
877 mono_handle_exception (MonoContext
*ctx
, gpointer obj
, gpointer original_ip
, gboolean test_only
)
879 return mono_handle_exception_internal (ctx
, obj
, original_ip
, test_only
, NULL
);
882 #endif /* CUSTOM_EXCEPTION_HANDLING */
884 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
887 mono_setup_altstack (MonoJitTlsData
*tls
)
889 pthread_t self
= pthread_self();
892 struct sigaltstack sa
;
893 guint8
*staddr
= NULL
;
894 guint8
*current
= (guint8
*)&staddr
;
896 if (mono_running_on_valgrind ())
899 /* Determine stack boundaries */
900 pthread_attr_init( &attr
);
901 #ifdef HAVE_PTHREAD_GETATTR_NP
902 pthread_getattr_np( self
, &attr
);
904 #ifdef HAVE_PTHREAD_ATTR_GET_NP
905 pthread_attr_get_np( self
, &attr
);
907 pthread_attr_getstacksize( &attr
, &stsize
);
909 #error "Not implemented"
913 pthread_attr_getstack( &attr
, (void**)&staddr
, &stsize
);
918 g_assert ((current
> staddr
) && (current
< staddr
+ stsize
));
920 tls
->end_of_stack
= staddr
+ stsize
;
923 * threads created by nptl does not seem to have a guard page, and
924 * since the main thread is not created by us, we can't even set one.
925 * Increasing stsize fools the SIGSEGV signal handler into thinking this
926 * is a stack overflow exception.
928 tls
->stack_size
= stsize
+ getpagesize ();
930 /* Setup an alternate signal stack */
931 tls
->signal_stack
= mmap (0, MONO_ARCH_SIGNAL_STACK_SIZE
, PROT_READ
|PROT_WRITE
|PROT_EXEC
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1, 0);
932 tls
->signal_stack_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
934 g_assert (tls
->signal_stack
);
936 sa
.ss_sp
= tls
->signal_stack
;
937 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
938 sa
.ss_flags
= SS_ONSTACK
;
939 sigaltstack (&sa
, NULL
);
943 mono_free_altstack (MonoJitTlsData
*tls
)
945 struct sigaltstack sa
;
948 sa
.ss_sp
= tls
->signal_stack
;
949 sa
.ss_size
= MONO_ARCH_SIGNAL_STACK_SIZE
;
950 sa
.ss_flags
= SS_DISABLE
;
951 err
= sigaltstack (&sa
, NULL
);
954 if (tls
->signal_stack
)
955 munmap (tls
->signal_stack
, MONO_ARCH_SIGNAL_STACK_SIZE
);
958 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
961 print_stack_frame (MonoMethod
*method
, gint32 native_offset
, gint32 il_offset
, gboolean managed
, gpointer data
)
963 FILE *stream
= (FILE*)data
;
966 gchar
*location
= mono_debug_print_stack_frame (method
, native_offset
, mono_domain_get ());
967 fprintf (stream
, " %s\n", location
);
970 fprintf (stream
, " at <unknown> <0x%05x>\n", native_offset
);
976 * mono_handle_native_sigsegv:
978 * Handle a SIGSEGV received while in native code by printing diagnostic
979 * information and aborting.
982 mono_handle_native_sigsegv (int signal
, void *ctx
)
984 #ifndef PLATFORM_WIN32
987 const char *signal_str
= (signal
== SIGSEGV
) ? "SIGSEGV" : "SIGABRT";
991 * A SIGSEGV indicates something went very wrong so we can no longer depend
992 * on anything working. So try to print out lots of diagnostics, starting
993 * with ones which have a greater chance of working.
997 "=================================================================\n"
998 "Got a %s while executing native code. This usually indicates\n"
999 "a fatal error in the mono runtime or one of the native libraries \n"
1000 "used by your application.\n"
1001 "=================================================================\n"
1004 fprintf (stderr
, "Stacktrace:\n\n");
1006 mono_jit_walk_stack (print_stack_frame
, TRUE
, stderr
);
1010 #ifdef HAVE_BACKTRACE_SYMBOLS
1016 fprintf (stderr
, "\nNative stacktrace:\n\n");
1018 size
= backtrace (array
, 256);
1019 names
= backtrace_symbols (array
, size
);
1020 for (i
=0; i
< size
; ++i
) {
1021 fprintf (stderr
, "\t%s\n", names
[i
]);
1029 #ifndef PLATFORM_WIN32
1031 /* Remove our SIGABRT handler */
1032 sa
.sa_handler
= SIG_DFL
;
1033 sigemptyset (&sa
.sa_mask
);
1036 g_assert (sigaction (SIGABRT
, &sa
, NULL
) != -1);
1044 * mono_print_thread_dump:
1046 * Print information about the current thread to stdout.
1049 mono_print_thread_dump (void *sigctx
)
1051 MonoThread
*thread
= mono_thread_current ();
1056 GError
*error
= NULL
;
1059 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &error
);
1061 fprintf (stdout
, "\n\"%s\"", name
);
1065 fprintf (stdout
, "\n\"\"");
1067 fprintf (stdout
, " tid=0x%p this=0x%p:\n", (gpointer
)(gsize
)thread
->tid
, thread
);
1071 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
1073 mono_jit_walk_stack_from_ctx (print_stack_frame
, &ctx
, TRUE
, stdout
);
1075 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");