2010-03-22 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / mini-exceptions.c
blobae29d7783f5b802836f296fda94fcfe87df56e8b
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);
67 void
68 mono_exceptions_init (void)
70 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
71 guint32 code_size;
72 MonoJumpInfo *ji;
74 if (mono_aot_only) {
75 restore_context_func = mono_aot_get_named_code ("restore_context");
76 call_filter_func = mono_aot_get_named_code ("call_filter");
77 throw_exception_func = mono_aot_get_named_code ("throw_exception");
78 rethrow_exception_func = mono_aot_get_named_code ("rethrow_exception");
79 } else {
80 restore_context_func = mono_arch_get_restore_context_full (&code_size, &ji, FALSE);
81 call_filter_func = mono_arch_get_call_filter_full (&code_size, &ji, FALSE);
82 throw_exception_func = mono_arch_get_throw_exception_full (&code_size, &ji, FALSE);
83 rethrow_exception_func = mono_arch_get_rethrow_exception_full (&code_size, &ji, FALSE);
85 #else
86 restore_context_func = mono_arch_get_restore_context ();
87 call_filter_func = mono_arch_get_call_filter ();
88 throw_exception_func = mono_arch_get_throw_exception ();
89 rethrow_exception_func = mono_arch_get_rethrow_exception ();
90 #endif
91 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
92 try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
93 restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
94 #endif
96 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
97 mono_arch_exceptions_init ();
98 #endif
101 gpointer
102 mono_get_throw_exception (void)
104 g_assert (throw_exception_func);
105 return throw_exception_func;
108 gpointer
109 mono_get_rethrow_exception (void)
111 g_assert (rethrow_exception_func);
112 return rethrow_exception_func;
115 gpointer
116 mono_get_call_filter (void)
118 g_assert (call_filter_func);
119 return call_filter_func;
122 gpointer
123 mono_get_restore_context (void)
125 g_assert (restore_context_func);
126 return restore_context_func;
129 gpointer
130 mono_get_throw_exception_by_name (void)
132 #ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME
134 gpointer code = NULL;
135 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
136 guint32 code_size;
137 MonoJumpInfo *ji;
138 #endif
140 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
141 if (throw_exception_by_name_func)
142 return throw_exception_by_name_func;
144 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
145 if (mono_aot_only)
146 code = mono_aot_get_named_code ("throw_exception_by_name");
147 else
148 code = mono_arch_get_throw_exception_by_name_full (&code_size, &ji, FALSE);
149 #else
150 code = mono_arch_get_throw_exception_by_name ();
151 #endif
153 mono_memory_barrier ();
155 throw_exception_by_name_func = code;
157 #else
159 throw_exception_by_name_func = NULL;
161 g_assert_not_reached ();
162 #endif
164 return throw_exception_by_name_func;
167 gpointer
168 mono_get_throw_corlib_exception (void)
170 gpointer code = NULL;
171 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
172 guint32 code_size;
173 MonoJumpInfo *ji;
174 #endif
176 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
177 if (throw_corlib_exception_func)
178 return throw_corlib_exception_func;
180 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
181 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
182 if (mono_aot_only)
183 code = mono_aot_get_named_code ("throw_corlib_exception");
184 else
185 code = mono_arch_get_throw_corlib_exception_full (&code_size, &ji, FALSE);
186 #else
187 code = mono_arch_get_throw_corlib_exception ();
188 #endif
189 #else
190 g_assert_not_reached ();
191 #endif
193 mono_memory_barrier ();
195 throw_corlib_exception_func = code;
197 return throw_corlib_exception_func;
200 static gboolean
201 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
203 MonoTryBlockHoleTableJitInfo *table;
204 int i;
205 guint32 offset;
206 guint16 clause;
208 /*FIXME check if under s390 it should be ei->try_start >= ip*/
209 if (ei->try_start > ip || ip >= ei->try_end)
210 return FALSE;
212 if (!ji->has_try_block_holes)
213 return TRUE;
215 table = mono_jit_info_get_try_block_hole_table_info (ji);
216 offset = (guint32)((char*)ip - (char*)ji->code_start);
217 clause = (guint16)(ei - ji->clauses);
218 g_assert (clause < ji->num_clauses);
220 for (i = 0; i < table->num_holes; ++i) {
221 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
222 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
223 return FALSE;
225 return TRUE;
228 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
231 * find_jit_info_no_ext:
233 * If the target has the find_jit_info_ext version of this function, define the old
234 * version here which translates between the old and new APIs.
236 static MonoJitInfo *
237 find_jit_info_no_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
238 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
240 StackFrameInfo frame;
241 MonoJitInfo *ji;
242 gboolean err;
243 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
245 /* Avoid costly table lookup during stack overflow */
246 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
247 ji = prev_ji;
248 else
249 ji = mini_jit_info_table_find (domain, ip, NULL);
251 if (managed)
252 *managed = FALSE;
254 err = mono_arch_find_jit_info_ext (domain, jit_tls, ji, ctx, new_ctx, lmf, &frame);
255 if (!err)
256 return (gpointer)-1;
258 /* Convert between the new and the old APIs */
259 switch (frame.type) {
260 case FRAME_TYPE_MANAGED:
261 if (managed)
262 *managed = TRUE;
263 return ji;
264 case FRAME_TYPE_MANAGED_TO_NATIVE:
265 if (frame.ji)
266 return frame.ji;
267 else {
268 memset (res, 0, sizeof (MonoJitInfo));
269 res->method = frame.method;
270 return res;
272 case FRAME_TYPE_DEBUGGER_INVOKE: {
273 MonoContext tmp_ctx;
276 * The normal exception handling code can't handle this frame, so just
277 * skip it.
279 ji = find_jit_info_no_ext (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
280 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
281 return ji;
283 default:
284 g_assert_not_reached ();
285 return NULL;
289 #endif
291 /* mono_find_jit_info:
293 * This function is used to gather information from @ctx. It return the
294 * MonoJitInfo of the corresponding function, unwinds one stack frame and
295 * stores the resulting context into @new_ctx. It also stores a string
296 * describing the stack location into @trace (if not NULL), and modifies
297 * the @lmf if necessary. @native_offset return the IP offset from the
298 * start of the function or -1 if that info is not available.
300 MonoJitInfo *
301 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
302 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
303 gboolean *managed)
305 gboolean managed2;
306 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
307 MonoJitInfo *ji;
309 if (trace)
310 *trace = NULL;
312 if (native_offset)
313 *native_offset = -1;
315 if (managed)
316 *managed = FALSE;
318 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
319 ji = find_jit_info_no_ext (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
320 #else
321 ji = mono_arch_find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
322 #endif
324 if (ji == (gpointer)-1)
325 return ji;
327 if (managed2 || (ji && ji->method->wrapper_type)) {
328 const char *real_ip, *start;
329 gint32 offset;
331 start = (const char *)ji->code_start;
332 if (!managed2)
333 /* ctx->ip points into native code */
334 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
335 else
336 real_ip = (const char*)ip;
338 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
339 offset = real_ip - start;
340 else
341 offset = -1;
343 if (native_offset)
344 *native_offset = offset;
346 if (managed)
347 if (!ji->method->wrapper_type)
348 *managed = TRUE;
350 if (trace)
351 *trace = mono_debug_print_stack_frame (ji->method, offset, domain);
352 } else {
353 if (trace) {
354 char *fname = mono_method_full_name (res->method, TRUE);
355 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
356 g_free (fname);
360 return ji;
363 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
366 * mono_find_jit_info_ext:
368 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
369 * structure.
371 gboolean
372 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
373 MonoJitInfo *prev_ji, MonoContext *ctx,
374 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
375 StackFrameInfo *frame)
377 gboolean err;
378 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
379 MonoJitInfo *ji;
380 MonoDomain *target_domain;
382 if (trace)
383 *trace = NULL;
385 /* Avoid costly table lookup during stack overflow */
386 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
387 ji = prev_ji;
388 else
389 ji = mini_jit_info_table_find (domain, ip, &target_domain);
391 if (!target_domain)
392 target_domain = domain;
394 err = mono_arch_find_jit_info_ext (target_domain, jit_tls, ji, ctx, new_ctx, lmf, frame);
395 if (!err)
396 return FALSE;
398 frame->native_offset = -1;
399 frame->domain = target_domain;
401 ji = frame->ji;
403 if (ji && (frame->managed || ji->method->wrapper_type)) {
404 const char *real_ip, *start;
406 start = (const char *)ji->code_start;
407 if (!frame->managed)
408 /* ctx->ip points into native code */
409 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
410 else
411 real_ip = (const char*)ip;
413 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
414 frame->native_offset = real_ip - start;
415 else
416 frame->native_offset = -1;
418 if (trace)
419 *trace = mono_debug_print_stack_frame (ji->method, frame->native_offset, domain);
420 } else {
421 if (trace && frame->method) {
422 char *fname = mono_method_full_name (frame->method, TRUE);
423 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
424 g_free (fname);
428 return TRUE;
431 #endif /* MONO_ARCH_HAVE_FIND_JIT_INFO_EXT */
433 static gpointer
434 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
436 MonoGenericJitInfo *gi;
437 gpointer info;
439 if (!ji->has_generic_jit_info)
440 return NULL;
441 gi = mono_jit_info_get_generic_jit_info (ji);
442 if (!gi->has_this)
443 return NULL;
445 if (gi->this_in_reg)
446 info = mono_arch_context_get_int_reg (ctx, gi->this_reg);
447 else
448 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
449 gi->this_offset);
450 if (mono_method_get_context (ji->method)->method_inst) {
451 return info;
452 } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
453 return info;
454 } else {
455 /* Avoid returning a managed object */
456 MonoObject *this_obj = info;
458 return this_obj->vtable->klass;
462 static MonoGenericContext
463 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
465 MonoGenericContext context = { NULL, NULL };
466 MonoClass *class, *method_container_class;
468 g_assert (generic_info);
470 g_assert (ji->method->is_inflated);
471 if (mono_method_get_context (ji->method)->method_inst) {
472 MonoMethodRuntimeGenericContext *mrgctx = generic_info;
474 class = mrgctx->class_vtable->klass;
475 context.method_inst = mrgctx->method_inst;
476 g_assert (context.method_inst);
477 } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
478 MonoVTable *vtable = generic_info;
480 class = vtable->klass;
481 } else {
482 class = generic_info;
485 //g_assert (!ji->method->klass->generic_container);
486 if (ji->method->klass->generic_class)
487 method_container_class = ji->method->klass->generic_class->container_class;
488 else
489 method_container_class = ji->method->klass;
491 /* class might refer to a subclass of ji->method's class */
492 while (class->generic_class && class->generic_class->container_class != method_container_class) {
493 class = class->parent;
494 g_assert (class);
497 if (class->generic_class || class->generic_container)
498 context.class_inst = mini_class_get_context (class)->class_inst;
500 if (class->generic_class)
501 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class->container_class, method_container_class));
502 else
503 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class));
505 return context;
508 static MonoMethod*
509 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
511 MonoGenericContext context;
512 MonoMethod *method;
514 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
515 return ji->method;
516 context = get_generic_context_from_stack_frame (ji, generic_info);
518 method = mono_method_get_declaring_generic_method (ji->method);
519 method = mono_class_inflate_generic_method (method, &context);
521 return method;
524 MonoString *
525 ves_icall_System_Exception_get_trace (MonoException *ex)
527 MonoDomain *domain = mono_domain_get ();
528 MonoString *res;
529 MonoArray *ta = ex->trace_ips;
530 int i, len;
531 GString *trace_str;
533 if (ta == NULL)
534 /* Exception is not thrown yet */
535 return NULL;
537 len = mono_array_length (ta) >> 1;
538 trace_str = g_string_new ("");
539 for (i = 0; i < len; i++) {
540 MonoJitInfo *ji;
541 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
542 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
544 ji = mono_jit_info_table_find (domain, ip);
545 if (ji == NULL) {
546 /* Unmanaged frame */
547 g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
548 } else {
549 gchar *location;
550 gint32 address;
551 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
553 address = (char *)ip - (char *)ji->code_start;
554 location = mono_debug_print_stack_frame (
555 method, address, ex->object.vtable->domain);
557 g_string_append_printf (trace_str, "%s\n", location);
558 g_free (location);
562 res = mono_string_new (ex->object.vtable->domain, trace_str->str);
563 g_string_free (trace_str, TRUE);
565 return res;
568 MonoArray *
569 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
571 MonoDomain *domain = mono_domain_get ();
572 MonoArray *res;
573 MonoArray *ta = exc->trace_ips;
574 MonoDebugSourceLocation *location;
575 int i, len;
577 if (ta == NULL) {
578 /* Exception is not thrown yet */
579 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
582 len = mono_array_length (ta) >> 1;
584 res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
586 for (i = skip; i < len; i++) {
587 MonoJitInfo *ji;
588 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
589 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
590 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
591 MonoMethod *method;
593 ji = mono_jit_info_table_find (domain, ip);
594 if (ji == NULL) {
595 /* Unmanaged frame */
596 mono_array_setref (res, i, sf);
597 continue;
600 g_assert (ji != NULL);
602 method = get_method_from_stack_frame (ji, generic_info);
603 if (ji->method->wrapper_type) {
604 char *s;
606 sf->method = NULL;
607 s = mono_method_full_name (method, TRUE);
608 MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
609 g_free (s);
611 else
612 MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
613 sf->native_offset = (char *)ip - (char *)ji->code_start;
616 * mono_debug_lookup_source_location() returns both the file / line number information
617 * and the IL offset. Note that computing the IL offset is already an expensive
618 * operation, so we shouldn't call this method twice.
620 location = mono_debug_lookup_source_location (ji->method, sf->native_offset, domain);
621 if (location)
622 sf->il_offset = location->il_offset;
623 else
624 sf->il_offset = 0;
626 if (need_file_info) {
627 if (location && location->source_file) {
628 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
629 sf->line = location->row;
630 sf->column = location->column;
631 } else {
632 sf->line = sf->column = 0;
633 sf->filename = NULL;
637 mono_debug_free_source_location (location);
638 mono_array_setref (res, i, sf);
641 return res;
645 * mono_walk_stack:
646 * @domain: starting appdomain
647 * @jit_tls: JIT data for the thread
648 * @start_ctx: starting state of the stack frame
649 * @func: callback to call for each stack frame
650 * @user_data: data passed to the callback
652 * This function walks the stack of a thread, starting from the state
653 * represented by jit_tls and start_ctx. For each frame the callback
654 * function is called with the relevant info. The walk ends when no more
655 * managed stack frames are found or when the callback returns a TRUE value.
656 * Note that the function can be used to walk the stack of a thread
657 * different from the current.
659 void
660 mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gpointer user_data)
662 MonoLMF *lmf = mono_get_lmf ();
663 MonoJitInfo *ji, rji;
664 gint native_offset;
665 gboolean managed;
666 MonoContext ctx, new_ctx;
668 ctx = *start_ctx;
670 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
672 * FIXME: mono_find_jit_info () will need to be able to return a different
673 * MonoDomain when apddomain transitions are found on the stack.
675 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
676 if (!ji || ji == (gpointer)-1)
677 return;
679 if (func (domain, &new_ctx, ji, user_data))
680 return;
682 ctx = new_ctx;
686 void
687 mono_jit_walk_stack_from_ctx (MonoStackWalk func, MonoContext *start_ctx, gboolean do_il_offset, gpointer user_data)
689 MonoDomain *domain = mono_domain_get ();
690 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
691 MonoLMF *lmf = mono_get_lmf ();
692 MonoJitInfo *ji, rji;
693 gint native_offset, il_offset;
694 gboolean managed;
695 MonoContext ctx, new_ctx;
697 MONO_ARCH_CONTEXT_DEF
699 mono_arch_flush_register_windows ();
701 if (start_ctx) {
702 memcpy (&ctx, start_ctx, sizeof (MonoContext));
703 } else {
704 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
705 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
706 #else
707 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_jit_walk_stack_from_ctx);
708 #endif
711 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
712 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
713 g_assert (ji);
715 if (ji == (gpointer)-1)
716 return;
718 if (do_il_offset) {
719 MonoDebugSourceLocation *source;
721 source = mono_debug_lookup_source_location (ji->method, native_offset, domain);
722 il_offset = source ? source->il_offset : -1;
723 mono_debug_free_source_location (source);
724 } else
725 il_offset = -1;
727 if (func (ji->method, native_offset, il_offset, managed, user_data))
728 return;
730 ctx = new_ctx;
734 void
735 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data)
737 mono_jit_walk_stack_from_ctx (func, NULL, do_il_offset, user_data);
740 void
741 mono_jit_walk_stack_from_ctx_in_thread (MonoJitStackWalk func, MonoDomain *domain, MonoContext *start_ctx, gboolean do_il_offset, MonoInternalThread *thread, MonoLMF *lmf, gpointer user_data)
743 MonoJitTlsData *jit_tls = thread->jit_data;
744 gint il_offset;
745 MonoContext ctx, new_ctx;
746 StackFrameInfo frame;
747 #ifndef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
748 gint native_offset;
749 gboolean managed;
750 MonoJitInfo *ji, rji;
751 #else
752 gboolean res;
753 #endif
755 MONO_ARCH_CONTEXT_DEF
757 mono_arch_flush_register_windows ();
759 if (start_ctx) {
760 memcpy (&ctx, start_ctx, sizeof (MonoContext));
761 } else {
762 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
763 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
764 #else
765 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_jit_walk_stack_from_ctx);
766 #endif
767 g_assert (thread == mono_thread_internal_current ());
770 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
771 frame.lmf = lmf;
772 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
773 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, &frame);
774 if (!res)
775 return;
776 #else
777 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
778 g_assert (ji);
779 frame.type = FRAME_TYPE_MANAGED;
780 frame.ji = ji;
781 frame.managed = managed;
782 frame.native_offset = native_offset;
784 if (ji == (gpointer)-1)
785 return;
786 #endif
788 if (do_il_offset && frame.ji) {
789 MonoDebugSourceLocation *source;
791 source = mono_debug_lookup_source_location (frame.ji->method, frame.native_offset, domain);
792 il_offset = source ? source->il_offset : -1;
793 mono_debug_free_source_location (source);
794 } else
795 il_offset = -1;
797 frame.il_offset = il_offset;
799 if (func (&frame, &ctx, user_data))
800 return;
802 ctx = new_ctx;
807 MonoBoolean
808 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
809 MonoReflectionMethod **method,
810 gint32 *iloffset, gint32 *native_offset,
811 MonoString **file, gint32 *line, gint32 *column)
813 MonoDomain *domain = mono_domain_get ();
814 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
815 MonoLMF *lmf = mono_get_lmf ();
816 MonoJitInfo *ji, rji;
817 MonoContext ctx, new_ctx, ji_ctx;
818 MonoDebugSourceLocation *location;
819 MonoMethod *last_method = NULL, *actual_method;
821 MONO_ARCH_CONTEXT_DEF;
823 mono_arch_flush_register_windows ();
825 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
826 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
827 #else
828 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
829 #endif
831 do {
832 ji_ctx = ctx;
833 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, (int*) native_offset, NULL);
834 ctx = new_ctx;
836 if (ji && ji != (gpointer)-1 &&
837 MONO_CONTEXT_GET_IP (&ctx) >= ji->code_start &&
838 (guint8*)MONO_CONTEXT_GET_IP (&ctx) < (guint8*)ji->code_start + ji->code_size) {
839 ji_ctx = ctx;
842 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_SP (&ctx) >= jit_tls->end_of_stack)
843 return FALSE;
845 /* skip all wrappers ??*/
846 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
847 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
848 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
849 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
850 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE ||
851 ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
852 continue;
854 if (ji->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE && ji->method == last_method) {
856 * FIXME: Native-to-managed wrappers sometimes show up twice.
857 * Probably the whole mono_find_jit_info () stuff needs to be fixed so this
858 * isn't needed.
860 continue;
863 last_method = ji->method;
865 skip--;
867 } while (skip >= 0);
869 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ji_ctx));
871 mono_gc_wbarrier_generic_store (method, (MonoObject*) mono_method_get_object (domain, actual_method, NULL));
873 location = mono_debug_lookup_source_location (ji->method, *native_offset, domain);
874 if (location)
875 *iloffset = location->il_offset;
876 else
877 *iloffset = 0;
879 if (need_file_info) {
880 if (location) {
881 mono_gc_wbarrier_generic_store (file, (MonoObject*) mono_string_new (domain, location->source_file));
882 *line = location->row;
883 *column = location->column;
884 } else {
885 *file = NULL;
886 *line = *column = 0;
890 mono_debug_free_source_location (location);
892 return TRUE;
895 typedef struct {
896 guint32 skips;
897 MonoSecurityFrame *frame;
898 } MonoFrameSecurityInfo;
900 static gboolean
901 callback_get_first_frame_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
903 MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
905 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
906 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
907 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
908 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
909 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
910 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
911 return FALSE;
914 if (si->skips > 0) {
915 si->skips--;
916 return FALSE;
919 si->frame = mono_declsec_create_frame (domain, ji);
921 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
922 return TRUE;
926 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
927 * @skip: the number of stack frames to skip
929 * This function returns a the security informations of a single stack frame
930 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
931 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
932 * evaluated.
934 MonoSecurityFrame*
935 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
937 MonoDomain *domain = mono_domain_get ();
938 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
939 MonoFrameSecurityInfo si;
940 MonoContext ctx;
942 MONO_ARCH_CONTEXT_DEF
944 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
945 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
946 #else
947 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
948 #endif
950 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
951 skip--;
952 #endif
954 si.skips = skip;
955 si.frame = NULL;
956 mono_walk_stack (domain, jit_tls, &ctx, callback_get_first_frame_security_info, (gpointer)&si);
958 return (si.skips == 0) ? si.frame : NULL;
962 typedef struct {
963 guint32 skips;
964 MonoArray *stack;
965 guint32 count;
966 guint32 maximum;
967 } MonoSecurityStack;
969 static void
970 grow_array (MonoSecurityStack *stack)
972 MonoDomain *domain = mono_domain_get ();
973 guint32 newsize = (stack->maximum << 1);
974 MonoArray *newstack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, newsize);
975 int i;
976 for (i=0; i < stack->maximum; i++) {
977 gpointer frame = mono_array_get (stack->stack, gpointer, i);
978 mono_array_setref (newstack, i, frame);
980 stack->maximum = newsize;
981 stack->stack = newstack;
984 static gboolean
985 callback_get_stack_frames_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
987 MonoSecurityStack *ss = (MonoSecurityStack*) data;
989 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
990 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
991 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
992 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
993 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
994 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
995 return FALSE;
998 if (ss->skips > 0) {
999 ss->skips--;
1000 return FALSE;
1003 if (ss->count == ss->maximum)
1004 grow_array (ss);
1006 mono_array_setref (ss->stack, ss->count++, mono_declsec_create_frame (domain, ji));
1008 /* continue down the stack */
1009 return FALSE;
1012 static MonoArray *
1013 glist_to_array (GList *list, MonoClass *eclass)
1015 MonoDomain *domain = mono_domain_get ();
1016 MonoArray *res;
1017 int len, i;
1019 if (!list)
1020 return NULL;
1022 len = g_list_length (list);
1023 res = mono_array_new (domain, eclass, len);
1025 for (i = 0; list; list = list->next, i++)
1026 mono_array_set (res, gpointer, i, list->data);
1028 return res;
1032 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
1033 * @skip: the number of stack frames to skip
1035 * This function returns an managed array of containing the security
1036 * informations for each frame (after the skipped ones). This is used for
1037 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
1038 * required.
1040 MonoArray*
1041 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
1043 MonoDomain *domain = mono_domain_get ();
1044 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1045 MonoSecurityStack ss;
1046 MonoContext ctx;
1048 MONO_ARCH_CONTEXT_DEF
1050 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1051 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
1052 #else
1053 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityStack);
1054 #endif
1056 #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
1057 skip--;
1058 #endif
1060 ss.skips = skip;
1061 ss.count = 0;
1062 ss.maximum = MONO_CAS_INITIAL_STACK_SIZE;
1063 ss.stack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, ss.maximum);
1064 mono_walk_stack (domain, jit_tls, &ctx, callback_get_stack_frames_security_info, (gpointer)&ss);
1065 /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
1066 return ss.stack;
1069 static MonoClass*
1070 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1072 MonoClass *catch_class = ei->data.catch_class;
1073 MonoType *inflated_type;
1074 MonoGenericContext context;
1076 if (!catch_class)
1077 return NULL;
1079 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1080 return catch_class;
1081 context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1083 /* FIXME: we shouldn't inflate but instead put the
1084 type in the rgctx and fetch it from there. It
1085 might be a good idea to do this lazily, i.e. only
1086 when the exception is actually thrown, so as not to
1087 waste space for exception clauses which might never
1088 be encountered. */
1089 inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
1090 catch_class = mono_class_from_mono_type (inflated_type);
1091 mono_metadata_free_type (inflated_type);
1093 return catch_class;
1097 * mini_jit_info_table_find:
1099 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1100 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1101 * OUT_DOMAIN if it is not NULL.
1103 MonoJitInfo*
1104 mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
1106 MonoJitInfo *ji;
1107 MonoInternalThread *t = mono_thread_internal_current ();
1108 GSList *l;
1110 if (out_domain)
1111 *out_domain = NULL;
1113 ji = mono_jit_info_table_find (domain, addr);
1114 if (ji) {
1115 if (out_domain)
1116 *out_domain = domain;
1117 return ji;
1120 /* maybe it is shared code, so we also search in the root domain */
1121 if (domain != mono_get_root_domain ()) {
1122 ji = mono_jit_info_table_find (mono_get_root_domain (), addr);
1123 if (ji) {
1124 if (out_domain)
1125 *out_domain = mono_get_root_domain ();
1126 return ji;
1130 for (l = t->appdomain_refs; l; l = l->next) {
1131 if (l->data != domain) {
1132 ji = mono_jit_info_table_find ((MonoDomain*)l->data, addr);
1133 if (ji) {
1134 if (out_domain)
1135 *out_domain = (MonoDomain*)l->data;
1136 return ji;
1141 return NULL;
1145 * mono_handle_exception_internal:
1146 * @ctx: saved processor state
1147 * @obj: the exception object
1148 * @test_only: only test if the exception is caught, but dont call handlers
1149 * @out_filter_idx: out parameter. if test_only is true, set to the index of
1150 * the first filter clause which caught the exception.
1151 * @resume: whenever to resume unwinding based on the state in MonoJitTlsData.
1153 static gboolean
1154 mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only, gboolean resume, gint32 *out_filter_idx, MonoJitInfo **out_ji)
1156 MonoDomain *domain = mono_domain_get ();
1157 MonoJitInfo *ji, rji;
1158 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1159 static void (*restore_context) (void *);
1160 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1161 MonoLMF *lmf = mono_get_lmf ();
1162 MonoArray *initial_trace_ips = NULL;
1163 GList *trace_ips = NULL;
1164 MonoException *mono_ex;
1165 gboolean stack_overflow = FALSE;
1166 MonoContext initial_ctx;
1167 int frame_count = 0;
1168 gboolean has_dynamic_methods = FALSE;
1169 gint32 filter_idx, first_filter_idx;
1171 g_assert (ctx != NULL);
1172 if (!obj) {
1173 MonoException *ex = mono_get_exception_null_reference ();
1174 MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object"));
1175 obj = (MonoObject *)ex;
1179 * Allocate a new exception object instead of the preconstructed ones.
1181 if (obj == domain->stack_overflow_ex) {
1183 * It is not a good idea to try and put even more pressure on the little stack available.
1184 * obj = mono_get_exception_stack_overflow ();
1186 stack_overflow = TRUE;
1188 else if (obj == domain->null_reference_ex) {
1189 obj = mono_get_exception_null_reference ();
1192 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1193 mono_ex = (MonoException*)obj;
1194 initial_trace_ips = mono_ex->trace_ips;
1195 } else {
1196 mono_ex = NULL;
1199 if (mono_ex && jit_tls->class_cast_from && !strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) {
1200 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1201 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1202 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
1203 mono_ex->message = mono_string_new (domain, msg);
1204 g_free (from_name);
1205 g_free (to_name);
1206 g_free (msg);
1209 if (!call_filter)
1210 call_filter = mono_get_call_filter ();
1212 if (!restore_context)
1213 restore_context = mono_get_restore_context ();
1215 g_assert (jit_tls->end_of_stack);
1216 g_assert (jit_tls->abort_func);
1218 if (!test_only) {
1219 MonoContext ctx_cp = *ctx;
1220 if (mono_trace_is_enabled ()) {
1221 MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0);
1222 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message);
1223 MonoObject *message;
1224 const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
1225 char *msg = NULL;
1226 MonoObject *exc = NULL;
1227 if (get_message == NULL) {
1228 message = NULL;
1229 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
1230 message = NULL;
1231 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
1232 } else {
1233 message = mono_runtime_invoke (get_message, obj, NULL, &exc);
1236 if (msg == NULL) {
1237 msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
1239 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
1240 g_free (msg);
1241 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
1242 mono_print_thread_dump_from_ctx (ctx);
1244 mono_profiler_exception_thrown (obj);
1245 if (!mono_handle_exception_internal (&ctx_cp, obj, original_ip, TRUE, FALSE, &first_filter_idx, out_ji)) {
1246 if (mono_break_on_exc)
1247 G_BREAKPOINT ();
1248 mono_debugger_agent_handle_exception (obj, ctx, NULL);
1249 // FIXME: This runs managed code so it might cause another stack overflow when
1250 // we are handling a stack overflow
1251 mono_unhandled_exception (obj);
1252 } else {
1253 mono_debugger_agent_handle_exception (obj, ctx, &ctx_cp);
1257 if (out_filter_idx)
1258 *out_filter_idx = -1;
1259 if (out_ji)
1260 *out_ji = NULL;
1261 filter_idx = 0;
1262 initial_ctx = *ctx;
1263 memset (&rji, 0, sizeof (rji));
1265 while (1) {
1266 MonoContext new_ctx;
1267 guint32 free_stack;
1269 ji = mono_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx,
1270 NULL, &lmf, NULL, NULL);
1271 if (!ji) {
1272 g_warning ("Exception inside function without unwind info");
1273 g_assert_not_reached ();
1276 if (ji != (gpointer)-1 && !(ji->code_start <= MONO_CONTEXT_GET_IP (ctx) && (((guint8*)ji->code_start + ji->code_size >= (guint8*)MONO_CONTEXT_GET_IP (ctx))))) {
1278 * The exception was raised in native code and we got back to managed code
1279 * using the LMF.
1281 *ctx = new_ctx;
1282 continue;
1285 if (ji != (gpointer)-1) {
1286 frame_count ++;
1287 //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
1289 if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1291 * Avoid overwriting the stack trace if the exception is
1292 * rethrown. Also avoid giant stack traces during a stack
1293 * overflow.
1295 if (!initial_trace_ips && (frame_count < 1000)) {
1296 trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1297 trace_ips = g_list_prepend (trace_ips,
1298 get_generic_info_from_stack_frame (ji, ctx));
1302 if (ji->method->dynamic)
1303 has_dynamic_methods = TRUE;
1305 if (stack_overflow)
1306 #ifndef MONO_ARCH_STACK_GROWS_UP
1307 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1308 #else
1309 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1310 #endif
1311 else
1312 free_stack = 0xffffff;
1315 * During stack overflow, wait till the unwinding frees some stack
1316 * space before running handlers/finalizers.
1318 if ((free_stack > (64 * 1024)) && ji->num_clauses) {
1319 int i;
1321 for (i = 0; i < ji->num_clauses; i++) {
1322 MonoJitExceptionInfo *ei = &ji->clauses [i];
1323 gboolean filtered = FALSE;
1325 #if defined(__s390__)
1327 * This is required in cases where a try block starts immediately after
1328 * a call which causes an exception. Testcase: tests/exception8.cs.
1329 * FIXME: Clean this up.
1331 if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) && MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
1332 #else
1333 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1334 #endif
1335 /* catch block */
1336 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1338 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
1339 if (ji->from_llvm) {
1340 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1341 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, obj);
1342 #else
1343 g_assert_not_reached ();
1344 #endif
1345 } else {
1346 /* store the exception object in bp + ei->exvar_offset */
1347 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
1351 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1352 if (test_only) {
1353 mono_perfcounters->exceptions_filters++;
1354 mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
1355 filtered = call_filter (ctx, ei->data.filter);
1356 if (filtered && out_filter_idx)
1357 *out_filter_idx = filter_idx;
1358 if (out_ji)
1359 *out_ji = ji;
1361 else {
1363 * Filter clauses should only be run in the
1364 * first pass of exception handling.
1366 filtered = (filter_idx == first_filter_idx);
1368 filter_idx ++;
1371 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
1372 mono_object_isinst (obj, catch_class)) || filtered) {
1373 if (test_only) {
1374 if (mono_ex && !initial_trace_ips) {
1375 trace_ips = g_list_reverse (trace_ips);
1376 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1377 if (has_dynamic_methods)
1378 /* These methods could go away anytime, so compute the stack trace now */
1379 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1381 g_list_free (trace_ips);
1383 return TRUE;
1385 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1386 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1387 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1388 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1389 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1390 *(mono_get_lmf_addr ()) = lmf;
1391 mono_perfcounters->exceptions_depth += frame_count;
1392 if (obj == domain->stack_overflow_ex)
1393 jit_tls->handling_stack_ovf = FALSE;
1395 return 0;
1397 if (!test_only && is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1398 (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
1399 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1400 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1401 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1402 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1403 call_filter (ctx, ei->handler_start);
1405 if (!test_only && is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1406 (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
1407 if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1408 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1409 mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1410 mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1411 mono_perfcounters->exceptions_finallys++;
1412 *(mono_get_lmf_addr ()) = lmf;
1413 if (ji->from_llvm) {
1415 * LLVM compiled finally handlers follow the design
1416 * of the c++ ehabi, i.e. they call a resume function
1417 * at the end instead of returning to the caller.
1418 * So save the exception handling state,
1419 * mono_resume_unwind () will call us again to continue
1420 * the unwinding.
1422 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1423 *(mono_get_lmf_addr ()) = lmf;
1424 jit_tls->ex_ctx = new_ctx;
1425 jit_tls->ex_obj = obj;
1426 return 0;
1427 } else {
1428 call_filter (ctx, ei->handler_start);
1435 if (!test_only)
1436 mono_profiler_exception_method_leave (ji->method);
1439 *ctx = new_ctx;
1441 if (ji == (gpointer)-1) {
1443 if (!test_only) {
1444 *(mono_get_lmf_addr ()) = lmf;
1446 jit_tls->abort_func (obj);
1447 g_assert_not_reached ();
1448 } else {
1449 if (mono_ex && !initial_trace_ips) {
1450 trace_ips = g_list_reverse (trace_ips);
1451 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1452 if (has_dynamic_methods)
1453 /* These methods could go away anytime, so compute the stack trace now */
1454 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1456 g_list_free (trace_ips);
1457 return FALSE;
1462 g_assert_not_reached ();
1466 * mono_debugger_handle_exception:
1468 * Notify the debugger about exceptions. Returns TRUE if the debugger wants us to stop
1469 * at the exception and FALSE to resume with the normal exception handling.
1471 * The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
1472 * MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
1473 * `callq throw' instruction.
1475 gboolean
1476 mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
1478 MonoDebuggerExceptionAction action;
1480 if (!mono_debug_using_mono_debugger ())
1481 return FALSE;
1483 if (!obj) {
1484 MonoException *ex = mono_get_exception_null_reference ();
1485 MONO_OBJECT_SETREF (ex, message, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
1486 obj = (MonoObject *)ex;
1489 action = _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1491 if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP) {
1493 * The debugger wants us to stop on the `throw' instruction.
1494 * By the time we get here, it already inserted a breakpoint there.
1496 return TRUE;
1497 } else if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED) {
1498 MonoContext ctx_cp = *ctx;
1499 MonoJitInfo *ji = NULL;
1500 gboolean ret;
1503 * The debugger wants us to stop only if this exception is user-unhandled.
1506 ret = mono_handle_exception_internal (&ctx_cp, obj, MONO_CONTEXT_GET_IP (ctx), TRUE, FALSE, NULL, &ji);
1507 if (ret && (ji != NULL) && (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
1509 * The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
1510 * inside the method being invoked, so we handle it like a user-unhandled exception.
1512 ret = FALSE;
1515 if (!ret) {
1517 * The exception is user-unhandled - tell the debugger to stop.
1519 return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1523 * The exception is catched somewhere - resume with the normal exception handling and don't
1524 * stop in the debugger.
1528 return FALSE;
1532 * mono_debugger_run_finally:
1533 * @start_ctx: saved processor state
1535 * This method is called by the Mono Debugger to call all `finally' clauses of the
1536 * current stack frame. It's used when the user issues a `return' command to make
1537 * the current stack frame return. After returning from this method, the debugger
1538 * unwinds the stack one frame and gives control back to the user.
1540 * NOTE: This method is only used when running inside the Mono Debugger.
1542 void
1543 mono_debugger_run_finally (MonoContext *start_ctx)
1545 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1546 MonoDomain *domain = mono_domain_get ();
1547 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1548 MonoLMF *lmf = mono_get_lmf ();
1549 MonoContext ctx, new_ctx;
1550 MonoJitInfo *ji, rji;
1551 int i;
1553 ctx = *start_ctx;
1555 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1556 if (!ji || ji == (gpointer)-1)
1557 return;
1559 if (!call_filter)
1560 call_filter = mono_get_call_filter ();
1562 for (i = 0; i < ji->num_clauses; i++) {
1563 MonoJitExceptionInfo *ei = &ji->clauses [i];
1565 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
1566 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1567 call_filter (&ctx, ei->handler_start);
1573 * mono_handle_exception:
1574 * @ctx: saved processor state
1575 * @obj: the exception object
1576 * @test_only: only test if the exception is caught, but dont call handlers
1578 gboolean
1579 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
1581 if (!test_only)
1582 mono_perfcounters->exceptions_thrown++;
1584 return mono_handle_exception_internal (ctx, obj, original_ip, test_only, FALSE, NULL, NULL);
1587 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1589 #ifndef MONO_ARCH_USE_SIGACTION
1590 #error "Can't use sigaltstack without sigaction"
1591 #endif
1593 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1595 void
1596 mono_setup_altstack (MonoJitTlsData *tls)
1598 size_t stsize = 0;
1599 struct sigaltstack sa;
1600 guint8 *staddr = NULL;
1602 if (mono_running_on_valgrind ())
1603 return;
1605 mono_thread_get_stack_bounds (&staddr, &stsize);
1607 g_assert (staddr);
1609 tls->end_of_stack = staddr + stsize;
1611 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1613 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1614 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
1616 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1617 /* mprotect can fail for the main thread stack */
1618 gpointer gaddr = mono_valloc (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON|MONO_MMAP_FIXED);
1619 g_assert (gaddr == tls->stack_ovf_guard_base);
1620 tls->stack_ovf_valloced = TRUE;
1624 * threads created by nptl does not seem to have a guard page, and
1625 * since the main thread is not created by us, we can't even set one.
1626 * Increasing stsize fools the SIGSEGV signal handler into thinking this
1627 * is a stack overflow exception.
1629 tls->stack_size = stsize + mono_pagesize ();
1631 /* Setup an alternate signal stack */
1632 tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
1633 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1635 g_assert (tls->signal_stack);
1637 sa.ss_sp = tls->signal_stack;
1638 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1639 sa.ss_flags = SS_ONSTACK;
1640 sigaltstack (&sa, NULL);
1643 void
1644 mono_free_altstack (MonoJitTlsData *tls)
1646 struct sigaltstack sa;
1647 int err;
1649 sa.ss_sp = tls->signal_stack;
1650 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1651 sa.ss_flags = SS_DISABLE;
1652 err = sigaltstack (&sa, NULL);
1653 g_assert (err == 0);
1655 if (tls->signal_stack)
1656 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1657 if (tls->stack_ovf_valloced)
1658 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size);
1659 else
1660 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1663 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1665 void
1666 mono_setup_altstack (MonoJitTlsData *tls)
1670 void
1671 mono_free_altstack (MonoJitTlsData *tls)
1675 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1677 static gboolean
1678 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
1680 gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
1681 /* we need to leave some room for throwing the exception */
1682 while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
1683 unprotect_size -= mono_pagesize ();
1684 /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1685 * is sufficient stack
1687 //fprintf (stderr, "restoring stack protection: %p-%p (%d)\n", jit_tls->stack_ovf_guard_base, (char*)jit_tls->stack_ovf_guard_base + unprotect_size, unprotect_size);
1688 if (unprotect_size)
1689 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
1690 return unprotect_size == jit_tls->stack_ovf_guard_size;
1693 static void
1694 try_more_restore (void)
1696 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1697 if (try_restore_stack_protection (jit_tls, 500))
1698 jit_tls->restore_stack_prot = NULL;
1701 static void
1702 restore_stack_protection (void)
1704 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1705 MonoException *ex = mono_domain_get ()->stack_overflow_ex;
1706 /* if we can't restore the stack protection, keep a callback installed so
1707 * we'll try to restore as much stack as we can at each return from unmanaged
1708 * code.
1710 if (try_restore_stack_protection (jit_tls, 4096))
1711 jit_tls->restore_stack_prot = NULL;
1712 else
1713 jit_tls->restore_stack_prot = try_more_restore_tramp;
1714 /* here we also throw a stack overflow exception */
1715 ex->trace_ips = NULL;
1716 ex->stack_trace = NULL;
1717 mono_raise_exception (ex);
1720 gpointer
1721 mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
1723 void (*func)(void) = (gpointer)tramp_data;
1724 func ();
1725 return NULL;
1728 gboolean
1729 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
1731 /* we got a stack overflow in the soft-guard pages
1732 * There are two cases:
1733 * 1) managed code caused the overflow: we unprotect the soft-guard page
1734 * and let the arch-specific code trigger the exception handling mechanism
1735 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1736 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1737 * and hope we can continue with those enabled, at least until the hard-guard page
1738 * is hit. The alternative to continuing here is to just print a message and abort.
1739 * We may add in the future the code to protect the pages again in the codepath
1740 * when we return from unmanaged to managed code.
1742 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
1743 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
1744 /* we unprotect the minimum amount we can */
1745 guint32 guard_size;
1746 gboolean handled = FALSE;
1748 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
1749 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
1750 guard_size -= mono_pagesize ();
1752 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
1753 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
1754 mono_mprotect ((char*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size - guard_size, guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1755 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1756 if (ji) {
1757 mono_arch_handle_altstack_exception (ctx, fault_addr, TRUE);
1758 handled = TRUE;
1760 #endif
1761 if (!handled) {
1762 /* We print a message: after this even managed stack overflows
1763 * may crash the runtime
1765 fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), fault_addr);
1766 if (!jit_tls->handling_stack_ovf) {
1767 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
1768 jit_tls->handling_stack_ovf = 1;
1769 } else {
1770 /*fprintf (stderr, "Already handling stack overflow\n");*/
1773 return TRUE;
1775 return FALSE;
1778 static gboolean
1779 print_stack_frame (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed, gpointer data)
1781 FILE *stream = (FILE*)data;
1783 if (method) {
1784 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1785 fprintf (stream, " %s\n", location);
1786 g_free (location);
1787 } else
1788 fprintf (stream, " at <unknown> <0x%05x>\n", native_offset);
1790 return FALSE;
1793 static G_GNUC_UNUSED gboolean
1794 print_stack_frame_to_string (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed,
1795 gpointer data)
1797 GString *p = (GString*)data;
1799 if (method) {
1800 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1801 g_string_append_printf (p, " %s\n", location);
1802 g_free (location);
1803 } else
1804 g_string_append_printf (p, " at <unknown> <0x%05x>\n", native_offset);
1806 return FALSE;
1809 static gboolean handling_sigsegv = FALSE;
1812 * mono_handle_native_sigsegv:
1814 * Handle a SIGSEGV received while in native code by printing diagnostic
1815 * information and aborting.
1817 void
1818 mono_handle_native_sigsegv (int signal, void *ctx)
1820 #ifdef MONO_ARCH_USE_SIGACTION
1821 struct sigaction sa;
1822 #endif
1823 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1825 if (handling_sigsegv)
1826 return;
1828 if (mini_get_debug_options ()->suspend_on_sigsegv) {
1829 fprintf (stderr, "Received SIGSEGV, suspending...");
1830 while (1)
1834 /* To prevent infinite loops when the stack walk causes a crash */
1835 handling_sigsegv = TRUE;
1837 /* !jit_tls means the thread was not registered with the runtime */
1838 if (jit_tls && mono_thread_internal_current ()) {
1839 fprintf (stderr, "Stacktrace:\n\n");
1841 mono_jit_walk_stack (print_stack_frame, TRUE, stderr);
1843 fflush (stderr);
1846 #ifdef HAVE_BACKTRACE_SYMBOLS
1848 void *array [256];
1849 char **names;
1850 int i, size;
1851 const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
1853 fprintf (stderr, "\nNative stacktrace:\n\n");
1855 size = backtrace (array, 256);
1856 names = backtrace_symbols (array, size);
1857 for (i =0; i < size; ++i) {
1858 fprintf (stderr, "\t%s\n", names [i]);
1860 free (names);
1862 fflush (stderr);
1864 /* Try to get more meaningful information using gdb */
1866 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
1867 if (!mini_get_debug_options ()->no_gdb_backtrace && !mono_debug_using_mono_debugger ()) {
1868 /* From g_spawn_command_line_sync () in eglib */
1869 int res;
1870 int stdout_pipe [2] = { -1, -1 };
1871 pid_t pid;
1872 int status;
1873 char buffer [1024];
1875 res = pipe (stdout_pipe);
1876 g_assert (res != -1);
1878 //pid = fork ();
1880 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1881 * it will deadlock. Call the syscall directly instead.
1883 pid = mono_runtime_syscall_fork ();
1885 if (pid == 0) {
1886 close (stdout_pipe [0]);
1887 dup2 (stdout_pipe [1], STDOUT_FILENO);
1889 for (i = getdtablesize () - 1; i >= 3; i--)
1890 close (i);
1892 if (!mono_gdb_render_native_backtraces ())
1893 close (STDOUT_FILENO);
1895 exit (1);
1898 close (stdout_pipe [1]);
1900 fprintf (stderr, "\nDebug info from gdb:\n\n");
1902 while (1) {
1903 int nread = read (stdout_pipe [0], buffer, 1024);
1905 if (nread <= 0)
1906 break;
1907 write (STDERR_FILENO, buffer, nread);
1910 waitpid (pid, &status, WNOHANG);
1912 #endif
1914 * A SIGSEGV indicates something went very wrong so we can no longer depend
1915 * on anything working. So try to print out lots of diagnostics, starting
1916 * with ones which have a greater chance of working.
1918 fprintf (stderr,
1919 "\n"
1920 "=================================================================\n"
1921 "Got a %s while executing native code. This usually indicates\n"
1922 "a fatal error in the mono runtime or one of the native libraries \n"
1923 "used by your application.\n"
1924 "=================================================================\n"
1925 "\n", signal_str);
1928 #endif
1930 #ifdef MONO_ARCH_USE_SIGACTION
1932 /* Remove our SIGABRT handler */
1933 sa.sa_handler = SIG_DFL;
1934 sigemptyset (&sa.sa_mask);
1935 sa.sa_flags = 0;
1937 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
1939 #endif
1941 abort ();
1944 static void
1945 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
1947 MonoInternalThread *thread = mono_thread_internal_current ();
1948 #if defined(__i386__) || defined(__x86_64__)
1949 MonoContext ctx;
1950 #endif
1951 GString* text = g_string_new (0);
1952 char *name, *wapi_desc;
1953 GError *error = NULL;
1955 if (thread->name) {
1956 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
1957 g_assert (!error);
1958 g_string_append_printf (text, "\n\"%s\"", name);
1959 g_free (name);
1961 else if (thread->threadpool_thread)
1962 g_string_append (text, "\n\"<threadpool thread>\"");
1963 else
1964 g_string_append (text, "\n\"<unnamed thread>\"");
1966 #ifndef HOST_WIN32
1967 wapi_desc = wapi_current_thread_desc ();
1968 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
1969 free (wapi_desc);
1970 #endif
1972 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
1973 if (start_ctx) {
1974 memcpy (&ctx, start_ctx, sizeof (MonoContext));
1975 } else if (!sigctx)
1976 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
1977 else
1978 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
1980 mono_jit_walk_stack_from_ctx (print_stack_frame_to_string, &ctx, TRUE, text);
1981 #else
1982 printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
1983 #endif
1985 fprintf (stdout, "%s", text->str);
1986 g_string_free (text, TRUE);
1987 fflush (stdout);
1991 * mono_print_thread_dump:
1993 * Print information about the current thread to stdout.
1994 * SIGCTX can be NULL, allowing this to be called from gdb.
1996 void
1997 mono_print_thread_dump (void *sigctx)
1999 mono_print_thread_dump_internal (sigctx, NULL);
2002 void
2003 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2005 mono_print_thread_dump_internal (NULL, ctx);
2009 * mono_resume_unwind:
2011 * This is called by code at the end of LLVM compiled finally clauses to continue
2012 * unwinding.
2014 void
2015 mono_resume_unwind (void)
2017 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2018 static void (*restore_context) (MonoContext *);
2019 MonoContext ctx;
2021 memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));
2023 mono_handle_exception_internal (&ctx, jit_tls->ex_obj, NULL, FALSE, TRUE, NULL, NULL);
2025 if (!restore_context)
2026 restore_context = mono_get_restore_context ();
2028 restore_context (&ctx);