2010-04-06 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / mini-exceptions.c
blob5aa521164e4b0609cd017da49d821ab2b37a6f54
1 /*
2 * mini-exceptions.c: generic exception support
4 * Authors:
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Mono Team (mono-list@lists.ximian.com)
8 * Copyright 2001-2003 Ximian, Inc.
9 * Copyright 2003-2008 Ximian, Inc.
12 #include <config.h>
13 #include <glib.h>
14 #include <signal.h>
15 #include <string.h>
17 #ifdef HAVE_EXECINFO_H
18 #include <execinfo.h>
19 #endif
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
23 #endif
25 #ifdef HAVE_SYS_WAIT_H
26 #include <sys/wait.h>
27 #endif
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
33 #ifdef HAVE_SYS_SYSCALL_H
34 #include <sys/syscall.h>
35 #endif
37 #include <mono/metadata/appdomain.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/threads-types.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include <mono/metadata/exception.h>
43 #include <mono/metadata/gc-internal.h>
44 #include <mono/metadata/mono-debug.h>
45 #include <mono/metadata/profiler.h>
46 #include <mono/utils/mono-mmap.h>
48 #include "mini.h"
49 #include "debug-mini.h"
50 #include "trace.h"
51 #include "debugger-agent.h"
53 #ifndef MONO_ARCH_CONTEXT_DEF
54 #define MONO_ARCH_CONTEXT_DEF
55 #endif
57 static gpointer restore_context_func, call_filter_func;
58 static gpointer throw_exception_func, rethrow_exception_func;
59 static gpointer throw_exception_by_name_func, throw_corlib_exception_func;
61 static gpointer try_more_restore_tramp = NULL;
62 static gpointer restore_stack_protection_tramp = NULL;
64 static void try_more_restore (void);
65 static void restore_stack_protection (void);
66 static void mono_walk_stack_full (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gboolean use_new_ctx, gpointer user_data);
68 void
69 mono_exceptions_init (void)
71 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
72 guint32 code_size;
73 MonoJumpInfo *ji;
75 if (mono_aot_only) {
76 restore_context_func = mono_aot_get_named_code ("restore_context");
77 call_filter_func = mono_aot_get_named_code ("call_filter");
78 throw_exception_func = mono_aot_get_named_code ("throw_exception");
79 rethrow_exception_func = mono_aot_get_named_code ("rethrow_exception");
80 } else {
81 restore_context_func = mono_arch_get_restore_context_full (&code_size, &ji, FALSE);
82 call_filter_func = mono_arch_get_call_filter_full (&code_size, &ji, FALSE);
83 throw_exception_func = mono_arch_get_throw_exception_full (&code_size, &ji, FALSE);
84 rethrow_exception_func = mono_arch_get_rethrow_exception_full (&code_size, &ji, FALSE);
86 #else
87 restore_context_func = mono_arch_get_restore_context ();
88 call_filter_func = mono_arch_get_call_filter ();
89 throw_exception_func = mono_arch_get_throw_exception ();
90 rethrow_exception_func = mono_arch_get_rethrow_exception ();
91 #endif
92 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
93 try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
94 restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
95 #endif
97 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
98 mono_arch_exceptions_init ();
99 #endif
102 gpointer
103 mono_get_throw_exception (void)
105 g_assert (throw_exception_func);
106 return throw_exception_func;
109 gpointer
110 mono_get_rethrow_exception (void)
112 g_assert (rethrow_exception_func);
113 return rethrow_exception_func;
116 gpointer
117 mono_get_call_filter (void)
119 g_assert (call_filter_func);
120 return call_filter_func;
123 gpointer
124 mono_get_restore_context (void)
126 g_assert (restore_context_func);
127 return restore_context_func;
130 gpointer
131 mono_get_throw_exception_by_name (void)
133 #ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME
135 gpointer code = NULL;
136 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
137 guint32 code_size;
138 MonoJumpInfo *ji;
139 #endif
141 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
142 if (throw_exception_by_name_func)
143 return throw_exception_by_name_func;
145 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
146 if (mono_aot_only)
147 code = mono_aot_get_named_code ("throw_exception_by_name");
148 else
149 code = mono_arch_get_throw_exception_by_name_full (&code_size, &ji, FALSE);
150 #else
151 code = mono_arch_get_throw_exception_by_name ();
152 #endif
154 mono_memory_barrier ();
156 throw_exception_by_name_func = code;
158 #else
160 throw_exception_by_name_func = NULL;
162 g_assert_not_reached ();
163 #endif
165 return throw_exception_by_name_func;
168 gpointer
169 mono_get_throw_corlib_exception (void)
171 gpointer code = NULL;
172 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
173 guint32 code_size;
174 MonoJumpInfo *ji;
175 #endif
177 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
178 if (throw_corlib_exception_func)
179 return throw_corlib_exception_func;
181 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
182 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
183 if (mono_aot_only)
184 code = mono_aot_get_named_code ("throw_corlib_exception");
185 else
186 code = mono_arch_get_throw_corlib_exception_full (&code_size, &ji, FALSE);
187 #else
188 code = mono_arch_get_throw_corlib_exception ();
189 #endif
190 #else
191 g_assert_not_reached ();
192 #endif
194 mono_memory_barrier ();
196 throw_corlib_exception_func = code;
198 return throw_corlib_exception_func;
201 static gboolean
202 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
204 MonoTryBlockHoleTableJitInfo *table;
205 int i;
206 guint32 offset;
207 guint16 clause;
209 /*FIXME check if under s390 it should be ei->try_start >= ip*/
210 if (ei->try_start > ip || ip >= ei->try_end)
211 return FALSE;
213 if (!ji->has_try_block_holes)
214 return TRUE;
216 table = mono_jit_info_get_try_block_hole_table_info (ji);
217 offset = (guint32)((char*)ip - (char*)ji->code_start);
218 clause = (guint16)(ei - ji->clauses);
219 g_assert (clause < ji->num_clauses);
221 for (i = 0; i < table->num_holes; ++i) {
222 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
223 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
224 return FALSE;
226 return TRUE;
229 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
232 * find_jit_info_no_ext:
234 * If the target has the find_jit_info_ext version of this function, define the old
235 * version here which translates between the old and new APIs.
237 static MonoJitInfo *
238 find_jit_info_no_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
239 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
241 StackFrameInfo frame;
242 MonoJitInfo *ji;
243 gboolean err;
244 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
246 /* Avoid costly table lookup during stack overflow */
247 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
248 ji = prev_ji;
249 else
250 ji = mini_jit_info_table_find (domain, ip, NULL);
252 if (managed)
253 *managed = FALSE;
255 err = mono_arch_find_jit_info_ext (domain, jit_tls, ji, ctx, new_ctx, lmf, &frame);
256 if (!err)
257 return (gpointer)-1;
259 /* Convert between the new and the old APIs */
260 switch (frame.type) {
261 case FRAME_TYPE_MANAGED:
262 if (managed)
263 *managed = TRUE;
264 return ji;
265 case FRAME_TYPE_MANAGED_TO_NATIVE:
266 if (frame.ji)
267 return frame.ji;
268 else {
269 memset (res, 0, sizeof (MonoJitInfo));
270 res->method = frame.method;
271 return res;
273 case FRAME_TYPE_DEBUGGER_INVOKE: {
274 MonoContext tmp_ctx;
277 * The normal exception handling code can't handle this frame, so just
278 * skip it.
280 ji = find_jit_info_no_ext (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
281 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
282 return ji;
284 default:
285 g_assert_not_reached ();
286 return NULL;
290 #endif
292 /* mono_find_jit_info:
294 * This function is used to gather information from @ctx. It return the
295 * MonoJitInfo of the corresponding function, unwinds one stack frame and
296 * stores the resulting context into @new_ctx. It also stores a string
297 * describing the stack location into @trace (if not NULL), and modifies
298 * the @lmf if necessary. @native_offset return the IP offset from the
299 * start of the function or -1 if that info is not available.
301 MonoJitInfo *
302 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
303 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
304 gboolean *managed)
306 gboolean managed2;
307 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
308 MonoJitInfo *ji;
310 if (trace)
311 *trace = NULL;
313 if (native_offset)
314 *native_offset = -1;
316 if (managed)
317 *managed = FALSE;
319 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
320 ji = find_jit_info_no_ext (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
321 #else
322 ji = mono_arch_find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
323 #endif
325 if (ji == (gpointer)-1)
326 return ji;
328 if (managed2 || (ji && ji->method->wrapper_type)) {
329 const char *real_ip, *start;
330 gint32 offset;
332 start = (const char *)ji->code_start;
333 if (!managed2)
334 /* ctx->ip points into native code */
335 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
336 else
337 real_ip = (const char*)ip;
339 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
340 offset = real_ip - start;
341 else
342 offset = -1;
344 if (native_offset)
345 *native_offset = offset;
347 if (managed)
348 if (!ji->method->wrapper_type)
349 *managed = TRUE;
351 if (trace)
352 *trace = mono_debug_print_stack_frame (ji->method, offset, domain);
353 } else {
354 if (trace) {
355 char *fname = mono_method_full_name (res->method, TRUE);
356 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
357 g_free (fname);
361 return ji;
364 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
367 * mono_find_jit_info_ext:
369 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
370 * structure.
372 gboolean
373 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
374 MonoJitInfo *prev_ji, MonoContext *ctx,
375 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
376 StackFrameInfo *frame)
378 gboolean err;
379 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
380 MonoJitInfo *ji;
381 MonoDomain *target_domain;
383 if (trace)
384 *trace = NULL;
386 /* Avoid costly table lookup during stack overflow */
387 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
388 ji = prev_ji;
389 else
390 ji = mini_jit_info_table_find (domain, ip, &target_domain);
392 if (!target_domain)
393 target_domain = domain;
395 err = mono_arch_find_jit_info_ext (target_domain, jit_tls, ji, ctx, new_ctx, lmf, frame);
396 if (!err)
397 return FALSE;
399 frame->native_offset = -1;
400 frame->domain = target_domain;
402 ji = frame->ji;
404 if (ji && (frame->managed || ji->method->wrapper_type)) {
405 const char *real_ip, *start;
407 start = (const char *)ji->code_start;
408 if (!frame->managed)
409 /* ctx->ip points into native code */
410 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
411 else
412 real_ip = (const char*)ip;
414 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
415 frame->native_offset = real_ip - start;
416 else
417 frame->native_offset = -1;
419 if (trace)
420 *trace = mono_debug_print_stack_frame (ji->method, frame->native_offset, domain);
421 } else {
422 if (trace && frame->method) {
423 char *fname = mono_method_full_name (frame->method, TRUE);
424 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
425 g_free (fname);
429 return TRUE;
432 #endif /* MONO_ARCH_HAVE_FIND_JIT_INFO_EXT */
434 static gpointer
435 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
437 MonoGenericJitInfo *gi;
438 gpointer info;
440 if (!ji->has_generic_jit_info)
441 return NULL;
442 gi = mono_jit_info_get_generic_jit_info (ji);
443 if (!gi->has_this)
444 return NULL;
446 if (gi->this_in_reg)
447 info = mono_arch_context_get_int_reg (ctx, gi->this_reg);
448 else
449 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
450 gi->this_offset);
451 if (mono_method_get_context (ji->method)->method_inst) {
452 return info;
453 } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
454 return info;
455 } else {
456 /* Avoid returning a managed object */
457 MonoObject *this_obj = info;
459 return this_obj->vtable->klass;
463 static MonoGenericContext
464 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
466 MonoGenericContext context = { NULL, NULL };
467 MonoClass *class, *method_container_class;
469 g_assert (generic_info);
471 g_assert (ji->method->is_inflated);
472 if (mono_method_get_context (ji->method)->method_inst) {
473 MonoMethodRuntimeGenericContext *mrgctx = generic_info;
475 class = mrgctx->class_vtable->klass;
476 context.method_inst = mrgctx->method_inst;
477 g_assert (context.method_inst);
478 } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
479 MonoVTable *vtable = generic_info;
481 class = vtable->klass;
482 } else {
483 class = generic_info;
486 //g_assert (!ji->method->klass->generic_container);
487 if (ji->method->klass->generic_class)
488 method_container_class = ji->method->klass->generic_class->container_class;
489 else
490 method_container_class = ji->method->klass;
492 /* class might refer to a subclass of ji->method's class */
493 while (class->generic_class && class->generic_class->container_class != method_container_class) {
494 class = class->parent;
495 g_assert (class);
498 if (class->generic_class || class->generic_container)
499 context.class_inst = mini_class_get_context (class)->class_inst;
501 if (class->generic_class)
502 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class->container_class, method_container_class));
503 else
504 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class));
506 return context;
509 static MonoMethod*
510 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
512 MonoGenericContext context;
513 MonoMethod *method;
515 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
516 return ji->method;
517 context = get_generic_context_from_stack_frame (ji, generic_info);
519 method = mono_method_get_declaring_generic_method (ji->method);
520 method = mono_class_inflate_generic_method (method, &context);
522 return method;
525 MonoString *
526 ves_icall_System_Exception_get_trace (MonoException *ex)
528 MonoDomain *domain = mono_domain_get ();
529 MonoString *res;
530 MonoArray *ta = ex->trace_ips;
531 int i, len;
532 GString *trace_str;
534 if (ta == NULL)
535 /* Exception is not thrown yet */
536 return NULL;
538 len = mono_array_length (ta) >> 1;
539 trace_str = g_string_new ("");
540 for (i = 0; i < len; i++) {
541 MonoJitInfo *ji;
542 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
543 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
545 ji = mono_jit_info_table_find (domain, ip);
546 if (ji == NULL) {
547 /* Unmanaged frame */
548 g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
549 } else {
550 gchar *location;
551 gint32 address;
552 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
554 address = (char *)ip - (char *)ji->code_start;
555 location = mono_debug_print_stack_frame (
556 method, address, ex->object.vtable->domain);
558 g_string_append_printf (trace_str, "%s\n", location);
559 g_free (location);
563 res = mono_string_new (ex->object.vtable->domain, trace_str->str);
564 g_string_free (trace_str, TRUE);
566 return res;
569 MonoArray *
570 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
572 MonoDomain *domain = mono_domain_get ();
573 MonoArray *res;
574 MonoArray *ta = exc->trace_ips;
575 MonoDebugSourceLocation *location;
576 int i, len;
578 if (ta == NULL) {
579 /* Exception is not thrown yet */
580 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
583 len = mono_array_length (ta) >> 1;
585 res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
587 for (i = skip; i < len; i++) {
588 MonoJitInfo *ji;
589 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
590 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
591 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
592 MonoMethod *method;
594 ji = mono_jit_info_table_find (domain, ip);
595 if (ji == NULL) {
596 /* Unmanaged frame */
597 mono_array_setref (res, i, sf);
598 continue;
601 g_assert (ji != NULL);
603 method = get_method_from_stack_frame (ji, generic_info);
604 if (ji->method->wrapper_type) {
605 char *s;
607 sf->method = NULL;
608 s = mono_method_full_name (method, TRUE);
609 MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
610 g_free (s);
612 else
613 MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
614 sf->native_offset = (char *)ip - (char *)ji->code_start;
617 * mono_debug_lookup_source_location() returns both the file / line number information
618 * and the IL offset. Note that computing the IL offset is already an expensive
619 * operation, so we shouldn't call this method twice.
621 location = mono_debug_lookup_source_location (ji->method, sf->native_offset, domain);
622 if (location)
623 sf->il_offset = location->il_offset;
624 else
625 sf->il_offset = 0;
627 if (need_file_info) {
628 if (location && location->source_file) {
629 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
630 sf->line = location->row;
631 sf->column = location->column;
632 } else {
633 sf->line = sf->column = 0;
634 sf->filename = NULL;
638 mono_debug_free_source_location (location);
639 mono_array_setref (res, i, sf);
642 return res;
646 * mono_walk_stack:
647 * @domain: starting appdomain
648 * @jit_tls: JIT data for the thread
649 * @start_ctx: starting state of the stack frame
650 * @func: callback to call for each stack frame
651 * @user_data: data passed to the callback
653 * This function walks the stack of a thread, starting from the state
654 * represented by jit_tls and start_ctx. For each frame the callback
655 * function is called with the relevant info. The walk ends when no more
656 * managed stack frames are found or when the callback returns a TRUE value.
657 * Note that the function can be used to walk the stack of a thread
658 * different from the current.
660 void
661 mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gpointer user_data)
663 mono_walk_stack_full (domain, jit_tls, start_ctx, func, TRUE, user_data);
666 static void
667 mono_walk_stack_full (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gboolean use_new_ctx, gpointer user_data)
669 MonoLMF *lmf = mono_get_lmf ();
670 MonoJitInfo *ji, rji;
671 gint native_offset;
672 gboolean managed;
673 MonoContext ctx, new_ctx;
675 ctx = *start_ctx;
677 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
679 * FIXME: mono_find_jit_info () will need to be able to return a different
680 * MonoDomain when apddomain transitions are found on the stack.
682 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
683 if (!ji || ji == (gpointer)-1)
684 return;
686 if (func (domain, use_new_ctx ? &new_ctx : &ctx, ji, user_data))
687 return;
689 ctx = new_ctx;
693 void
694 mono_jit_walk_stack_from_ctx (MonoStackWalk func, MonoContext *start_ctx, gboolean do_il_offset, gpointer user_data)
696 MonoDomain *domain = mono_domain_get ();
697 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
698 MonoLMF *lmf = mono_get_lmf ();
699 MonoJitInfo *ji, rji;
700 gint native_offset, il_offset;
701 gboolean managed;
702 MonoContext ctx, new_ctx;
704 MONO_ARCH_CONTEXT_DEF
706 mono_arch_flush_register_windows ();
708 if (start_ctx) {
709 memcpy (&ctx, start_ctx, sizeof (MonoContext));
710 } else {
711 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
712 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
713 #else
714 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_jit_walk_stack_from_ctx);
715 #endif
718 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
719 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
720 g_assert (ji);
722 if (ji == (gpointer)-1)
723 return;
725 if (do_il_offset) {
726 MonoDebugSourceLocation *source;
728 source = mono_debug_lookup_source_location (ji->method, native_offset, domain);
729 il_offset = source ? source->il_offset : -1;
730 mono_debug_free_source_location (source);
731 } else
732 il_offset = -1;
734 if (func (ji->method, native_offset, il_offset, managed, user_data))
735 return;
737 ctx = new_ctx;
741 void
742 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data)
744 mono_jit_walk_stack_from_ctx (func, NULL, do_il_offset, user_data);
747 void
748 mono_jit_walk_stack_from_ctx_in_thread (MonoJitStackWalk func, MonoDomain *domain, MonoContext *start_ctx, gboolean do_il_offset, MonoInternalThread *thread, MonoLMF *lmf, gpointer user_data)
750 MonoJitTlsData *jit_tls = thread->jit_data;
751 gint il_offset;
752 MonoContext ctx, new_ctx;
753 StackFrameInfo frame;
754 #ifndef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
755 gint native_offset;
756 gboolean managed;
757 MonoJitInfo *ji, rji;
758 #else
759 gboolean res;
760 #endif
762 MONO_ARCH_CONTEXT_DEF
764 mono_arch_flush_register_windows ();
766 if (start_ctx) {
767 memcpy (&ctx, start_ctx, sizeof (MonoContext));
768 } else {
769 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
770 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
771 #else
772 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_jit_walk_stack_from_ctx);
773 #endif
774 g_assert (thread == mono_thread_internal_current ());
777 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
778 frame.lmf = lmf;
779 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
780 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, &frame);
781 if (!res)
782 return;
783 #else
784 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
785 g_assert (ji);
786 frame.type = FRAME_TYPE_MANAGED;
787 frame.ji = ji;
788 frame.managed = managed;
789 frame.native_offset = native_offset;
791 if (ji == (gpointer)-1)
792 return;
793 #endif
795 if (do_il_offset && frame.ji) {
796 MonoDebugSourceLocation *source;
798 source = mono_debug_lookup_source_location (frame.ji->method, frame.native_offset, domain);
799 il_offset = source ? source->il_offset : -1;
800 mono_debug_free_source_location (source);
801 } else
802 il_offset = -1;
804 frame.il_offset = il_offset;
806 if (func (&frame, &ctx, user_data))
807 return;
809 ctx = new_ctx;
814 MonoBoolean
815 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
816 MonoReflectionMethod **method,
817 gint32 *iloffset, gint32 *native_offset,
818 MonoString **file, gint32 *line, gint32 *column)
820 MonoDomain *domain = mono_domain_get ();
821 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
822 MonoLMF *lmf = mono_get_lmf ();
823 MonoJitInfo *ji, rji;
824 MonoContext ctx, new_ctx, ji_ctx;
825 MonoDebugSourceLocation *location;
826 MonoMethod *last_method = NULL, *actual_method;
828 MONO_ARCH_CONTEXT_DEF;
830 mono_arch_flush_register_windows ();
832 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
833 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
834 #else
835 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
836 #endif
838 do {
839 ji_ctx = ctx;
840 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, (int*) native_offset, NULL);
841 ctx = new_ctx;
843 if (ji && ji != (gpointer)-1 &&
844 MONO_CONTEXT_GET_IP (&ctx) >= ji->code_start &&
845 (guint8*)MONO_CONTEXT_GET_IP (&ctx) < (guint8*)ji->code_start + ji->code_size) {
846 ji_ctx = ctx;
849 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_SP (&ctx) >= jit_tls->end_of_stack)
850 return FALSE;
852 /* skip all wrappers ??*/
853 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
854 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
855 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
856 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
857 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE ||
858 ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
859 continue;
861 if (ji->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE && ji->method == last_method) {
863 * FIXME: Native-to-managed wrappers sometimes show up twice.
864 * Probably the whole mono_find_jit_info () stuff needs to be fixed so this
865 * isn't needed.
867 continue;
870 last_method = ji->method;
872 skip--;
874 } while (skip >= 0);
876 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ji_ctx));
878 mono_gc_wbarrier_generic_store (method, (MonoObject*) mono_method_get_object (domain, actual_method, NULL));
880 location = mono_debug_lookup_source_location (ji->method, *native_offset, domain);
881 if (location)
882 *iloffset = location->il_offset;
883 else
884 *iloffset = 0;
886 if (need_file_info) {
887 if (location) {
888 mono_gc_wbarrier_generic_store (file, (MonoObject*) mono_string_new (domain, location->source_file));
889 *line = location->row;
890 *column = location->column;
891 } else {
892 *file = NULL;
893 *line = *column = 0;
897 mono_debug_free_source_location (location);
899 return TRUE;
902 typedef struct {
903 guint32 skips;
904 MonoSecurityFrame *frame;
905 } MonoFrameSecurityInfo;
907 static gboolean
908 callback_get_first_frame_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
910 MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
912 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
913 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
914 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
915 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
916 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
917 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
918 return FALSE;
921 if (si->skips > 0) {
922 si->skips--;
923 return FALSE;
926 si->frame = mono_declsec_create_frame (domain, ji);
928 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
929 return TRUE;
933 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
934 * @skip: the number of stack frames to skip
936 * This function returns a the security informations of a single stack frame
937 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
938 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
939 * evaluated.
941 MonoSecurityFrame*
942 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
944 MonoDomain *domain = mono_domain_get ();
945 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
946 MonoFrameSecurityInfo si;
947 MonoContext ctx;
949 MONO_ARCH_CONTEXT_DEF
951 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
952 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
953 #else
954 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
955 #endif
957 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
958 skip--;
959 #endif
961 si.skips = skip;
962 si.frame = NULL;
963 mono_walk_stack (domain, jit_tls, &ctx, callback_get_first_frame_security_info, (gpointer)&si);
965 return (si.skips == 0) ? si.frame : NULL;
969 typedef struct {
970 guint32 skips;
971 MonoArray *stack;
972 guint32 count;
973 guint32 maximum;
974 } MonoSecurityStack;
976 static void
977 grow_array (MonoSecurityStack *stack)
979 MonoDomain *domain = mono_domain_get ();
980 guint32 newsize = (stack->maximum << 1);
981 MonoArray *newstack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, newsize);
982 int i;
983 for (i=0; i < stack->maximum; i++) {
984 gpointer frame = mono_array_get (stack->stack, gpointer, i);
985 mono_array_setref (newstack, i, frame);
987 stack->maximum = newsize;
988 stack->stack = newstack;
991 static gboolean
992 callback_get_stack_frames_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
994 MonoSecurityStack *ss = (MonoSecurityStack*) data;
996 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
997 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
998 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
999 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
1000 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
1001 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
1002 return FALSE;
1005 if (ss->skips > 0) {
1006 ss->skips--;
1007 return FALSE;
1010 if (ss->count == ss->maximum)
1011 grow_array (ss);
1013 mono_array_setref (ss->stack, ss->count++, mono_declsec_create_frame (domain, ji));
1015 /* continue down the stack */
1016 return FALSE;
1019 static MonoArray *
1020 glist_to_array (GList *list, MonoClass *eclass)
1022 MonoDomain *domain = mono_domain_get ();
1023 MonoArray *res;
1024 int len, i;
1026 if (!list)
1027 return NULL;
1029 len = g_list_length (list);
1030 res = mono_array_new (domain, eclass, len);
1032 for (i = 0; list; list = list->next, i++)
1033 mono_array_set (res, gpointer, i, list->data);
1035 return res;
1039 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
1040 * @skip: the number of stack frames to skip
1042 * This function returns an managed array of containing the security
1043 * informations for each frame (after the skipped ones). This is used for
1044 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
1045 * required.
1047 MonoArray*
1048 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
1050 MonoDomain *domain = mono_domain_get ();
1051 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1052 MonoSecurityStack ss;
1053 MonoContext ctx;
1055 MONO_ARCH_CONTEXT_DEF
1057 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1058 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
1059 #else
1060 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityStack);
1061 #endif
1063 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
1064 skip--;
1065 #endif
1067 ss.skips = skip;
1068 ss.count = 0;
1069 ss.maximum = MONO_CAS_INITIAL_STACK_SIZE;
1070 ss.stack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, ss.maximum);
1071 mono_walk_stack (domain, jit_tls, &ctx, callback_get_stack_frames_security_info, (gpointer)&ss);
1072 /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
1073 return ss.stack;
1076 static MonoClass*
1077 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1079 MonoClass *catch_class = ei->data.catch_class;
1080 MonoType *inflated_type;
1081 MonoGenericContext context;
1083 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1084 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
1085 return NULL;
1087 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1088 return catch_class;
1089 context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1091 /* FIXME: we shouldn't inflate but instead put the
1092 type in the rgctx and fetch it from there. It
1093 might be a good idea to do this lazily, i.e. only
1094 when the exception is actually thrown, so as not to
1095 waste space for exception clauses which might never
1096 be encountered. */
1097 inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
1098 catch_class = mono_class_from_mono_type (inflated_type);
1099 mono_metadata_free_type (inflated_type);
1101 return catch_class;
1105 * mini_jit_info_table_find:
1107 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1108 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1109 * OUT_DOMAIN if it is not NULL.
1111 MonoJitInfo*
1112 mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
1114 MonoJitInfo *ji;
1115 MonoInternalThread *t = mono_thread_internal_current ();
1116 GSList *l;
1118 if (out_domain)
1119 *out_domain = NULL;
1121 ji = mono_jit_info_table_find (domain, addr);
1122 if (ji) {
1123 if (out_domain)
1124 *out_domain = domain;
1125 return ji;
1128 /* maybe it is shared code, so we also search in the root domain */
1129 if (domain != mono_get_root_domain ()) {
1130 ji = mono_jit_info_table_find (mono_get_root_domain (), addr);
1131 if (ji) {
1132 if (out_domain)
1133 *out_domain = mono_get_root_domain ();
1134 return ji;
1138 for (l = t->appdomain_refs; l; l = l->next) {
1139 if (l->data != domain) {
1140 ji = mono_jit_info_table_find ((MonoDomain*)l->data, addr);
1141 if (ji) {
1142 if (out_domain)
1143 *out_domain = (MonoDomain*)l->data;
1144 return ji;
1149 return NULL;
1153 * mono_handle_exception_internal:
1154 * @ctx: saved processor state
1155 * @obj: the exception object
1156 * @test_only: only test if the exception is caught, but dont call handlers
1157 * @out_filter_idx: out parameter. if test_only is true, set to the index of
1158 * the first filter clause which caught the exception.
1159 * @resume: whenever to resume unwinding based on the state in MonoJitTlsData.
1161 static gboolean
1162 mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only, gboolean resume, gint32 *out_filter_idx, MonoJitInfo **out_ji)
1164 MonoDomain *domain = mono_domain_get ();
1165 MonoJitInfo *ji, rji;
1166 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1167 static void (*restore_context) (void *);
1168 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1169 MonoLMF *lmf = mono_get_lmf ();
1170 MonoArray *initial_trace_ips = NULL;
1171 GList *trace_ips = NULL;
1172 MonoException *mono_ex;
1173 gboolean stack_overflow = FALSE;
1174 MonoContext initial_ctx;
1175 int frame_count = 0;
1176 gboolean has_dynamic_methods = FALSE;
1177 gint32 filter_idx, first_filter_idx;
1180 g_assert (ctx != NULL);
1181 if (!obj) {
1182 MonoException *ex = mono_get_exception_null_reference ();
1183 MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object"));
1184 obj = (MonoObject *)ex;
1188 * Allocate a new exception object instead of the preconstructed ones.
1190 if (obj == domain->stack_overflow_ex) {
1192 * It is not a good idea to try and put even more pressure on the little stack available.
1193 * obj = mono_get_exception_stack_overflow ();
1195 stack_overflow = TRUE;
1197 else if (obj == domain->null_reference_ex) {
1198 obj = mono_get_exception_null_reference ();
1201 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1202 mono_ex = (MonoException*)obj;
1203 initial_trace_ips = mono_ex->trace_ips;
1204 } else {
1205 mono_ex = NULL;
1208 if (mono_ex && jit_tls->class_cast_from && !strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) {
1209 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1210 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1211 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
1212 mono_ex->message = mono_string_new (domain, msg);
1213 g_free (from_name);
1214 g_free (to_name);
1215 g_free (msg);
1218 if (!call_filter)
1219 call_filter = mono_get_call_filter ();
1221 if (!restore_context)
1222 restore_context = mono_get_restore_context ();
1224 g_assert (jit_tls->end_of_stack);
1225 g_assert (jit_tls->abort_func);
1227 if (!test_only) {
1228 MonoContext ctx_cp = *ctx;
1229 if (mono_trace_is_enabled ()) {
1230 MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0);
1231 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message);
1232 MonoObject *message;
1233 const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
1234 char *msg = NULL;
1235 MonoObject *exc = NULL;
1236 if (get_message == NULL) {
1237 message = NULL;
1238 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
1239 message = NULL;
1240 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
1241 } else {
1242 message = mono_runtime_invoke (get_message, obj, NULL, &exc);
1245 if (msg == NULL) {
1246 msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
1248 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
1249 g_free (msg);
1250 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
1251 mono_print_thread_dump_from_ctx (ctx);
1253 mono_profiler_exception_thrown (obj);
1254 if (!mono_handle_exception_internal (&ctx_cp, obj, original_ip, TRUE, FALSE, &first_filter_idx, out_ji)) {
1255 if (mono_break_on_exc)
1256 G_BREAKPOINT ();
1257 mono_debugger_agent_handle_exception (obj, ctx, NULL);
1258 // FIXME: This runs managed code so it might cause another stack overflow when
1259 // we are handling a stack overflow
1260 mono_unhandled_exception (obj);
1261 } else {
1262 mono_debugger_agent_handle_exception (obj, ctx, &ctx_cp);
1266 if (out_filter_idx)
1267 *out_filter_idx = -1;
1268 if (out_ji)
1269 *out_ji = NULL;
1270 filter_idx = 0;
1271 initial_ctx = *ctx;
1272 memset (&rji, 0, sizeof (rji));
1274 while (1) {
1275 MonoContext new_ctx;
1276 guint32 free_stack;
1278 ji = mono_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx,
1279 NULL, &lmf, NULL, NULL);
1280 if (!ji) {
1281 g_warning ("Exception inside function without unwind info");
1282 g_assert_not_reached ();
1285 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))))) {
1287 * The exception was raised in native code and we got back to managed code
1288 * using the LMF.
1290 *ctx = new_ctx;
1291 continue;
1294 if (ji != (gpointer)-1) {
1295 frame_count ++;
1296 //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
1298 if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1300 * Avoid overwriting the stack trace if the exception is
1301 * rethrown. Also avoid giant stack traces during a stack
1302 * overflow.
1304 if (!initial_trace_ips && (frame_count < 1000)) {
1305 trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1306 trace_ips = g_list_prepend (trace_ips,
1307 get_generic_info_from_stack_frame (ji, ctx));
1311 if (ji->method->dynamic)
1312 has_dynamic_methods = TRUE;
1314 if (stack_overflow)
1315 #ifndef MONO_ARCH_STACK_GROWS_UP
1316 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1317 #else
1318 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1319 #endif
1320 else
1321 free_stack = 0xffffff;
1324 * During stack overflow, wait till the unwinding frees some stack
1325 * space before running handlers/finalizers.
1327 if ((free_stack > (64 * 1024)) && ji->num_clauses) {
1328 int i;
1330 for (i = 0; i < ji->num_clauses; i++) {
1331 MonoJitExceptionInfo *ei = &ji->clauses [i];
1332 gboolean filtered = FALSE;
1334 #if defined(__s390__)
1336 * This is required in cases where a try block starts immediately after
1337 * a call which causes an exception. Testcase: tests/exception8.cs.
1338 * FIXME: Clean this up.
1340 if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) && MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
1341 #else
1342 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1343 #endif
1344 /* catch block */
1345 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1347 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
1348 if (ji->from_llvm) {
1349 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1350 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, obj);
1351 #else
1352 g_assert_not_reached ();
1353 #endif
1354 } else {
1355 /* store the exception object in bp + ei->exvar_offset */
1356 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
1360 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1361 if (test_only) {
1362 mono_perfcounters->exceptions_filters++;
1363 mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
1364 filtered = call_filter (ctx, ei->data.filter);
1365 if (filtered && out_filter_idx)
1366 *out_filter_idx = filter_idx;
1367 if (out_ji)
1368 *out_ji = ji;
1370 else {
1372 * Filter clauses should only be run in the
1373 * first pass of exception handling.
1375 filtered = (filter_idx == first_filter_idx);
1377 filter_idx ++;
1380 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
1381 mono_object_isinst (obj, catch_class)) || filtered) {
1382 if (test_only) {
1383 if (mono_ex && !initial_trace_ips) {
1384 trace_ips = g_list_reverse (trace_ips);
1385 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1386 if (has_dynamic_methods)
1387 /* These methods could go away anytime, so compute the stack trace now */
1388 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1390 g_list_free (trace_ips);
1392 return TRUE;
1395 * This guards against the situation that we abort a thread that is executing a finally clause
1396 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
1397 * check for this situation here and resume interruption if we are below the guarded block.
1399 if (G_UNLIKELY (jit_tls->handler_block_return_address)) {
1400 gboolean is_outside = FALSE;
1401 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->ex_ctx);
1402 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
1403 //FIXME make this stack direction aware
1404 if (catch_bp > prot_bp) {
1405 is_outside = TRUE;
1406 } else if (catch_bp == prot_bp) {
1407 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
1408 * So we check if the catch handler_start is protected by the guarded handler protected region
1410 * Assumptions:
1411 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
1412 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
1413 * There aren't any further finally/fault handler blocks down the stack over this exception.
1414 * This must be ensured by the code that installs the guard trampoline.
1416 g_assert (ji == mini_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (&jit_tls->ex_ctx), NULL));
1418 if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
1419 is_outside = TRUE;
1422 if (is_outside) {
1423 jit_tls->handler_block_return_address = NULL;
1424 jit_tls->handler_block = NULL;
1425 mono_thread_resume_interruption (); /*We ignore the exception here, it will be raised later*/
1429 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1430 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1431 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1432 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1433 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1434 *(mono_get_lmf_addr ()) = lmf;
1435 mono_perfcounters->exceptions_depth += frame_count;
1436 if (obj == domain->stack_overflow_ex)
1437 jit_tls->handling_stack_ovf = FALSE;
1439 return 0;
1441 if (!test_only && is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1442 (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
1443 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1444 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1445 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1446 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1447 call_filter (ctx, ei->handler_start);
1449 if (!test_only && is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1450 (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
1451 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1452 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1453 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1454 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1455 mono_perfcounters->exceptions_finallys++;
1456 *(mono_get_lmf_addr ()) = lmf;
1457 if (ji->from_llvm) {
1459 * LLVM compiled finally handlers follow the design
1460 * of the c++ ehabi, i.e. they call a resume function
1461 * at the end instead of returning to the caller.
1462 * So save the exception handling state,
1463 * mono_resume_unwind () will call us again to continue
1464 * the unwinding.
1466 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1467 *(mono_get_lmf_addr ()) = lmf;
1468 jit_tls->ex_ctx = new_ctx;
1469 jit_tls->ex_obj = obj;
1470 return 0;
1471 } else {
1472 call_filter (ctx, ei->handler_start);
1479 if (!test_only)
1480 mono_profiler_exception_method_leave (ji->method);
1483 *ctx = new_ctx;
1485 if (ji == (gpointer)-1) {
1487 if (!test_only) {
1488 *(mono_get_lmf_addr ()) = lmf;
1490 jit_tls->abort_func (obj);
1491 g_assert_not_reached ();
1492 } else {
1493 if (mono_ex && !initial_trace_ips) {
1494 trace_ips = g_list_reverse (trace_ips);
1495 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1496 if (has_dynamic_methods)
1497 /* These methods could go away anytime, so compute the stack trace now */
1498 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1500 g_list_free (trace_ips);
1501 return FALSE;
1506 g_assert_not_reached ();
1510 * mono_debugger_handle_exception:
1512 * Notify the debugger about exceptions. Returns TRUE if the debugger wants us to stop
1513 * at the exception and FALSE to resume with the normal exception handling.
1515 * The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
1516 * MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
1517 * `callq throw' instruction.
1519 gboolean
1520 mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
1522 MonoDebuggerExceptionAction action;
1524 if (!mono_debug_using_mono_debugger ())
1525 return FALSE;
1527 if (!obj) {
1528 MonoException *ex = mono_get_exception_null_reference ();
1529 MONO_OBJECT_SETREF (ex, message, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
1530 obj = (MonoObject *)ex;
1533 action = _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1535 if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP) {
1537 * The debugger wants us to stop on the `throw' instruction.
1538 * By the time we get here, it already inserted a breakpoint there.
1540 return TRUE;
1541 } else if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED) {
1542 MonoContext ctx_cp = *ctx;
1543 MonoJitInfo *ji = NULL;
1544 gboolean ret;
1547 * The debugger wants us to stop only if this exception is user-unhandled.
1550 ret = mono_handle_exception_internal (&ctx_cp, obj, MONO_CONTEXT_GET_IP (ctx), TRUE, FALSE, NULL, &ji);
1551 if (ret && (ji != NULL) && (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
1553 * The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
1554 * inside the method being invoked, so we handle it like a user-unhandled exception.
1556 ret = FALSE;
1559 if (!ret) {
1561 * The exception is user-unhandled - tell the debugger to stop.
1563 return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1567 * The exception is catched somewhere - resume with the normal exception handling and don't
1568 * stop in the debugger.
1572 return FALSE;
1576 * mono_debugger_run_finally:
1577 * @start_ctx: saved processor state
1579 * This method is called by the Mono Debugger to call all `finally' clauses of the
1580 * current stack frame. It's used when the user issues a `return' command to make
1581 * the current stack frame return. After returning from this method, the debugger
1582 * unwinds the stack one frame and gives control back to the user.
1584 * NOTE: This method is only used when running inside the Mono Debugger.
1586 void
1587 mono_debugger_run_finally (MonoContext *start_ctx)
1589 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1590 MonoDomain *domain = mono_domain_get ();
1591 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1592 MonoLMF *lmf = mono_get_lmf ();
1593 MonoContext ctx, new_ctx;
1594 MonoJitInfo *ji, rji;
1595 int i;
1597 ctx = *start_ctx;
1599 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1600 if (!ji || ji == (gpointer)-1)
1601 return;
1603 if (!call_filter)
1604 call_filter = mono_get_call_filter ();
1606 for (i = 0; i < ji->num_clauses; i++) {
1607 MonoJitExceptionInfo *ei = &ji->clauses [i];
1609 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
1610 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1611 call_filter (&ctx, ei->handler_start);
1617 * mono_handle_exception:
1618 * @ctx: saved processor state
1619 * @obj: the exception object
1620 * @test_only: only test if the exception is caught, but dont call handlers
1622 gboolean
1623 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
1625 if (!test_only)
1626 mono_perfcounters->exceptions_thrown++;
1628 return mono_handle_exception_internal (ctx, obj, original_ip, test_only, FALSE, NULL, NULL);
1631 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1633 #ifndef MONO_ARCH_USE_SIGACTION
1634 #error "Can't use sigaltstack without sigaction"
1635 #endif
1637 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1639 void
1640 mono_setup_altstack (MonoJitTlsData *tls)
1642 size_t stsize = 0;
1643 struct sigaltstack sa;
1644 guint8 *staddr = NULL;
1646 if (mono_running_on_valgrind ())
1647 return;
1649 mono_thread_get_stack_bounds (&staddr, &stsize);
1651 g_assert (staddr);
1653 tls->end_of_stack = staddr + stsize;
1655 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1657 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1658 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
1660 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1661 /* mprotect can fail for the main thread stack */
1662 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);
1663 g_assert (gaddr == tls->stack_ovf_guard_base);
1664 tls->stack_ovf_valloced = TRUE;
1668 * threads created by nptl does not seem to have a guard page, and
1669 * since the main thread is not created by us, we can't even set one.
1670 * Increasing stsize fools the SIGSEGV signal handler into thinking this
1671 * is a stack overflow exception.
1673 tls->stack_size = stsize + mono_pagesize ();
1675 /* Setup an alternate signal stack */
1676 tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
1677 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1679 g_assert (tls->signal_stack);
1681 sa.ss_sp = tls->signal_stack;
1682 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1683 sa.ss_flags = SS_ONSTACK;
1684 sigaltstack (&sa, NULL);
1687 void
1688 mono_free_altstack (MonoJitTlsData *tls)
1690 struct sigaltstack sa;
1691 int err;
1693 sa.ss_sp = tls->signal_stack;
1694 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1695 sa.ss_flags = SS_DISABLE;
1696 err = sigaltstack (&sa, NULL);
1697 g_assert (err == 0);
1699 if (tls->signal_stack)
1700 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1701 if (tls->stack_ovf_valloced)
1702 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size);
1703 else
1704 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1707 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1709 void
1710 mono_setup_altstack (MonoJitTlsData *tls)
1714 void
1715 mono_free_altstack (MonoJitTlsData *tls)
1719 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1721 static gboolean
1722 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
1724 gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
1725 /* we need to leave some room for throwing the exception */
1726 while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
1727 unprotect_size -= mono_pagesize ();
1728 /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1729 * is sufficient stack
1731 //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);
1732 if (unprotect_size)
1733 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
1734 return unprotect_size == jit_tls->stack_ovf_guard_size;
1737 static void
1738 try_more_restore (void)
1740 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1741 if (try_restore_stack_protection (jit_tls, 500))
1742 jit_tls->restore_stack_prot = NULL;
1745 static void
1746 restore_stack_protection (void)
1748 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1749 MonoException *ex = mono_domain_get ()->stack_overflow_ex;
1750 /* if we can't restore the stack protection, keep a callback installed so
1751 * we'll try to restore as much stack as we can at each return from unmanaged
1752 * code.
1754 if (try_restore_stack_protection (jit_tls, 4096))
1755 jit_tls->restore_stack_prot = NULL;
1756 else
1757 jit_tls->restore_stack_prot = try_more_restore_tramp;
1758 /* here we also throw a stack overflow exception */
1759 ex->trace_ips = NULL;
1760 ex->stack_trace = NULL;
1761 mono_raise_exception (ex);
1764 gpointer
1765 mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
1767 void (*func)(void) = (gpointer)tramp_data;
1768 func ();
1769 return NULL;
1772 gboolean
1773 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
1775 /* we got a stack overflow in the soft-guard pages
1776 * There are two cases:
1777 * 1) managed code caused the overflow: we unprotect the soft-guard page
1778 * and let the arch-specific code trigger the exception handling mechanism
1779 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1780 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1781 * and hope we can continue with those enabled, at least until the hard-guard page
1782 * is hit. The alternative to continuing here is to just print a message and abort.
1783 * We may add in the future the code to protect the pages again in the codepath
1784 * when we return from unmanaged to managed code.
1786 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
1787 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
1788 /* we unprotect the minimum amount we can */
1789 guint32 guard_size;
1790 gboolean handled = FALSE;
1792 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
1793 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
1794 guard_size -= mono_pagesize ();
1796 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
1797 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
1798 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);
1799 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1800 if (ji) {
1801 mono_arch_handle_altstack_exception (ctx, fault_addr, TRUE);
1802 handled = TRUE;
1804 #endif
1805 if (!handled) {
1806 /* We print a message: after this even managed stack overflows
1807 * may crash the runtime
1809 fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), fault_addr);
1810 if (!jit_tls->handling_stack_ovf) {
1811 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
1812 jit_tls->handling_stack_ovf = 1;
1813 } else {
1814 /*fprintf (stderr, "Already handling stack overflow\n");*/
1817 return TRUE;
1819 return FALSE;
1822 static gboolean
1823 print_stack_frame (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed, gpointer data)
1825 FILE *stream = (FILE*)data;
1827 if (method) {
1828 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1829 fprintf (stream, " %s\n", location);
1830 g_free (location);
1831 } else
1832 fprintf (stream, " at <unknown> <0x%05x>\n", native_offset);
1834 return FALSE;
1837 static G_GNUC_UNUSED gboolean
1838 print_stack_frame_to_string (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed,
1839 gpointer data)
1841 GString *p = (GString*)data;
1843 if (method) {
1844 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1845 g_string_append_printf (p, " %s\n", location);
1846 g_free (location);
1847 } else
1848 g_string_append_printf (p, " at <unknown> <0x%05x>\n", native_offset);
1850 return FALSE;
1853 static gboolean handling_sigsegv = FALSE;
1856 * mono_handle_native_sigsegv:
1858 * Handle a SIGSEGV received while in native code by printing diagnostic
1859 * information and aborting.
1861 void
1862 mono_handle_native_sigsegv (int signal, void *ctx)
1864 #ifdef MONO_ARCH_USE_SIGACTION
1865 struct sigaction sa;
1866 #endif
1867 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1869 if (handling_sigsegv)
1870 return;
1872 if (mini_get_debug_options ()->suspend_on_sigsegv) {
1873 fprintf (stderr, "Received SIGSEGV, suspending...");
1874 while (1)
1878 /* To prevent infinite loops when the stack walk causes a crash */
1879 handling_sigsegv = TRUE;
1881 /* !jit_tls means the thread was not registered with the runtime */
1882 if (jit_tls && mono_thread_internal_current ()) {
1883 fprintf (stderr, "Stacktrace:\n\n");
1885 mono_jit_walk_stack (print_stack_frame, TRUE, stderr);
1887 fflush (stderr);
1890 #ifdef HAVE_BACKTRACE_SYMBOLS
1892 void *array [256];
1893 char **names;
1894 int i, size;
1895 const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
1897 fprintf (stderr, "\nNative stacktrace:\n\n");
1899 size = backtrace (array, 256);
1900 names = backtrace_symbols (array, size);
1901 for (i =0; i < size; ++i) {
1902 fprintf (stderr, "\t%s\n", names [i]);
1904 free (names);
1906 fflush (stderr);
1908 /* Try to get more meaningful information using gdb */
1910 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
1911 if (!mini_get_debug_options ()->no_gdb_backtrace && !mono_debug_using_mono_debugger ()) {
1912 /* From g_spawn_command_line_sync () in eglib */
1913 int res;
1914 int stdout_pipe [2] = { -1, -1 };
1915 pid_t pid;
1916 int status;
1917 char buffer [1024];
1919 res = pipe (stdout_pipe);
1920 g_assert (res != -1);
1922 //pid = fork ();
1924 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1925 * it will deadlock. Call the syscall directly instead.
1927 pid = mono_runtime_syscall_fork ();
1929 if (pid == 0) {
1930 close (stdout_pipe [0]);
1931 dup2 (stdout_pipe [1], STDOUT_FILENO);
1933 for (i = getdtablesize () - 1; i >= 3; i--)
1934 close (i);
1936 if (!mono_gdb_render_native_backtraces ())
1937 close (STDOUT_FILENO);
1939 exit (1);
1942 close (stdout_pipe [1]);
1944 fprintf (stderr, "\nDebug info from gdb:\n\n");
1946 while (1) {
1947 int nread = read (stdout_pipe [0], buffer, 1024);
1949 if (nread <= 0)
1950 break;
1951 write (STDERR_FILENO, buffer, nread);
1954 waitpid (pid, &status, WNOHANG);
1956 #endif
1958 * A SIGSEGV indicates something went very wrong so we can no longer depend
1959 * on anything working. So try to print out lots of diagnostics, starting
1960 * with ones which have a greater chance of working.
1962 fprintf (stderr,
1963 "\n"
1964 "=================================================================\n"
1965 "Got a %s while executing native code. This usually indicates\n"
1966 "a fatal error in the mono runtime or one of the native libraries \n"
1967 "used by your application.\n"
1968 "=================================================================\n"
1969 "\n", signal_str);
1972 #endif
1974 #ifdef MONO_ARCH_USE_SIGACTION
1976 /* Remove our SIGABRT handler */
1977 sa.sa_handler = SIG_DFL;
1978 sigemptyset (&sa.sa_mask);
1979 sa.sa_flags = 0;
1981 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
1983 #endif
1985 abort ();
1988 static void
1989 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
1991 MonoInternalThread *thread = mono_thread_internal_current ();
1992 #if defined(__i386__) || defined(__x86_64__)
1993 MonoContext ctx;
1994 #endif
1995 GString* text = g_string_new (0);
1996 char *name, *wapi_desc;
1997 GError *error = NULL;
1999 if (thread->name) {
2000 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
2001 g_assert (!error);
2002 g_string_append_printf (text, "\n\"%s\"", name);
2003 g_free (name);
2005 else if (thread->threadpool_thread)
2006 g_string_append (text, "\n\"<threadpool thread>\"");
2007 else
2008 g_string_append (text, "\n\"<unnamed thread>\"");
2010 #ifndef HOST_WIN32
2011 wapi_desc = wapi_current_thread_desc ();
2012 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
2013 free (wapi_desc);
2014 #endif
2016 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2017 if (start_ctx) {
2018 memcpy (&ctx, start_ctx, sizeof (MonoContext));
2019 } else if (!sigctx)
2020 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
2021 else
2022 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
2024 mono_jit_walk_stack_from_ctx (print_stack_frame_to_string, &ctx, TRUE, text);
2025 #else
2026 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
2027 #endif
2029 fprintf (stdout, "%s", text->str);
2030 g_string_free (text, TRUE);
2031 fflush (stdout);
2035 * mono_print_thread_dump:
2037 * Print information about the current thread to stdout.
2038 * SIGCTX can be NULL, allowing this to be called from gdb.
2040 void
2041 mono_print_thread_dump (void *sigctx)
2043 mono_print_thread_dump_internal (sigctx, NULL);
2046 void
2047 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2049 mono_print_thread_dump_internal (NULL, ctx);
2053 * mono_resume_unwind:
2055 * This is called by code at the end of LLVM compiled finally clauses to continue
2056 * unwinding.
2058 void
2059 mono_resume_unwind (void)
2061 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2062 static void (*restore_context) (MonoContext *);
2063 MonoContext ctx;
2065 memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));
2067 mono_handle_exception_internal (&ctx, jit_tls->ex_obj, NULL, FALSE, TRUE, NULL, NULL);
2069 if (!restore_context)
2070 restore_context = mono_get_restore_context ();
2072 restore_context (&ctx);
2075 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
2077 typedef struct {
2078 MonoJitInfo *ji;
2079 MonoContext ctx;
2080 MonoJitExceptionInfo *ei;
2081 } FindHandlerBlockData;
2083 static gboolean
2084 find_last_handler_block (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
2086 int i;
2087 gpointer ip;
2088 FindHandlerBlockData *pdata = data;
2090 if (ji->method->wrapper_type)
2091 return FALSE;
2093 ip = MONO_CONTEXT_GET_IP (ctx);
2095 for (i = 0; i < ji->num_clauses; ++i) {
2096 MonoJitExceptionInfo *ei = ji->clauses + i;
2097 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2098 continue;
2099 /*If ip points to the first instruction it means the handler block didn't start
2100 so we can leave its execution to the EH machinery*/
2101 if (ei->handler_start < ip && ip < ei->data.handler_end) {
2102 pdata->ji = ji;
2103 pdata->ei = ei;
2104 pdata->ctx = *ctx;
2105 break;
2108 return FALSE;
2112 static gpointer
2113 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
2115 int i;
2116 MonoJitExceptionInfo *clause = NULL;
2117 gpointer ip;
2119 ip = MONO_CONTEXT_GET_IP (ctx);
2121 for (i = 0; i < ji->num_clauses; ++i) {
2122 clause = &ji->clauses [i];
2123 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2124 continue;
2125 if (clause->handler_start < ip && clause->data.handler_end > ip)
2126 break;
2129 /*no matching finally */
2130 if (i == ji->num_clauses)
2131 return NULL;
2133 /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
2134 if (ip == clause->handler_start)
2135 return NULL;
2137 return mono_arch_install_handler_block_guard (ji, clause, ctx, mono_create_handler_block_trampoline ());
2141 * Finds the bottom handler block running and install a block guard if needed.
2143 gboolean
2144 mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx)
2146 FindHandlerBlockData data = { 0 };
2147 MonoDomain *domain = mono_domain_get ();
2148 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2149 gpointer resume_ip;
2151 if (jit_tls->handler_block_return_address)
2152 return FALSE;
2154 mono_walk_stack_full (domain, jit_tls, ctx, find_last_handler_block, FALSE, &data);
2156 if (!data.ji)
2157 return FALSE;
2159 memcpy (&jit_tls->ex_ctx, &data.ctx, sizeof (MonoContext));
2161 resume_ip = install_handler_block_guard (data.ji, &data.ctx);
2162 if (resume_ip == NULL)
2163 return FALSE;
2165 jit_tls->handler_block_return_address = resume_ip;
2166 jit_tls->handler_block = data.ei;
2168 #ifndef HOST_WIN32
2169 /*Clear current thread from been wapi interrupted otherwise things can go south*/
2170 wapi_clear_interruption ();
2171 #endif
2172 return TRUE;
2175 #else
2176 gboolean
2177 mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx)
2179 return FALSE;
2182 #endif