b575a2ccb67fd6064aacb8de27e6e00af134bafd
[mono.git] / mono / mini / mini-exceptions.c
1 /*
2  * mini-exceptions.c: generic exception support
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Mono Team (mono-list@lists.ximian.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc.
9  * Copyright 2003-2008 Novell, Inc.
10  * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
11  */
12
13 #include <config.h>
14 #include <glib.h>
15 #include <string.h>
16
17 #ifdef HAVE_SIGNAL_H
18 #include <signal.h>
19 #endif
20
21 #ifdef HAVE_EXECINFO_H
22 #include <execinfo.h>
23 #endif
24
25 #ifdef HAVE_SYS_TYPES_H
26 #include <sys/types.h>
27 #endif
28
29 #ifdef HAVE_SYS_WAIT_H
30 #include <sys/wait.h>
31 #endif
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 #ifdef HAVE_SYS_SYSCALL_H
38 #include <sys/syscall.h>
39 #endif
40
41 #ifdef HAVE_SYS_PRCTL_H
42 #include <sys/prctl.h>
43 #endif
44
45 #ifdef HAVE_UNWIND_H
46 #include <unwind.h>
47 #endif
48
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/tabledefs.h>
51 #include <mono/metadata/threads.h>
52 #include <mono/metadata/threads-types.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/metadata/exception.h>
55 #include <mono/metadata/object-internals.h>
56 #include <mono/metadata/gc-internals.h>
57 #include <mono/metadata/mono-debug.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/mono-endian.h>
60 #include <mono/metadata/environment.h>
61 #include <mono/metadata/mono-mlist.h>
62 #include <mono/utils/mono-mmap.h>
63 #include <mono/utils/mono-logger-internals.h>
64
65 #include "mini.h"
66 #include "trace.h"
67 #include "debugger-agent.h"
68 #include "seq-points.h"
69 #include "llvm-runtime.h"
70 #include "mini-llvm.h"
71
72 #ifdef ENABLE_LLVM
73 #include "mini-llvm-cpp.h"
74 #endif
75
76 #ifdef ENABLE_EXTENSION_MODULE
77 #include "../../../mono-extensions/mono/mini/mini-exceptions.c"
78 #endif
79
80 #ifndef MONO_ARCH_CONTEXT_DEF
81 #define MONO_ARCH_CONTEXT_DEF
82 #endif
83
84 static gpointer restore_context_func, call_filter_func;
85 static gpointer throw_exception_func, rethrow_exception_func;
86 static gpointer throw_corlib_exception_func;
87
88 static gpointer try_more_restore_tramp = NULL;
89 static gpointer restore_stack_protection_tramp = NULL;
90
91 static MonoUnhandledExceptionFunc unhandled_exception_hook = NULL;
92 static gpointer unhandled_exception_hook_data = NULL;
93
94 static void try_more_restore (void);
95 static void restore_stack_protection (void);
96 static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data);
97 static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx);
98 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
99
100 void
101 mono_exceptions_init (void)
102 {
103         MonoRuntimeExceptionHandlingCallbacks cbs;
104         if (mono_aot_only) {
105                 restore_context_func = mono_aot_get_trampoline ("restore_context");
106                 call_filter_func = mono_aot_get_trampoline ("call_filter");
107                 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
108                 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
109         } else {
110                 MonoTrampInfo *info;
111
112                 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
113                 mono_tramp_info_register (info, NULL);
114                 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
115                 mono_tramp_info_register (info, NULL);
116                 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
117                 mono_tramp_info_register (info, NULL);
118                 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
119                 mono_tramp_info_register (info, NULL);
120         }
121 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
122         if (!mono_llvm_only) {
123                 try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
124                 restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
125         }
126 #endif
127
128 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
129         mono_arch_exceptions_init ();
130 #endif
131         cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
132         cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
133
134         if (mono_llvm_only)
135                 cbs.mono_raise_exception = mono_llvm_raise_exception;
136         else
137                 cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception ();
138         cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
139         cbs.mono_exception_walk_trace = mono_exception_walk_trace;
140         cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
141         mono_install_eh_callbacks (&cbs);
142 }
143
144 gpointer
145 mono_get_throw_exception (void)
146 {
147         g_assert (throw_exception_func);
148         return throw_exception_func;
149 }
150
151 gpointer
152 mono_get_rethrow_exception (void)
153 {
154         g_assert (rethrow_exception_func);
155         return rethrow_exception_func;
156 }
157
158 gpointer
159 mono_get_call_filter (void)
160 {
161         g_assert (call_filter_func);
162         return call_filter_func;
163 }
164
165 gpointer
166 mono_get_restore_context (void)
167 {
168         g_assert (restore_context_func);
169         return restore_context_func;
170 }
171
172 gpointer
173 mono_get_throw_corlib_exception (void)
174 {
175         gpointer code = NULL;
176         MonoTrampInfo *info;
177
178         /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
179         if (throw_corlib_exception_func)
180                 return throw_corlib_exception_func;
181
182         if (mono_aot_only)
183                 code = mono_aot_get_trampoline ("throw_corlib_exception");
184         else {
185                 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
186                 mono_tramp_info_register (info, NULL);
187         }
188
189         mono_memory_barrier ();
190
191         throw_corlib_exception_func = code;
192
193         return throw_corlib_exception_func;
194 }
195
196 static gboolean
197 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
198 {
199         MonoTryBlockHoleTableJitInfo *table;
200         int i;
201         guint32 offset;
202         guint16 clause;
203
204         if (ei->try_start > ip || ip >= ei->try_end)
205                 return FALSE;
206
207         if (!ji->has_try_block_holes)
208                 return TRUE;
209
210         table = mono_jit_info_get_try_block_hole_table_info (ji);
211         offset = (guint32)((char*)ip - (char*)ji->code_start);
212         clause = (guint16)(ei - ji->clauses);
213         g_assert (clause < ji->num_clauses);
214
215         for (i = 0; i < table->num_holes; ++i) {
216                 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
217                 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
218                         return FALSE;
219         }
220         return TRUE;
221 }
222
223 /*
224  * find_jit_info:
225  *
226  * Translate between the mono_arch_unwind_frame function and the old API.
227  */
228 static MonoJitInfo *
229 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
230                            MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
231 {
232         StackFrameInfo frame;
233         MonoJitInfo *ji;
234         gboolean err;
235         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
236
237         /* Avoid costly table lookup during stack overflow */
238         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
239                 ji = prev_ji;
240         else
241                 ji = mini_jit_info_table_find (domain, (char *)ip, NULL);
242
243         if (managed)
244                 *managed = FALSE;
245
246         err = mono_arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
247         if (!err)
248                 return (MonoJitInfo *)-1;
249
250         if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
251                 /*
252                  * Remove any unused lmf.
253                  * Mask out the lower bits which might be used to hold additional information.
254                  */
255                 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(SIZEOF_VOID_P -1));
256         }
257
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 frame.ji;
264         case FRAME_TYPE_TRAMPOLINE:
265                 return frame.ji;
266         case FRAME_TYPE_MANAGED_TO_NATIVE:
267                 if (frame.ji)
268                         return frame.ji;
269                 else {
270                         memset (res, 0, sizeof (MonoJitInfo));
271                         res->d.method = frame.method;
272                         return res;
273                 }
274         case FRAME_TYPE_DEBUGGER_INVOKE: {
275                 MonoContext tmp_ctx;
276
277                 /*
278                  * The normal exception handling code can't handle this frame, so just
279                  * skip it.
280                  */
281                 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
282                 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
283                 return ji;
284         }
285         default:
286                 g_assert_not_reached ();
287                 return NULL;
288         }
289 }
290
291 /* mono_find_jit_info:
292  *
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.
299  */
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)
304 {
305         gboolean managed2;
306         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
307         MonoJitInfo *ji;
308         MonoMethod *method = NULL;
309
310         if (trace)
311                 *trace = NULL;
312
313         if (native_offset)
314                 *native_offset = -1;
315
316         if (managed)
317                 *managed = FALSE;
318
319         ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
320
321         if (ji == (gpointer)-1)
322                 return ji;
323
324         if (ji && !ji->is_trampoline)
325                 method = jinfo_get_method (ji);
326
327         if (managed2 || (method && method->wrapper_type)) {
328                 const char *real_ip, *start;
329                 gint32 offset;
330
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;
337
338                 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
339                         offset = real_ip - start;
340                 else
341                         offset = -1;
342
343                 if (native_offset)
344                         *native_offset = offset;
345
346                 if (managed)
347                         if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
348                                 *managed = TRUE;
349
350                 if (trace)
351                         *trace = mono_debug_print_stack_frame (method, offset, domain);
352         } else {
353                 if (trace) {
354                         char *fname = mono_method_full_name (jinfo_get_method (res), TRUE);
355                         *trace = g_strdup_printf ("in (unmanaged) %s", fname);
356                         g_free (fname);
357                 }
358         }
359
360         return ji;
361 }
362
363 /*
364  * mono_find_jit_info_ext:
365  *
366  *   A version of mono_find_jit_info which returns all data in the StackFrameInfo
367  * structure.
368  * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
369  * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
370  * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
371  * to obtain the last managed frame.
372  * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
373  * On return, it will be filled with the locations where callee saved registers are saved
374  * by the current frame. This is returned outside of StackFrameInfo because it can be
375  * quite large on some platforms.
376  * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
377  * not be set.
378  */
379 gboolean
380 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, 
381                                                 MonoJitInfo *prev_ji, MonoContext *ctx,
382                                                 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
383                                                 mgreg_t **save_locations,
384                                                 StackFrameInfo *frame)
385 {
386         gboolean err;
387         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
388         MonoJitInfo *ji;
389         MonoDomain *target_domain = domain;
390         MonoMethod *method = NULL;
391         gboolean async = mono_thread_info_is_async_context ();
392
393         if (trace)
394                 *trace = NULL;
395
396         /* Avoid costly table lookup during stack overflow */
397         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
398                 ji = prev_ji;
399         else
400                 ji = mini_jit_info_table_find (domain, (char *)ip, &target_domain);
401
402         if (!target_domain)
403                 target_domain = domain;
404
405         if (save_locations)
406                 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (mgreg_t*));
407
408         err = mono_arch_unwind_frame (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
409         if (!err)
410                 return FALSE;
411
412         if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
413                 /*
414                  * Remove any unused lmf.
415                  * Mask out the lower bits which might be used to hold additional information.
416                  */
417                 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(SIZEOF_VOID_P -1));
418         }
419
420         if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async)
421                 method = jinfo_get_method (frame->ji);
422
423         if (frame->type == FRAME_TYPE_MANAGED && method) {
424                 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
425                         frame->managed = TRUE;
426         }
427
428         if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
429                 /*
430                  * This type of frame is just a marker, the caller should unwind once more to get the
431                  * last managed frame.
432                  */
433                 frame->ji = NULL;
434                 frame->method = NULL;
435         }
436
437         frame->native_offset = -1;
438         frame->domain = target_domain;
439         frame->async_context = async;
440
441         ji = frame->ji;
442
443         if (frame->type == FRAME_TYPE_MANAGED)
444                 frame->method = method;
445
446         if (ji && (frame->managed || (method && method->wrapper_type))) {
447                 const char *real_ip, *start;
448
449                 start = (const char *)ji->code_start;
450                 if (!frame->managed)
451                         /* ctx->ip points into native code */
452                         real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
453                 else
454                         real_ip = (const char*)ip;
455
456                 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
457                         frame->native_offset = real_ip - start;
458                 else
459                         frame->native_offset = -1;
460
461                 if (trace)
462                         *trace = mono_debug_print_stack_frame (method, frame->native_offset, domain);
463         } else {
464                 if (trace && frame->method) {
465                         char *fname = mono_method_full_name (frame->method, TRUE);
466                         *trace = g_strdup_printf ("in (unmanaged) %s", fname);
467                         g_free (fname);
468                 }
469         }
470
471         return TRUE;
472 }
473
474 /*
475  * This function is async-safe.
476  */
477 static gpointer
478 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
479 {
480         MonoGenericJitInfo *gi;
481         MonoMethod *method;
482         gpointer info;
483
484         if (!ji->has_generic_jit_info)
485                 return NULL;
486         gi = mono_jit_info_get_generic_jit_info (ji);
487         if (!gi->has_this)
488                 return NULL;
489
490         info = NULL;
491         /*
492          * Search location list if available, it contains the precise location of the
493          * argument for every pc offset, even if the method was interrupted while it was in
494          * its prolog.
495          */
496         if (gi->nlocs) {
497                 int offset = (mgreg_t)MONO_CONTEXT_GET_IP (ctx) - (mgreg_t)ji->code_start;
498                 int i;
499
500                 for (i = 0; i < gi->nlocs; ++i) {
501                         MonoDwarfLocListEntry *entry = &gi->locations [i];
502
503                         if (offset >= entry->from && (offset < entry->to || entry->to == 0)) {
504                                 if (entry->is_reg)
505                                         info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg);
506                                 else
507                                         info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset);
508                                 break;
509                         }
510                 }
511                 g_assert (i < gi->nlocs);
512         } else {
513                 if (gi->this_in_reg)
514                         info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg);
515                 else
516                         info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
517                                                                                   gi->this_offset);
518         }
519
520         method = jinfo_get_method (ji);
521         if (mono_method_get_context (method)->method_inst) {
522                 /* A MonoMethodRuntimeGenericContext* */
523                 return info;
524         } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype) {
525                 /* A MonoVTable* */
526                 return info;
527         } else {
528                 /* Avoid returning a managed object */
529                 MonoObject *this_obj = (MonoObject *)info;
530
531                 return this_obj->vtable;
532         }
533 }
534
535 /*
536  * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
537  */
538 static MonoGenericContext
539 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
540 {
541         MonoGenericContext context = { NULL, NULL };
542         MonoClass *klass, *method_container_class;
543         MonoMethod *method;
544
545         g_assert (generic_info);
546
547         method = jinfo_get_method (ji);
548         g_assert (method->is_inflated);
549         if (mono_method_get_context (method)->method_inst) {
550                 MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext *)generic_info;
551
552                 klass = mrgctx->class_vtable->klass;
553                 context.method_inst = mrgctx->method_inst;
554                 g_assert (context.method_inst);
555         } else {
556                 MonoVTable *vtable = (MonoVTable *)generic_info;
557
558                 klass = vtable->klass;
559         }
560
561         //g_assert (!method->klass->generic_container);
562         if (method->klass->generic_class)
563                 method_container_class = method->klass->generic_class->container_class;
564         else
565                 method_container_class = method->klass;
566
567         /* class might refer to a subclass of method's class */
568         while (!(klass == method->klass || (klass->generic_class && klass->generic_class->container_class == method_container_class))) {
569                 klass = klass->parent;
570                 g_assert (klass);
571         }
572
573         if (klass->generic_class || klass->generic_container)
574                 context.class_inst = mini_class_get_context (klass)->class_inst;
575
576         if (klass->generic_class)
577                 g_assert (mono_class_has_parent_and_ignore_generics (klass->generic_class->container_class, method_container_class));
578         else
579                 g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class));
580
581         return context;
582 }
583
584 static MonoMethod*
585 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
586 {
587         MonoError error;
588         MonoGenericContext context;
589         MonoMethod *method;
590         
591         if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
592                 return jinfo_get_method (ji);
593         context = get_generic_context_from_stack_frame (ji, generic_info);
594
595         method = jinfo_get_method (ji);
596         method = mono_method_get_declaring_generic_method (method);
597         method = mono_class_inflate_generic_method_checked (method, &context, &error);
598         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
599
600         return method;
601 }
602
603 /**
604  * mono_exception_walk_native_trace:
605  * @ex: The exception object whose frames should be walked
606  * @func: callback to call for each stack frame
607  * @user_data: data passed to the callback
608  *
609  * This function walks the stacktrace of an exception. For
610  * each frame the callback function is called with the relevant info.
611  * The walk ends when no more stack frames are found or when the callback
612  * returns a TRUE value.
613  */
614  
615 gboolean
616 mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
617 {
618         MonoDomain *domain = mono_domain_get ();
619         MonoArray *ta = ex->trace_ips;
620         int len, i;
621
622         if (ta == NULL)
623                 return FALSE;
624
625         len = mono_array_length (ta) >> 1;
626         for (i = 0; i < len; i++) {
627                 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
628                 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
629                 MonoJitInfo *ji = mono_jit_info_table_find (domain, (char *)ip);
630
631                 if (ji == NULL) {
632                         if (func (NULL, ip, 0, FALSE, user_data))
633                                 return TRUE;
634                 } else {
635                         MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
636                         if (func (method, ji->code_start, (char *) ip - (char *) ji->code_start, TRUE, user_data))
637                                 return TRUE;
638                 }
639         }
640         
641         return len > 0;
642 }
643
644 MonoArray *
645 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
646 {
647         MonoDomain *domain = mono_domain_get ();
648         MonoArray *res;
649         MonoArray *ta = exc->trace_ips;
650         MonoDebugSourceLocation *location;
651         int i, len;
652
653         if (ta == NULL) {
654                 /* Exception is not thrown yet */
655                 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
656         }
657
658         len = mono_array_length (ta) >> 1;
659
660         res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
661
662         for (i = skip; i < len; i++) {
663                 MonoJitInfo *ji;
664                 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
665                 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
666                 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
667                 MonoMethod *method;
668
669                 ji = mono_jit_info_table_find (domain, (char *)ip);
670                 if (ji == NULL) {
671                         /* Unmanaged frame */
672                         mono_array_setref (res, i, sf);
673                         continue;
674                 }
675
676                 g_assert (ji != NULL);
677
678                 method = get_method_from_stack_frame (ji, generic_info);
679                 if (jinfo_get_method (ji)->wrapper_type) {
680                         char *s;
681
682                         sf->method = NULL;
683                         s = mono_method_get_name_full (method, TRUE, MONO_TYPE_NAME_FORMAT_REFLECTION);
684                         MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
685                         g_free (s);
686                 }
687                 else
688                         MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
689
690                 sf->method_index = ji->from_aot ? mono_aot_find_method_index (method) : 0xffffff;
691                 sf->method_address = (gsize) ji->code_start;
692                 sf->native_offset = (char *)ip - (char *)ji->code_start;
693
694                 /*
695                  * mono_debug_lookup_source_location() returns both the file / line number information
696                  * and the IL offset.  Note that computing the IL offset is already an expensive
697                  * operation, so we shouldn't call this method twice.
698                  */
699                 location = mono_debug_lookup_source_location (jinfo_get_method (ji), sf->native_offset, domain);
700                 if (location) {
701                         sf->il_offset = location->il_offset;
702                 } else {
703                         SeqPoint sp;
704                         if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (ji), sf->native_offset, NULL, &sp))
705                                 sf->il_offset = sp.il_offset;
706                         else
707                                 sf->il_offset = -1;
708                 }
709
710                 if (need_file_info) {
711                         if (location && location->source_file) {
712                                 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
713                                 sf->line = location->row;
714                                 sf->column = location->column;
715                         } else {
716                                 sf->line = sf->column = 0;
717                                 sf->filename = NULL;
718                         }
719                 }
720
721                 mono_debug_free_source_location (location);
722                 mono_array_setref (res, i, sf);
723         }
724
725         return res;
726 }
727
728 static void
729 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
730 {
731         if (!start_ctx) {
732                 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
733                 if (jit_tls && jit_tls->orig_ex_ctx_set)
734                         start_ctx = &jit_tls->orig_ex_ctx;
735         }
736         mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
737 }
738 /**
739  * mono_walk_stack_with_ctx:
740  *
741  * Unwind the current thread starting at @start_ctx.
742  * 
743  * If @start_ctx is null, we capture the current context.
744  */
745 void
746 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
747 {
748         MonoContext extra_ctx;
749         MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
750         MONO_ARCH_CONTEXT_DEF
751
752         if (!thread || !thread->jit_data)
753                 return;
754
755         if (!start_ctx) {
756                 mono_arch_flush_register_windows ();
757
758 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
759                 MONO_INIT_CONTEXT_FROM_CURRENT (&extra_ctx);
760 #else
761                 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
762 #endif
763                 start_ctx = &extra_ctx;
764         }
765
766         mono_walk_stack_full (func, start_ctx, mono_domain_get (), (MonoJitTlsData *)thread->jit_data, mono_get_lmf (), unwind_options, user_data);
767 }
768
769 /**
770  * mono_walk_stack_with_state:
771  *
772  * Unwind a thread described by @state.
773  *
774  * State must be valid (state->valid == TRUE).
775  *
776  * If you are using this function to unwind another thread, make sure it is suspended.
777  * 
778  * If @state is null, we capture the current context.
779  */
780 void
781 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
782 {
783         MonoThreadUnwindState extra_state;
784         if (!state) {
785                 g_assert (!mono_thread_info_is_async_context ());
786                 if (!mono_thread_state_init_from_current (&extra_state))
787                         return;
788                 state = &extra_state;
789         }
790
791         g_assert (state->valid);
792
793         if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
794                 /* Not attached */
795                 return;
796
797         mono_walk_stack_full (func,
798                 &state->ctx, 
799                 (MonoDomain *)state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
800                 (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
801                 (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF],
802                 unwind_options, user_data);
803 }
804
805 void
806 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
807 {
808         MonoThreadUnwindState state;
809         if (!mono_thread_state_init_from_current (&state))
810                 return;
811         mono_walk_stack_with_state (func, &state, options, user_data);
812 }
813
814 /**
815  * mono_walk_stack_full:
816  * @func: callback to call for each stack frame
817  * @domain: starting appdomain, can be NULL to use the current domain
818  * @unwind_options: what extra information the unwinder should gather
819  * @start_ctx: starting state of the stack walk, can be NULL.
820  * @thread: the thread whose stack to walk, can be NULL to use the current thread
821  * @lmf: the LMF of @thread, can be NULL to use the LMF of the current thread
822  * @user_data: data passed to the callback
823  *
824  * This function walks the stack of a thread, starting from the state
825  * represented by start_ctx. For each frame the callback
826  * function is called with the relevant info. The walk ends when no more
827  * managed stack frames are found or when the callback returns a TRUE value.
828  */
829 static void
830 mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data)
831 {
832         gint il_offset, i;
833         MonoContext ctx, new_ctx;
834         StackFrameInfo frame;
835         gboolean res;
836         mgreg_t *reg_locations [MONO_MAX_IREGS];
837         mgreg_t *new_reg_locations [MONO_MAX_IREGS];
838         gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
839         gboolean async = mono_thread_info_is_async_context ();
840
841         g_assert (start_ctx);
842         g_assert (domain);
843         g_assert (jit_tls);
844         /*The LMF will be null if the target have no managed frames.*/
845         /* g_assert (lmf); */
846
847         if (async)
848                 g_assert (unwind_options == MONO_UNWIND_NONE);
849
850         memcpy (&ctx, start_ctx, sizeof (MonoContext));
851         memset (reg_locations, 0, sizeof (reg_locations));
852
853         while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
854                 frame.lmf = lmf;
855                 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
856                 if (!res)
857                         return;
858
859                 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji && !frame.ji->is_trampoline) {
860                         MonoDebugSourceLocation *source;
861
862                         source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
863                         if (source) {
864                                 il_offset = source->il_offset;
865                         } else {
866                                 SeqPoint sp;
867                                 if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (frame.ji), frame.native_offset, NULL, &sp))
868                                         il_offset = sp.il_offset;
869                                 else
870                                         il_offset = -1;
871                         }
872                         mono_debug_free_source_location (source);
873                 } else
874                         il_offset = -1;
875
876                 frame.il_offset = il_offset;
877
878                 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji && !frame.ji->is_trampoline) {
879                         frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
880                 } else {
881                         frame.actual_method = frame.method;
882                 }
883
884                 if (get_reg_locations)
885                         frame.reg_locations = reg_locations;
886
887                 if (func (&frame, &ctx, user_data))
888                         return;
889
890                 if (get_reg_locations) {
891                         for (i = 0; i < MONO_MAX_IREGS; ++i)
892                                 if (new_reg_locations [i])
893                                         reg_locations [i] = new_reg_locations [i];
894                 }
895                 
896                 ctx = new_ctx;
897         }
898 }
899
900 MonoBoolean
901 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
902                           MonoReflectionMethod **method, 
903                           gint32 *iloffset, gint32 *native_offset,
904                           MonoString **file, gint32 *line, gint32 *column)
905 {
906         MonoDomain *domain = mono_domain_get ();
907         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
908         MonoLMF *lmf = mono_get_lmf ();
909         MonoJitInfo *ji = NULL;
910         MonoContext ctx, new_ctx;
911         MonoDebugSourceLocation *location;
912         MonoMethod *jmethod = NULL, *actual_method;
913         StackFrameInfo frame;
914         gboolean res;
915
916         MONO_ARCH_CONTEXT_DEF;
917
918         mono_arch_flush_register_windows ();
919
920 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
921         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
922 #else
923         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
924 #endif
925
926         new_ctx = ctx;
927         do {
928                 ctx = new_ctx;
929                 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
930                 if (!res)
931                         return FALSE;
932
933                 if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
934                                 frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
935                                 frame.type == FRAME_TYPE_TRAMPOLINE)
936                         continue;
937
938                 ji = frame.ji;
939                 *native_offset = frame.native_offset;
940
941                 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
942                 jmethod = jinfo_get_method (ji);
943                 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
944                         continue;
945                 skip--;
946         } while (skip >= 0);
947
948         actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
949
950         mono_gc_wbarrier_generic_store (method, (MonoObject*) mono_method_get_object (domain, actual_method, NULL));
951
952         location = mono_debug_lookup_source_location (jmethod, *native_offset, domain);
953         if (location)
954                 *iloffset = location->il_offset;
955         else
956                 *iloffset = 0;
957
958         if (need_file_info) {
959                 if (location) {
960                         mono_gc_wbarrier_generic_store (file, (MonoObject*) mono_string_new (domain, location->source_file));
961                         *line = location->row;
962                         *column = location->column;
963                 } else {
964                         *file = NULL;
965                         *line = *column = 0;
966                 }
967         }
968
969         mono_debug_free_source_location (location);
970
971         return TRUE;
972 }
973
974 static MonoClass*
975 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
976 {
977         MonoClass *catch_class = ei->data.catch_class;
978         MonoType *inflated_type;
979         MonoGenericContext context;
980
981         /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
982         if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
983                 return NULL;
984
985         if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
986                 return catch_class;
987         context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
988
989         /* FIXME: we shouldn't inflate but instead put the
990            type in the rgctx and fetch it from there.  It
991            might be a good idea to do this lazily, i.e. only
992            when the exception is actually thrown, so as not to
993            waste space for exception clauses which might never
994            be encountered. */
995         inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
996         catch_class = mono_class_from_mono_type (inflated_type);
997         mono_metadata_free_type (inflated_type);
998
999         return catch_class;
1000 }
1001
1002 /*
1003  * mini_jit_info_table_find_ext:
1004  *
1005  *   Same as mono_jit_info_table_find, but search all the domains of the current thread
1006  * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1007  * OUT_DOMAIN if it is not NULL.
1008  */
1009 MonoJitInfo*
1010 mini_jit_info_table_find_ext (MonoDomain *domain, char *addr, gboolean allow_trampolines, MonoDomain **out_domain)
1011 {
1012         MonoJitInfo *ji;
1013         MonoInternalThread *t = mono_thread_internal_current ();
1014         gpointer *refs;
1015
1016         if (out_domain)
1017                 *out_domain = NULL;
1018
1019         ji = mono_jit_info_table_find_internal (domain, addr, TRUE, allow_trampolines);
1020         if (ji) {
1021                 if (out_domain)
1022                         *out_domain = domain;
1023                 return ji;
1024         }
1025
1026         /* maybe it is shared code, so we also search in the root domain */
1027         if (domain != mono_get_root_domain ()) {
1028                 ji = mono_jit_info_table_find_internal (mono_get_root_domain (), addr, TRUE, allow_trampolines);
1029                 if (ji) {
1030                         if (out_domain)
1031                                 *out_domain = mono_get_root_domain ();
1032                         return ji;
1033                 }
1034         }
1035
1036         if (!t)
1037                 return NULL;
1038
1039         refs = (gpointer *)((t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL);
1040         for (; refs && *refs; refs++) {
1041                 if (*refs != domain && *refs != mono_get_root_domain ()) {
1042                         ji = mono_jit_info_table_find_internal ((MonoDomain*) *refs, addr, TRUE, allow_trampolines);
1043                         if (ji) {
1044                                 if (out_domain)
1045                                         *out_domain = (MonoDomain*) *refs;
1046                                 return ji;
1047                         }
1048                 }
1049         }
1050
1051         return NULL;
1052 }
1053
1054 MonoJitInfo*
1055 mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
1056 {
1057         return mini_jit_info_table_find_ext (domain, addr, TRUE, out_domain);
1058 }
1059
1060 /*
1061  * wrap_non_exception_throws:
1062  *
1063  *   Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
1064  * WrapNonExceptionThrows flag set.
1065  */
1066 static gboolean
1067 wrap_non_exception_throws (MonoMethod *m)
1068 {
1069         MonoAssembly *ass = m->klass->image->assembly;
1070         MonoCustomAttrInfo* attrs;
1071         static MonoClass *klass;
1072         int i;
1073         gboolean val = FALSE;
1074
1075         g_assert (ass);
1076         if (ass->wrap_non_exception_throws_inited)
1077                 return ass->wrap_non_exception_throws;
1078
1079         klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1080
1081         attrs = mono_custom_attrs_from_assembly (ass);
1082         if (attrs) {
1083                 for (i = 0; i < attrs->num_attrs; ++i) {
1084                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
1085                         const gchar *p;
1086                         int num_named, named_type, name_len;
1087                         char *name;
1088
1089                         if (!attr->ctor || attr->ctor->klass != klass)
1090                                 continue;
1091                         /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
1092                         p = (const char*)attr->data;
1093                         g_assert (read16 (p) == 0x0001);
1094                         p += 2;
1095                         num_named = read16 (p);
1096                         if (num_named != 1)
1097                                 continue;
1098                         p += 2;
1099                         named_type = *p;
1100                         p ++;
1101                         /* data_type = *p; */
1102                         p ++;
1103                         /* Property */
1104                         if (named_type != 0x54)
1105                                 continue;
1106                         name_len = mono_metadata_decode_blob_size (p, &p);
1107                         name = (char *)g_malloc (name_len + 1);
1108                         memcpy (name, p, name_len);
1109                         name [name_len] = 0;
1110                         p += name_len;
1111                         g_assert (!strcmp (name, "WrapNonExceptionThrows"));
1112                         g_free (name);
1113                         /* The value is a BOOLEAN */
1114                         val = *p;
1115                 }
1116                 mono_custom_attrs_free (attrs);
1117         }
1118
1119         ass->wrap_non_exception_throws = val;
1120         mono_memory_barrier ();
1121         ass->wrap_non_exception_throws_inited = TRUE;
1122
1123         return val;
1124 }
1125
1126 #ifndef MONO_ARCH_STACK_GROWS_UP
1127 #define DOES_STACK_GROWS_UP 1
1128 #else
1129 #define DOES_STACK_GROWS_UP 0
1130 #endif
1131
1132 #define MAX_UNMANAGED_BACKTRACE 128
1133 static MonoArray*
1134 build_native_trace (void)
1135 {
1136 /* This puppy only makes sense on mobile, IOW, ARM. */
1137 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
1138         MonoArray *res;
1139         void *native_trace [MAX_UNMANAGED_BACKTRACE];
1140         int size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE);
1141         int i;
1142
1143         if (!size)
1144                 return NULL;
1145         res = mono_array_new (mono_domain_get (), mono_defaults.int_class, size);
1146
1147         for (i = 0; i < size; i++)
1148                 mono_array_set (res, gpointer, i, native_trace [i]);
1149         return res;
1150 #else
1151         return NULL;
1152 #endif
1153 }
1154
1155 static void
1156 setup_stack_trace (MonoException *mono_ex, GSList *dynamic_methods, MonoArray *initial_trace_ips, GList **trace_ips)
1157 {
1158         if (mono_ex && !initial_trace_ips) {
1159                 *trace_ips = g_list_reverse (*trace_ips);
1160                 MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (*trace_ips, mono_defaults.int_class));
1161                 MONO_OBJECT_SETREF (mono_ex, native_trace_ips, build_native_trace ());
1162                 if (dynamic_methods) {
1163                         /* These methods could go away anytime, so save a reference to them in the exception object */
1164                         GSList *l;
1165                         MonoMList *list = NULL;
1166
1167                         for (l = dynamic_methods; l; l = l->next) {
1168                                 guint32 dis_link;
1169                                 MonoDomain *domain = mono_domain_get ();
1170
1171                                 if (domain->method_to_dyn_method) {
1172                                         mono_domain_lock (domain);
1173                                         dis_link = (guint32)(size_t)g_hash_table_lookup (domain->method_to_dyn_method, l->data);
1174                                         mono_domain_unlock (domain);
1175                                         if (dis_link) {
1176                                                 MonoObject *o = mono_gchandle_get_target (dis_link);
1177                                                 if (o) {
1178                                                         list = mono_mlist_prepend (list, o);
1179                                                 }
1180                                         }
1181                                 }
1182                         }
1183
1184                         MONO_OBJECT_SETREF (mono_ex, dynamic_methods, list);
1185                 }
1186         }
1187         g_list_free (*trace_ips);
1188         *trace_ips = NULL;
1189 }
1190
1191 /*
1192  * mono_handle_exception_internal_first_pass:
1193  *
1194  *   The first pass of exception handling. Unwind the stack until a catch clause which can catch
1195  * OBJ is found. Run the index of the filter clause which caught the exception into
1196  * OUT_FILTER_IDX. Return TRUE if the exception is caught, FALSE otherwise.
1197  */
1198 static gboolean
1199 mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception)
1200 {
1201         MonoDomain *domain = mono_domain_get ();
1202         MonoJitInfo *ji = NULL;
1203         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1204         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1205         MonoLMF *lmf = mono_get_lmf ();
1206         MonoArray *initial_trace_ips = NULL;
1207         GList *trace_ips = NULL;
1208         GSList *dynamic_methods = NULL;
1209         MonoException *mono_ex;
1210         gboolean stack_overflow = FALSE;
1211         MonoContext initial_ctx;
1212         MonoMethod *method;
1213         int frame_count = 0;
1214         gint32 filter_idx;
1215         int i;
1216         MonoObject *ex_obj;
1217
1218         g_assert (ctx != NULL);
1219
1220         if (obj == (MonoObject *)domain->stack_overflow_ex)
1221                 stack_overflow = TRUE;
1222
1223         mono_ex = (MonoException*)obj;
1224         initial_trace_ips = mono_ex->trace_ips;
1225
1226         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1227                 mono_ex = (MonoException*)obj;
1228                 initial_trace_ips = mono_ex->trace_ips;
1229         } else {
1230                 mono_ex = NULL;
1231         }
1232
1233         if (!call_filter)
1234                 call_filter = (int (*) (MonoContext *, void *))mono_get_call_filter ();
1235
1236         g_assert (jit_tls->end_of_stack);
1237         g_assert (jit_tls->abort_func);
1238
1239         if (out_filter_idx)
1240                 *out_filter_idx = -1;
1241         if (out_ji)
1242                 *out_ji = NULL;
1243         if (out_prev_ji)
1244                 *out_prev_ji = NULL;
1245         filter_idx = 0;
1246         initial_ctx = *ctx;
1247
1248         while (1) {
1249                 MonoContext new_ctx;
1250                 guint32 free_stack;
1251                 int clause_index_start = 0;
1252                 gboolean unwind_res = TRUE;
1253                 
1254                 StackFrameInfo frame;
1255
1256                 if (out_prev_ji)
1257                         *out_prev_ji = ji;
1258
1259                 unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1260                 if (unwind_res) {
1261                         if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
1262                                         frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
1263                                         frame.type == FRAME_TYPE_TRAMPOLINE) {
1264                                 *ctx = new_ctx;
1265                                 continue;
1266                         }
1267                         g_assert (frame.type == FRAME_TYPE_MANAGED);
1268                         ji = frame.ji;
1269                 }
1270
1271                 if (!unwind_res) {
1272                         setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
1273                         g_slist_free (dynamic_methods);
1274                         return FALSE;
1275                 }
1276
1277                 frame_count ++;
1278                 method = jinfo_get_method (ji);
1279                 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
1280
1281                 if (mini_get_debug_options ()->reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
1282                         g_error ("A native frame was found while unwinding the stack after an exception.\n"
1283                                          "The native frame called the managed method:\n%s\n",
1284                                          mono_method_full_name (method, TRUE));
1285                 }
1286
1287                 if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1288                         /* 
1289                          * Avoid overwriting the stack trace if the exception is
1290                          * rethrown. Also avoid giant stack traces during a stack
1291                          * overflow.
1292                          */
1293                         if (!initial_trace_ips && (frame_count < 1000)) {
1294                                 trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1295                                 trace_ips = g_list_prepend (trace_ips,
1296                                                                                         get_generic_info_from_stack_frame (ji, ctx));
1297                         }
1298                 }
1299
1300                 if (method->dynamic)
1301                         dynamic_methods = g_slist_prepend (dynamic_methods, method);
1302
1303                 if (stack_overflow) {
1304                         if (DOES_STACK_GROWS_UP)
1305                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1306                         else
1307                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1308                 } else {
1309                         free_stack = 0xffffff;
1310                 }
1311                                 
1312                 for (i = clause_index_start; i < ji->num_clauses; i++) {
1313                         MonoJitExceptionInfo *ei = &ji->clauses [i];
1314                         gboolean filtered = FALSE;
1315
1316                         /* 
1317                          * During stack overflow, wait till the unwinding frees some stack
1318                          * space before running handlers/finalizers.
1319                          */
1320                         if (free_stack <= (64 * 1024))
1321                                 continue;
1322
1323                         if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1324                                 /* catch block */
1325                                 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1326
1327                                 /*
1328                                  * Have to unwrap RuntimeWrappedExceptions if the
1329                                  * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1330                                  */
1331                                 if (non_exception && !wrap_non_exception_throws (method))
1332                                         ex_obj = non_exception;
1333                                 else
1334                                         ex_obj = obj;
1335
1336                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1337                                         gboolean is_user_frame = method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD;
1338 #ifndef DISABLE_PERFCOUNTERS
1339                                         mono_perfcounters->exceptions_filters++;
1340 #endif
1341                                         /*
1342                                         Here's the thing, if this is a filter clause done by a wrapper like runtime invoke, we don't want to
1343                                         trim the stackframe since if it returns FALSE we lose information.
1344
1345                                         FIXME Not 100% sure if it's a good idea even with user clauses.
1346                                         */
1347                                         if (is_user_frame)
1348                                                 setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
1349
1350 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1351                                         if (ji->from_llvm)
1352                                                 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1353                                         else
1354                                                 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
1355                                                 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1356 #else
1357                                         g_assert (!ji->from_llvm);
1358                                         /* store the exception object in bp + ei->exvar_offset */
1359                                         *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1360 #endif
1361
1362 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
1363                                         /*
1364                                          * Pass the original il clause index to the landing pad so it can
1365                                          * branch to the landing pad associated with the il clause.
1366                                          * This is needed because llvm compiled code assumes that the EH
1367                                          * code always branches to the innermost landing pad.
1368                                          */
1369                                         if (ji->from_llvm)
1370                                                 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
1371 #endif
1372
1373                                         mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx);
1374                                         filtered = call_filter (ctx, ei->data.filter);
1375                                         mono_debugger_agent_end_exception_filter (mono_ex, ctx, &initial_ctx);
1376                                         if (filtered && out_filter_idx)
1377                                                 *out_filter_idx = filter_idx;
1378                                         if (out_ji)
1379                                                 *out_ji = ji;
1380                                         filter_idx ++;
1381
1382                                         if (filtered) {
1383                                                 if (!is_user_frame)
1384                                                         setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
1385                                                 g_slist_free (dynamic_methods);
1386                                                 /* mono_debugger_agent_handle_exception () needs this */
1387                                                 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1388                                                 return TRUE;
1389                                         }
1390                                 }
1391
1392                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (ex_obj, catch_class)) {
1393                                         setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
1394                                         g_slist_free (dynamic_methods);
1395
1396                                         if (out_ji)
1397                                                 *out_ji = ji;
1398
1399                                         /* mono_debugger_agent_handle_exception () needs this */
1400                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1401                                         return TRUE;
1402                                 }
1403                         }
1404                 }
1405
1406                 *ctx = new_ctx;
1407         }
1408
1409         g_assert_not_reached ();
1410 }
1411
1412 /**
1413  * mono_handle_exception_internal:
1414  * @ctx: saved processor state
1415  * @obj: the exception object
1416  * @resume: whenever to resume unwinding based on the state in MonoJitTlsData.
1417  */
1418 static gboolean
1419 mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji)
1420 {
1421         MonoDomain *domain = mono_domain_get ();
1422         MonoJitInfo *ji, *prev_ji;
1423         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1424         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1425         MonoLMF *lmf = mono_get_lmf ();
1426         MonoException *mono_ex;
1427         gboolean stack_overflow = FALSE;
1428         MonoContext initial_ctx;
1429         MonoMethod *method;
1430         int frame_count = 0;
1431         gint32 filter_idx, first_filter_idx = 0;
1432         int i;
1433         MonoObject *ex_obj;
1434         MonoObject *non_exception = NULL;
1435
1436         g_assert (ctx != NULL);
1437         if (!obj) {
1438                 MonoException *ex = mono_get_exception_null_reference ();
1439                 MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object"));
1440                 obj = (MonoObject *)ex;
1441         } 
1442
1443         /*
1444          * Allocate a new exception object instead of the preconstructed ones.
1445          */
1446         if (obj == (MonoObject *)domain->stack_overflow_ex) {
1447                 /*
1448                  * It is not a good idea to try and put even more pressure on the little stack available.
1449                  * obj = mono_get_exception_stack_overflow ();
1450                  */
1451                 stack_overflow = TRUE;
1452         }
1453         else if (obj == (MonoObject *)domain->null_reference_ex) {
1454                 obj = (MonoObject *)mono_get_exception_null_reference ();
1455         }
1456
1457         if (!mono_object_isinst (obj, mono_defaults.exception_class)) {
1458                 non_exception = obj;
1459                 obj = (MonoObject *)mono_get_exception_runtime_wrapped (obj);
1460         }
1461
1462         mono_ex = (MonoException*)obj;
1463
1464         if (mini_get_debug_options ()->suspend_on_exception) {
1465                 mono_runtime_printf_err ("Exception thrown, suspending...");
1466                 while (1)
1467                         ;
1468         }
1469
1470         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1471                 mono_ex = (MonoException*)obj;
1472         } else {
1473                 mono_ex = NULL;
1474         }
1475
1476         if (mono_ex && jit_tls->class_cast_from) {
1477                 if (!strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) {
1478                         char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1479                         char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1480                         char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
1481                         mono_ex->message = mono_string_new (domain, msg);
1482                         g_free (from_name);
1483                         g_free (to_name);
1484                         g_free (msg);
1485                 }
1486                 if (!strcmp (mono_ex->object.vtable->klass->name, "ArrayTypeMismatchException")) {
1487                         char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1488                         char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1489                         char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
1490                         mono_ex->message = mono_string_new (domain, msg);
1491                         g_free (from_name);
1492                         g_free (to_name);
1493                         g_free (msg);
1494                 }
1495         }
1496
1497         if (!call_filter)
1498                 call_filter = (int (*)(MonoContext *, void*))mono_get_call_filter ();
1499
1500         g_assert (jit_tls->end_of_stack);
1501         g_assert (jit_tls->abort_func);
1502
1503         /*
1504          * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
1505          * end up being TRUE on any code path.
1506          */
1507         memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
1508
1509         if (!resume) {
1510                 gboolean res;
1511
1512                 MonoContext ctx_cp = *ctx;
1513                 if (mono_trace_is_enabled ()) {
1514                         MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0);
1515                         MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message);
1516                         MonoObject *message;
1517                         const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
1518                         char *msg = NULL;
1519                         MonoObject *exc = NULL;
1520                         if (get_message == NULL) {
1521                                 message = NULL;
1522                         } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
1523                                 message = NULL;
1524                                 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
1525                         } else {
1526                                 message = mono_runtime_invoke (get_message, obj, NULL, &exc);
1527                                 
1528                         }
1529                         if (msg == NULL) {
1530                                 msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
1531                         }
1532                         g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)mono_native_thread_id_get (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
1533                         g_free (msg);
1534                         if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
1535                                 mono_print_thread_dump_from_ctx (ctx);
1536                 }
1537                 jit_tls->orig_ex_ctx_set = TRUE;
1538                 mono_profiler_exception_thrown (obj);
1539                 jit_tls->orig_ex_ctx_set = FALSE;
1540
1541                 res = mono_handle_exception_internal_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception);
1542
1543                 if (!res) {
1544                         if (mini_get_debug_options ()->break_on_exc)
1545                                 G_BREAKPOINT ();
1546                         mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL);
1547
1548                         if (mini_get_debug_options ()->suspend_on_unhandled) {
1549                                 mono_runtime_printf_err ("Unhandled exception, suspending...");
1550                                 while (1)
1551                                         ;
1552                         }
1553
1554                         // FIXME: This runs managed code so it might cause another stack overflow when
1555                         // we are handling a stack overflow
1556                         mono_unhandled_exception (obj);
1557                 } else {
1558                         gboolean unhandled = FALSE;
1559
1560                         /*
1561                          * The exceptions caught by the mono_runtime_invoke () calls
1562                          * in the threadpool needs to be treated as unhandled (#669836).
1563                          *
1564                          * FIXME: The check below is hackish, but its hard to distinguish
1565                          * these runtime invoke calls from others in the runtime.
1566                          */
1567                         if (ji && jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
1568                                 if (prev_ji && jinfo_get_method (prev_ji) == mono_defaults.threadpool_perform_wait_callback_method)
1569                                         unhandled = TRUE;
1570                         }
1571
1572                         if (unhandled)
1573                                 mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL);
1574                         else
1575                                 mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, &ctx_cp);
1576                 }
1577         }
1578
1579         if (out_ji)
1580                 *out_ji = NULL;
1581         filter_idx = 0;
1582         initial_ctx = *ctx;
1583
1584         while (1) {
1585                 MonoContext new_ctx;
1586                 guint32 free_stack;
1587                 int clause_index_start = 0;
1588                 gboolean unwind_res = TRUE;
1589                 
1590                 if (resume) {
1591                         resume = FALSE;
1592                         ji = jit_tls->resume_state.ji;
1593                         new_ctx = jit_tls->resume_state.new_ctx;
1594                         clause_index_start = jit_tls->resume_state.clause_index;
1595                         lmf = jit_tls->resume_state.lmf;
1596                         first_filter_idx = jit_tls->resume_state.first_filter_idx;
1597                         filter_idx = jit_tls->resume_state.filter_idx;
1598                 } else {
1599                         StackFrameInfo frame;
1600
1601                         unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1602                         if (unwind_res) {
1603                                 if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
1604                                                 frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
1605                                                 frame.type == FRAME_TYPE_TRAMPOLINE) {
1606                                         *ctx = new_ctx;
1607                                         continue;
1608                                 }
1609                                 g_assert (frame.type == FRAME_TYPE_MANAGED);
1610                                 ji = frame.ji;
1611                         }
1612                 }
1613
1614                 if (!unwind_res) {
1615                         *(mono_get_lmf_addr ()) = lmf;
1616
1617                         jit_tls->abort_func (obj);
1618                         g_assert_not_reached ();
1619                 }
1620
1621                 method = jinfo_get_method (ji);
1622                 frame_count ++;
1623                 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
1624
1625                 if (stack_overflow) {
1626                         if (DOES_STACK_GROWS_UP)
1627                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1628                         else
1629                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1630                 } else {
1631                         free_stack = 0xffffff;
1632                 }
1633                                 
1634                 for (i = clause_index_start; i < ji->num_clauses; i++) {
1635                         MonoJitExceptionInfo *ei = &ji->clauses [i];
1636                         gboolean filtered = FALSE;
1637
1638                         /* 
1639                          * During stack overflow, wait till the unwinding frees some stack
1640                          * space before running handlers/finalizers.
1641                          */
1642                         if (free_stack <= (64 * 1024))
1643                                 continue;
1644
1645                         if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1646                                 /* catch block */
1647                                 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1648
1649                                 /*
1650                                  * Have to unwrap RuntimeWrappedExceptions if the
1651                                  * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1652                                  */
1653                                 if (non_exception && !wrap_non_exception_throws (method))
1654                                         ex_obj = non_exception;
1655                                 else
1656                                         ex_obj = obj;
1657
1658                                 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
1659 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1660                                         MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1661 #else
1662                                         g_assert (!ji->from_llvm);
1663                                         /* store the exception object in bp + ei->exvar_offset */
1664                                         *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1665 #endif
1666                                 }
1667
1668 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
1669                                 if (ji->from_llvm)
1670                                         MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
1671 #endif
1672
1673                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1674                                         /* 
1675                                          * Filter clauses should only be run in the 
1676                                          * first pass of exception handling.
1677                                          */
1678                                         filtered = (filter_idx == first_filter_idx);
1679                                         filter_idx ++;
1680                                 }
1681
1682                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
1683                                          mono_object_isinst (ex_obj, catch_class)) || filtered) {
1684                                         /*
1685                                          * This guards against the situation that we abort a thread that is executing a finally clause
1686                                          * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
1687                                          * check for this situation here and resume interruption if we are below the guarded block.
1688                                          */
1689                                         if (G_UNLIKELY (jit_tls->handler_block_return_address)) {
1690                                                 gboolean is_outside = FALSE;
1691                                                 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
1692                                                 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
1693                                                 //FIXME make this stack direction aware
1694                                                 if (catch_bp > prot_bp) {
1695                                                         is_outside = TRUE;
1696                                                 } else if (catch_bp == prot_bp) {
1697                                                         /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
1698                                                          * So we check if the catch handler_start is protected by the guarded handler protected region
1699                                                          *
1700                                                          * Assumptions:
1701                                                          *      If there is an outstanding guarded_block return address, it means the current thread must be aborted.
1702                                                          *      This is the only way to reach out the guarded block as other cases are handled by the trampoline.
1703                                                          *      There aren't any further finally/fault handler blocks down the stack over this exception.
1704                                                          *   This must be ensured by the code that installs the guard trampoline.
1705                                                          */
1706                                                         g_assert (ji == mini_jit_info_table_find (domain, (char *)MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
1707
1708                                                         if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
1709                                                                 is_outside = TRUE;
1710                                                         }
1711                                                 }
1712                                                 if (is_outside) {
1713                                                         jit_tls->handler_block_return_address = NULL;
1714                                                         jit_tls->handler_block = NULL;
1715                                                         mono_thread_resume_interruption (); /*We ignore the exception here, it will be raised later*/
1716                                                 }
1717                                         }
1718
1719                                         if (mono_trace_is_enabled () && mono_trace_eval (method))
1720                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE));
1721                                         jit_tls->orig_ex_ctx_set = TRUE;
1722                                         mono_profiler_exception_clause_handler (method, ei->flags, i);
1723                                         jit_tls->orig_ex_ctx_set = FALSE;
1724                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1725                                         mono_set_lmf (lmf);
1726 #ifndef DISABLE_PERFCOUNTERS
1727                                         mono_perfcounters->exceptions_depth += frame_count;
1728 #endif
1729                                         if (obj == (MonoObject *)domain->stack_overflow_ex)
1730                                                 jit_tls->handling_stack_ovf = FALSE;
1731
1732                                         return 0;
1733                                 }
1734                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
1735                                         if (mono_trace_is_enabled () && mono_trace_eval (method))
1736                                                 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
1737                                         jit_tls->orig_ex_ctx_set = TRUE;
1738                                         mono_profiler_exception_clause_handler (method, ei->flags, i);
1739                                         jit_tls->orig_ex_ctx_set = FALSE;
1740                                         call_filter (ctx, ei->handler_start);
1741                                 }
1742                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
1743                                         if (mono_trace_is_enabled () && mono_trace_eval (method))
1744                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
1745                                         jit_tls->orig_ex_ctx_set = TRUE;
1746                                         mono_profiler_exception_clause_handler (method, ei->flags, i);
1747                                         jit_tls->orig_ex_ctx_set = FALSE;
1748 #ifndef DISABLE_PERFCOUNTERS
1749                                         mono_perfcounters->exceptions_finallys++;
1750 #endif
1751                                         mono_set_lmf (lmf);
1752                                         if (ji->from_llvm) {
1753                                                 /* 
1754                                                  * LLVM compiled finally handlers follow the design
1755                                                  * of the c++ ehabi, i.e. they call a resume function
1756                                                  * at the end instead of returning to the caller.
1757                                                  * So save the exception handling state,
1758                                                  * mono_resume_unwind () will call us again to continue
1759                                                  * the unwinding.
1760                                                  */
1761                                                 jit_tls->resume_state.ex_obj = obj;
1762                                                 jit_tls->resume_state.ji = ji;
1763                                                 jit_tls->resume_state.clause_index = i + 1;
1764                                                 jit_tls->resume_state.ctx = *ctx;
1765                                                 jit_tls->resume_state.new_ctx = new_ctx;
1766                                                 jit_tls->resume_state.lmf = lmf;
1767                                                 jit_tls->resume_state.first_filter_idx = first_filter_idx;
1768                                                 jit_tls->resume_state.filter_idx = filter_idx;
1769                                                 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1770                                                 return 0;
1771                                         } else {
1772                                                 call_filter (ctx, ei->handler_start);
1773                                         }
1774                                 }
1775                         }
1776                 }
1777
1778                 jit_tls->orig_ex_ctx_set = TRUE;
1779                 mono_profiler_exception_method_leave (method);
1780                 jit_tls->orig_ex_ctx_set = FALSE;
1781
1782                 *ctx = new_ctx;
1783         }
1784
1785         g_assert_not_reached ();
1786 }
1787
1788 /**
1789  * mono_debugger_run_finally:
1790  * @start_ctx: saved processor state
1791  *
1792  * This method is called by the Mono Debugger to call all `finally' clauses of the
1793  * current stack frame.  It's used when the user issues a `return' command to make
1794  * the current stack frame return.  After returning from this method, the debugger
1795  * unwinds the stack one frame and gives control back to the user.
1796  *
1797  * NOTE: This method is only used when running inside the Mono Debugger.
1798  */
1799 void
1800 mono_debugger_run_finally (MonoContext *start_ctx)
1801 {
1802         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1803         MonoDomain *domain = mono_domain_get ();
1804         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1805         MonoLMF *lmf = mono_get_lmf ();
1806         MonoContext ctx, new_ctx;
1807         MonoJitInfo *ji, rji;
1808         int i;
1809
1810         ctx = *start_ctx;
1811
1812         ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1813         if (!ji || ji == (gpointer)-1)
1814                 return;
1815
1816         if (!call_filter)
1817                 call_filter = (int (*)(MonoContext *, void *))mono_get_call_filter ();
1818
1819         for (i = 0; i < ji->num_clauses; i++) {
1820                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1821
1822                 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
1823                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1824                         call_filter (&ctx, ei->handler_start);
1825                 }
1826         }
1827 }
1828
1829 /**
1830  * mono_handle_exception:
1831  * @ctx: saved processor state
1832  * @obj: the exception object
1833  */
1834 gboolean
1835 mono_handle_exception (MonoContext *ctx, MonoObject *obj)
1836 {
1837 #ifndef DISABLE_PERFCOUNTERS
1838         mono_perfcounters->exceptions_thrown++;
1839 #endif
1840
1841         return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
1842 }
1843
1844 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1845
1846 #ifndef MONO_ARCH_USE_SIGACTION
1847 #error "Can't use sigaltstack without sigaction"
1848 #endif
1849
1850 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1851
1852 void
1853 mono_setup_altstack (MonoJitTlsData *tls)
1854 {
1855         size_t stsize = 0;
1856         stack_t sa;
1857         guint8 *staddr = NULL;
1858
1859         if (mono_running_on_valgrind ())
1860                 return;
1861
1862         mono_thread_info_get_stack_bounds (&staddr, &stsize);
1863
1864         g_assert (staddr);
1865
1866         tls->end_of_stack = staddr + stsize;
1867         tls->stack_size = stsize;
1868
1869         /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1870
1871         tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1872         tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
1873
1874         g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
1875
1876         if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1877                 /* mprotect can fail for the main thread stack */
1878                 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);
1879                 g_assert (gaddr == tls->stack_ovf_guard_base);
1880                 tls->stack_ovf_valloced = TRUE;
1881         }
1882
1883         /* Setup an alternate signal stack */
1884         tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
1885         tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1886
1887         g_assert (tls->signal_stack);
1888
1889         sa.ss_sp = tls->signal_stack;
1890         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1891         sa.ss_flags = 0;
1892         g_assert (sigaltstack (&sa, NULL) == 0);
1893
1894         mono_gc_register_altstack ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size, (char*)staddr + stsize - ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size), tls->signal_stack, tls->signal_stack_size);
1895 }
1896
1897 void
1898 mono_free_altstack (MonoJitTlsData *tls)
1899 {
1900         stack_t sa;
1901         int err;
1902
1903         sa.ss_sp = tls->signal_stack;
1904         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1905         sa.ss_flags = SS_DISABLE;
1906         err = sigaltstack  (&sa, NULL);
1907         g_assert (err == 0);
1908
1909         if (tls->signal_stack)
1910                 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1911         if (tls->stack_ovf_valloced)
1912                 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size);
1913         else
1914                 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1915 }
1916
1917 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1918
1919 void
1920 mono_setup_altstack (MonoJitTlsData *tls)
1921 {
1922 }
1923
1924 void
1925 mono_free_altstack (MonoJitTlsData *tls)
1926 {
1927 }
1928
1929 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1930
1931 static gboolean
1932 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
1933 {
1934         gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
1935         /* we need to leave some room for throwing the exception */
1936         while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
1937                 unprotect_size -= mono_pagesize ();
1938         /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1939          * is sufficient stack
1940          */
1941         //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);
1942         if (unprotect_size)
1943                 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
1944         return unprotect_size == jit_tls->stack_ovf_guard_size;
1945 }
1946
1947 static G_GNUC_UNUSED void
1948 try_more_restore (void)
1949 {
1950         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1951         if (try_restore_stack_protection (jit_tls, 500))
1952                 jit_tls->restore_stack_prot = NULL;
1953 }
1954
1955 static G_GNUC_UNUSED void
1956 restore_stack_protection (void)
1957 {
1958         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1959         MonoException *ex = mono_domain_get ()->stack_overflow_ex;
1960         /* if we can't restore the stack protection, keep a callback installed so
1961          * we'll try to restore as much stack as we can at each return from unmanaged
1962          * code.
1963          */
1964         if (try_restore_stack_protection (jit_tls, 4096))
1965                 jit_tls->restore_stack_prot = NULL;
1966         else
1967                 jit_tls->restore_stack_prot = try_more_restore_tramp;
1968         /* here we also throw a stack overflow exception */
1969         ex->trace_ips = NULL;
1970         ex->stack_trace = NULL;
1971         mono_raise_exception (ex);
1972 }
1973
1974 gpointer
1975 mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
1976 {
1977         void (*func)(void) = (void (*)(void))tramp_data;
1978         func ();
1979         return NULL;
1980 }
1981
1982 gboolean
1983 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
1984 {
1985         if (mono_llvm_only)
1986                 return FALSE;
1987
1988         /* we got a stack overflow in the soft-guard pages
1989          * There are two cases:
1990          * 1) managed code caused the overflow: we unprotect the soft-guard page
1991          * and let the arch-specific code trigger the exception handling mechanism
1992          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1993          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1994          * and hope we can continue with those enabled, at least until the hard-guard page
1995          * is hit. The alternative to continuing here is to just print a message and abort.
1996          * We may add in the future the code to protect the pages again in the codepath
1997          * when we return from unmanaged to managed code.
1998          */
1999         if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
2000                         fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
2001                 /* we unprotect the minimum amount we can */
2002                 guint32 guard_size;
2003                 gboolean handled = FALSE;
2004
2005                 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
2006                 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
2007                         guard_size -= mono_pagesize ();
2008                 }
2009                 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
2010                 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
2011                 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);
2012 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2013                 if (ji) {
2014                         mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE);
2015                         handled = TRUE;
2016                 }
2017 #endif
2018                 if (!handled) {
2019                         /* We print a message: after this even managed stack overflows
2020                          * may crash the runtime
2021                          */
2022                         mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
2023                         if (!jit_tls->handling_stack_ovf) {
2024                                 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
2025                                 jit_tls->handling_stack_ovf = 1;
2026                         } else {
2027                                 /*fprintf (stderr, "Already handling stack overflow\n");*/
2028                         }
2029                 }
2030                 return TRUE;
2031         }
2032         return FALSE;
2033 }
2034
2035 typedef struct {
2036         MonoMethod *omethod;
2037         int count;
2038 } PrintOverflowUserData;
2039
2040 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2041 static gboolean
2042 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2043 {
2044         MonoMethod *method = NULL;
2045         PrintOverflowUserData *user_data = (PrintOverflowUserData *)data;
2046         gchar *location;
2047
2048         if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2049                 method = jinfo_get_method (frame->ji);
2050
2051         if (method) {
2052                 if (user_data->count == 0) {
2053                         /* The first frame is in its prolog, so a line number cannot be computed */
2054                         user_data->count ++;
2055                         return FALSE;
2056                 }
2057
2058                 /* If this is a one method overflow, skip the other instances */
2059                 if (method == user_data->omethod)
2060                         return FALSE;
2061
2062                 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2063                 mono_runtime_printf_err ("  %s", location);
2064                 g_free (location);
2065
2066                 if (user_data->count == 1) {
2067                         mono_runtime_printf_err ("  <...>");
2068                         user_data->omethod = method;
2069                 } else {
2070                         user_data->omethod = NULL;
2071                 }
2072
2073                 user_data->count ++;
2074         } else
2075                 mono_runtime_printf_err ("  at <unknown> <0x%05x>", frame->native_offset);
2076
2077         return FALSE;
2078 }
2079 #endif
2080
2081 void
2082 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
2083 {
2084 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2085         PrintOverflowUserData ud;
2086         MonoContext mctx;
2087 #endif
2088
2089         /* we don't do much now, but we can warn the user with a useful message */
2090         mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
2091
2092 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2093         mono_sigctx_to_monoctx (ctx, &mctx);
2094                         
2095         mono_runtime_printf_err ("Stacktrace:");
2096
2097         memset (&ud, 0, sizeof (ud));
2098
2099         mono_walk_stack_with_ctx (print_overflow_stack_frame, &mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
2100 #else
2101         if (ji && !ji->is_trampoline && jinfo_get_method (ji))
2102                 mono_runtime_printf_err ("At %s", mono_method_full_name (jinfo_get_method (ji), TRUE));
2103         else
2104                 mono_runtime_printf_err ("At <unmanaged>.");
2105 #endif
2106
2107         _exit (1);
2108 }
2109
2110 static gboolean
2111 print_stack_frame_to_stderr (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2112 {
2113         MonoMethod *method = NULL;
2114
2115         if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2116                 method = jinfo_get_method (frame->ji);
2117
2118         if (method) {
2119                 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2120                 mono_runtime_printf_err ("  %s", location);
2121                 g_free (location);
2122         } else
2123                 mono_runtime_printf_err ("  at <unknown> <0x%05x>", frame->native_offset);
2124
2125         return FALSE;
2126 }
2127
2128 static G_GNUC_UNUSED gboolean
2129 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2130 {
2131         GString *p = (GString*)data;
2132         MonoMethod *method = NULL;
2133
2134         if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2135                 method = jinfo_get_method (frame->ji);
2136
2137         if (method && frame->domain) {
2138                 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
2139                 g_string_append_printf (p, "  %s\n", location);
2140                 g_free (location);
2141         } else
2142                 g_string_append_printf (p, "  at <unknown> <0x%05x>\n", frame->native_offset);
2143
2144         return FALSE;
2145 }
2146
2147 #ifndef MONO_CROSS_COMPILE
2148
2149 static gboolean handling_sigsegv = FALSE;
2150
2151 /*
2152  * mono_handle_native_sigsegv:
2153  *
2154  *   Handle a SIGSEGV received while in native code by printing diagnostic 
2155  * information and aborting.
2156  */
2157 void
2158 mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
2159 {
2160 #ifdef MONO_ARCH_USE_SIGACTION
2161         struct sigaction sa;
2162 #endif
2163         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
2164         const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
2165
2166         if (handling_sigsegv)
2167                 return;
2168
2169         if (mini_get_debug_options ()->suspend_on_sigsegv) {
2170                 mono_runtime_printf_err ("Received SIGSEGV, suspending...");
2171 #ifdef HOST_WIN32
2172                 while (1)
2173                         ;
2174 #else
2175                 while (1) {
2176                         sleep (1);
2177                 }
2178 #endif
2179         }
2180
2181         /* To prevent infinite loops when the stack walk causes a crash */
2182         handling_sigsegv = TRUE;
2183
2184         /* !jit_tls means the thread was not registered with the runtime */
2185         if (jit_tls && mono_thread_internal_current ()) {
2186                 mono_runtime_printf_err ("Stacktrace:\n");
2187
2188                 /* FIXME: Is MONO_UNWIND_LOOKUP_IL_OFFSET correct here? */
2189                 mono_walk_stack (print_stack_frame_to_stderr, MONO_UNWIND_LOOKUP_IL_OFFSET, NULL);
2190         }
2191
2192 #ifdef HAVE_BACKTRACE_SYMBOLS
2193  {
2194         void *array [256];
2195         char **names;
2196         int i, size;
2197
2198         mono_runtime_printf_err ("\nNative stacktrace:\n");
2199
2200         size = backtrace (array, 256);
2201         names = backtrace_symbols (array, size);
2202         for (i =0; i < size; ++i) {
2203                 mono_runtime_printf_err ("\t%s", names [i]);
2204         }
2205         free (names);
2206
2207         /* Try to get more meaningful information using gdb */
2208
2209 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
2210         if (!mini_get_debug_options ()->no_gdb_backtrace) {
2211                 /* From g_spawn_command_line_sync () in eglib */
2212                 pid_t pid;
2213                 int status;
2214                 pid_t crashed_pid = getpid ();
2215
2216                 //pid = fork ();
2217                 /*
2218                  * glibc fork acquires some locks, so if the crash happened inside malloc/free,
2219                  * it will deadlock. Call the syscall directly instead.
2220                  */
2221                 pid = mono_runtime_syscall_fork ();
2222 #if defined (HAVE_PRCTL) && defined(PR_SET_PTRACER)
2223                 if (pid > 0) {
2224                         // Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to
2225                         // a value other than 0 (the most permissive ptrace scope). Most modern Linux
2226                         // distributions set the scope to 1 which allows attaching only to direct children of
2227                         // the current process
2228                         prctl (PR_SET_PTRACER, pid, 0, 0, 0);
2229                 }
2230 #endif
2231                 if (pid == 0) {
2232                         dup2 (STDERR_FILENO, STDOUT_FILENO);
2233
2234                         mono_gdb_render_native_backtraces (crashed_pid);
2235                         exit (1);
2236                 }
2237
2238                 mono_runtime_printf_err ("\nDebug info from gdb:\n");
2239                 waitpid (pid, &status, 0);
2240         }
2241 #endif
2242  }
2243 #elif defined (ENABLE_EXTENSION_MODULE)
2244         mono_extension_handle_native_sigsegv (ctx, info);
2245 #endif
2246
2247         /*
2248          * A SIGSEGV indicates something went very wrong so we can no longer depend
2249          * on anything working. So try to print out lots of diagnostics, starting 
2250          * with ones which have a greater chance of working.
2251          */
2252         mono_runtime_printf_err (
2253                          "\n"
2254                          "=================================================================\n"
2255                          "Got a %s while executing native code. This usually indicates\n"
2256                          "a fatal error in the mono runtime or one of the native libraries \n"
2257                          "used by your application.\n"
2258                          "=================================================================\n",
2259                         signal_str);
2260
2261
2262 #ifdef MONO_ARCH_USE_SIGACTION
2263
2264         /* Remove our SIGABRT handler */
2265         sa.sa_handler = SIG_DFL;
2266         sigemptyset (&sa.sa_mask);
2267         sa.sa_flags = 0;
2268
2269         g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
2270
2271 #endif
2272
2273         if (!mono_do_crash_chaining) {
2274                 /*Android abort is a fluke, it doesn't abort, it triggers another segv. */
2275 #if defined (PLATFORM_ANDROID)
2276                 exit (-1);
2277 #else
2278                 abort ();
2279 #endif
2280         }
2281 }
2282
2283 #else
2284
2285 void
2286 mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
2287 {
2288         g_assert_not_reached ();
2289 }
2290
2291 #endif /* !MONO_CROSS_COMPILE */
2292
2293 static void
2294 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
2295 {
2296         MonoInternalThread *thread = mono_thread_internal_current ();
2297 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2298         MonoContext ctx;
2299 #endif
2300         GString* text;
2301         char *name;
2302 #ifndef HOST_WIN32
2303         char *wapi_desc;
2304 #endif
2305         GError *error = NULL;
2306
2307         if (!thread)
2308                 return;
2309
2310         text = g_string_new (0);
2311         if (thread->name) {
2312                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
2313                 g_assert (!error);
2314                 g_string_append_printf (text, "\n\"%s\"", name);
2315                 g_free (name);
2316         }
2317         else if (thread->threadpool_thread)
2318                 g_string_append (text, "\n\"<threadpool thread>\"");
2319         else
2320                 g_string_append (text, "\n\"<unnamed thread>\"");
2321
2322 #ifndef HOST_WIN32
2323         wapi_desc = wapi_current_thread_desc ();
2324         g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread,  wapi_desc);
2325         free (wapi_desc);
2326 #endif
2327
2328 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2329         if (start_ctx) {
2330                 memcpy (&ctx, start_ctx, sizeof (MonoContext));
2331         } else if (!sigctx)
2332                 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
2333         else
2334                 mono_sigctx_to_monoctx (sigctx, &ctx);
2335
2336         mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
2337 #else
2338         mono_runtime_printf ("\t<Stack traces in thread dumps not supported on this platform>");
2339 #endif
2340
2341         mono_runtime_printf ("%s", text->str);
2342
2343 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
2344         OutputDebugStringA(text->str);
2345 #endif
2346
2347         g_string_free (text, TRUE);
2348         mono_runtime_stdout_fflush ();
2349 }
2350
2351 /*
2352  * mono_print_thread_dump:
2353  *
2354  *   Print information about the current thread to stdout.
2355  * SIGCTX can be NULL, allowing this to be called from gdb.
2356  */
2357 void
2358 mono_print_thread_dump (void *sigctx)
2359 {
2360         mono_print_thread_dump_internal (sigctx, NULL);
2361 }
2362
2363 void
2364 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2365 {
2366         mono_print_thread_dump_internal (NULL, ctx);
2367 }
2368
2369 /*
2370  * mono_resume_unwind:
2371  *
2372  *   This is called by a trampoline from LLVM compiled finally clauses to continue
2373  * unwinding.
2374  */
2375 void
2376 mono_resume_unwind (MonoContext *ctx)
2377 {
2378         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
2379         MonoContext new_ctx;
2380
2381         MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
2382         MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
2383         new_ctx = *ctx;
2384
2385         mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL);
2386
2387         mono_restore_context (&new_ctx);
2388 }
2389
2390 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
2391
2392 typedef struct {
2393         MonoJitInfo *ji;
2394         MonoContext ctx;
2395         MonoJitExceptionInfo *ei;
2396 } FindHandlerBlockData;
2397
2398 static gboolean
2399 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2400 {
2401         int i;
2402         gpointer ip;
2403         FindHandlerBlockData *pdata = (FindHandlerBlockData *)data;
2404         MonoJitInfo *ji = frame->ji;
2405
2406         if (!ji)
2407                 return FALSE;
2408
2409         ip = MONO_CONTEXT_GET_IP (ctx);
2410
2411         for (i = 0; i < ji->num_clauses; ++i) {
2412                 MonoJitExceptionInfo *ei = ji->clauses + i;
2413                 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2414                         continue;
2415                 /*If ip points to the first instruction it means the handler block didn't start
2416                  so we can leave its execution to the EH machinery*/
2417                 if (ei->handler_start < ip && ip < ei->data.handler_end) {
2418                         pdata->ji = ji;
2419                         pdata->ei = ei;
2420                         pdata->ctx = *ctx;
2421                         break;
2422                 }
2423         }
2424         return FALSE;
2425 }
2426
2427
2428 static gpointer
2429 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
2430 {
2431         int i;
2432         MonoJitExceptionInfo *clause = NULL;
2433         gpointer ip;
2434
2435         ip = MONO_CONTEXT_GET_IP (ctx);
2436
2437         for (i = 0; i < ji->num_clauses; ++i) {
2438                 clause = &ji->clauses [i];
2439                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2440                         continue;
2441                 if (clause->handler_start < ip && clause->data.handler_end > ip)
2442                         break;
2443         }
2444
2445         /*no matching finally */
2446         if (i == ji->num_clauses)
2447                 return NULL;
2448
2449         /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
2450         if (ip == clause->handler_start)
2451                 return NULL;
2452
2453         return mono_arch_install_handler_block_guard (ji, clause, ctx, mono_create_handler_block_trampoline ());
2454 }
2455
2456 /*
2457  * Finds the bottom handler block running and install a block guard if needed.
2458  * FIXME add full-aot support.
2459  */
2460 gboolean
2461 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
2462 {
2463         FindHandlerBlockData data = { 0 };
2464         MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
2465         gpointer resume_ip;
2466
2467         /* FIXME */
2468         if (mono_aot_only)
2469                 return FALSE;
2470
2471         /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
2472          * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
2473          */
2474         if (!jit_tls || jit_tls->handler_block_return_address)
2475                 return FALSE;
2476
2477         /* Do an async safe stack walk */
2478         mono_thread_info_set_is_async_context (TRUE);
2479         mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data);
2480         mono_thread_info_set_is_async_context (FALSE);
2481
2482         if (!data.ji)
2483                 return FALSE;
2484
2485         memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
2486
2487         resume_ip = install_handler_block_guard (data.ji, &data.ctx);
2488         if (resume_ip == NULL)
2489                 return FALSE;
2490
2491         jit_tls->handler_block_return_address = resume_ip;
2492         jit_tls->handler_block = data.ei;
2493
2494         return TRUE;
2495 }
2496
2497 #else
2498 gboolean
2499 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
2500 {
2501         return FALSE;
2502 }
2503
2504 #endif
2505
2506 void
2507 mono_set_cast_details (MonoClass *from, MonoClass *to)
2508 {
2509         MonoJitTlsData *jit_tls = NULL;
2510
2511         if (mini_get_debug_options ()->better_cast_details) {
2512                 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
2513                 jit_tls->class_cast_from = from;
2514                 jit_tls->class_cast_to = to;
2515         }
2516 }
2517
2518
2519 /*returns false if the thread is not attached*/
2520 gboolean
2521 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
2522 {
2523 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2524         MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
2525         if (!thread) {
2526                 ctx->valid = FALSE;
2527                 G_BREAKPOINT ();
2528                 return FALSE;
2529         }
2530
2531         if (sigctx) {
2532                 mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
2533
2534                 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2535                 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2536                 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2537         }
2538         else {
2539                 mono_thread_state_init (ctx);
2540         }
2541
2542         if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
2543                 return FALSE;
2544
2545         ctx->valid = TRUE;
2546         return TRUE;
2547 #else
2548         g_error ("Implement mono_arch_sigctx_to_monoctx for the current target");
2549         return FALSE;
2550 #endif
2551 }
2552
2553 void
2554 mono_thread_state_init (MonoThreadUnwindState *ctx)
2555 {
2556         MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
2557
2558 #if defined(MONO_CROSS_COMPILE)
2559         ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
2560 #elif MONO_ARCH_HAS_MONO_CONTEXT
2561         MONO_CONTEXT_GET_CURRENT (ctx->ctx);
2562 #else
2563         g_error ("Use a null sigctx requires a working mono-context");
2564 #endif
2565
2566         ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2567         ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2568         ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
2569         ctx->valid = TRUE;
2570 }
2571
2572
2573 gboolean
2574 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
2575 {
2576         MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
2577         if (!thread) {
2578                 ctx->valid = FALSE;
2579                 return FALSE;
2580         }
2581
2582         ctx->ctx = *mctx;
2583         ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2584         ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2585         ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2586         ctx->valid = TRUE;
2587         return TRUE;
2588 }
2589
2590 /*returns false if the thread is not attached*/
2591 gboolean
2592 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
2593 {
2594         MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
2595         MONO_ARCH_CONTEXT_DEF
2596
2597         mono_arch_flush_register_windows ();
2598
2599         if (!thread || !thread->jit_data) {
2600                 ctx->valid = FALSE;
2601                 return FALSE;
2602         }
2603 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
2604         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx->ctx);
2605 #else
2606         MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
2607 #endif
2608                 
2609         ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2610         ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2611         ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2612         ctx->valid = TRUE;
2613         return TRUE;
2614 }
2615
2616 static void
2617 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
2618 {
2619         mono_handle_exception (ctx, (MonoObject *)exc);
2620         mono_restore_context (ctx);
2621 }
2622
2623 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
2624 void
2625 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
2626 {
2627 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
2628         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
2629         jit_tls->ex_ctx = *ctx;
2630
2631         mono_arch_setup_async_callback (ctx, async_cb, user_data);
2632 #else
2633         g_error ("This target doesn't support mono_arch_setup_async_callback");
2634 #endif
2635 }
2636
2637 void
2638 mono_install_unhandled_exception_hook (MonoUnhandledExceptionFunc func, gpointer user_data)
2639 {
2640         unhandled_exception_hook = func;
2641         unhandled_exception_hook_data = user_data;
2642 }
2643
2644 void
2645 mono_invoke_unhandled_exception_hook (MonoObject *exc)
2646 {
2647         if (unhandled_exception_hook) {
2648                 unhandled_exception_hook (exc, unhandled_exception_hook_data);
2649         } else {
2650                 MonoObject *other = NULL;
2651                 MonoString *str = mono_object_to_string (exc, &other);
2652                 char *msg = NULL;
2653                 
2654                 if (str)
2655                         msg = mono_string_to_utf8 (str);
2656                 else if (other) {
2657                         char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
2658                         char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other);
2659
2660                         msg = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
2661                                 original_backtrace, nested_backtrace);
2662
2663                         g_free (original_backtrace);
2664                         g_free (nested_backtrace);
2665                 } else {
2666                         msg = g_strdup ("Nested exception trying to figure out what went wrong");
2667                 }
2668                 mono_runtime_printf_err ("[ERROR] FATAL UNHANDLED EXCEPTION: %s", msg);
2669                 g_free (msg);
2670 #if defined(HOST_IOS)
2671                 g_assertion_message ("Terminating runtime due to unhandled exception");
2672 #else
2673                 exit (mono_environment_exitcode_get ());
2674 #endif
2675         }
2676
2677         g_assert_not_reached ();
2678 }
2679
2680 /*
2681  * mono_restore_context:
2682  *
2683  *   Call the architecture specific restore context function.
2684  */
2685 void
2686 mono_restore_context (MonoContext *ctx)
2687 {
2688         static void (*restore_context) (MonoContext *);
2689
2690         if (!restore_context)
2691                 restore_context = (void (*)(MonoContext *))mono_get_restore_context ();
2692         restore_context (ctx);
2693         g_assert_not_reached ();
2694 }
2695
2696 /*
2697  * mono_jinfo_get_unwind_info:
2698  *
2699  *   Return the unwind info for JI.
2700  */
2701 guint8*
2702 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
2703 {
2704         if (ji->from_aot)
2705                 return mono_aot_get_unwind_info (ji, unwind_info_len);
2706         else
2707                 return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
2708 }
2709
2710 int
2711 mono_jinfo_get_epilog_size (MonoJitInfo *ji)
2712 {
2713         MonoArchEHJitInfo *info;
2714
2715         info = mono_jit_info_get_arch_eh_info (ji);
2716         g_assert (info);
2717
2718         return info->epilog_size;
2719 }
2720
2721 /*
2722  * LLVM/Bitcode exception handling.
2723  */
2724
2725 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
2726
2727 #if 0
2728 static gboolean show_native_addresses = TRUE;
2729 #else
2730 static gboolean show_native_addresses = FALSE;
2731 #endif
2732
2733 static _Unwind_Reason_Code
2734 build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
2735 {
2736         MonoDomain *domain = mono_domain_get ();
2737         uintptr_t ip = _Unwind_GetIP (frame_ctx);
2738
2739         if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
2740                 GList **trace_ips = (GList **)state;
2741                 *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
2742         }
2743
2744         return _URC_NO_REASON;
2745 }
2746
2747 #endif
2748
2749 static void
2750 throw_exception (MonoObject *ex, gboolean rethrow)
2751 {
2752         MonoJitTlsData *jit_tls = mono_get_jit_tls ();
2753         MonoException *mono_ex;
2754
2755         if (!mono_object_isinst (ex, mono_defaults.exception_class))
2756                 mono_ex = mono_get_exception_runtime_wrapped (ex);
2757         else
2758                 mono_ex = (MonoException*)ex;
2759
2760         // Note: Not pinned
2761         jit_tls->thrown_exc = mono_gchandle_new ((MonoObject*)mono_ex, FALSE);
2762
2763         if (!rethrow) {
2764 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
2765                 GList *l, *ips = NULL;
2766                 GList *trace;
2767
2768                 _Unwind_Backtrace (build_stack_trace, &ips);
2769                 /* The list contains gshared info-ip pairs */
2770                 trace = NULL;
2771                 ips = g_list_reverse (ips);
2772                 for (l = ips; l; l = l->next) {
2773                         // FIXME:
2774                         trace = g_list_append (trace, l->data);
2775                         trace = g_list_append (trace, NULL);
2776                 }
2777                 MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (trace, mono_defaults.int_class));
2778                 g_list_free (l);
2779                 g_list_free (trace);
2780 #endif
2781         }
2782
2783         mono_llvm_cpp_throw_exception ();
2784 }
2785
2786 void
2787 mono_llvm_throw_exception (MonoObject *ex)
2788 {
2789         throw_exception (ex, FALSE);
2790 }
2791
2792 void
2793 mono_llvm_rethrow_exception (MonoObject *ex)
2794 {
2795         throw_exception (ex, TRUE);
2796 }
2797
2798 void
2799 mono_llvm_raise_exception (MonoException *e)
2800 {
2801         mono_llvm_throw_exception ((MonoObject*)e);
2802 }
2803
2804 void
2805 mono_llvm_throw_corlib_exception (guint32 ex_token_index)
2806 {
2807         guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
2808         MonoException *ex;
2809
2810         ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token);
2811
2812         mono_llvm_throw_exception ((MonoObject*)ex);
2813 }
2814
2815 /*
2816  * mono_llvm_resume_exception:
2817  *
2818  *   Resume exception propagation.
2819  */
2820 void
2821 mono_llvm_resume_exception (void)
2822 {
2823         mono_llvm_cpp_throw_exception ();
2824 }
2825
2826 /*
2827  * mono_llvm_load_exception:
2828  *
2829  *   Return the currently thrown exception.
2830  */
2831 MonoObject *
2832 mono_llvm_load_exception (void)
2833 {
2834         MonoJitTlsData *jit_tls = mono_get_jit_tls ();
2835
2836         MonoException *mono_ex = (MonoException*)mono_gchandle_get_target (jit_tls->thrown_exc);
2837
2838         if (mono_ex->trace_ips) {
2839                 GList *trace_ips = NULL;
2840                 gpointer ip = __builtin_return_address (0);
2841
2842                 size_t upper = mono_array_length (mono_ex->trace_ips);
2843
2844                 for (int i = 0; i < upper; i++) {
2845                         gpointer curr_ip = mono_array_get (mono_ex->trace_ips, gpointer, i);
2846                         trace_ips = g_list_prepend (trace_ips, curr_ip);
2847
2848                         if (ip == curr_ip)
2849                                 break;
2850                 }
2851
2852                 // FIXME: Does this work correctly for rethrows?
2853                 // We may be discarding useful information
2854                 // when this gets GC'ed
2855                 MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (trace_ips, mono_defaults.int_class));
2856                 g_list_free (trace_ips);
2857
2858                 // FIXME:
2859                 //MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
2860         } else {
2861                 MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_array_new (mono_domain_get (), mono_defaults.int_class, 0));
2862                 MONO_OBJECT_SETREF (mono_ex, stack_trace, mono_array_new (mono_domain_get (), mono_defaults.stack_frame_class, 0));
2863         }
2864
2865         return &mono_ex->object;
2866 }
2867
2868 /*
2869  * mono_llvm_clear_exception:
2870  *
2871  *   Mark the currently thrown exception as handled.
2872  */
2873 void
2874 mono_llvm_clear_exception (void)
2875 {
2876         MonoJitTlsData *jit_tls = mono_get_jit_tls ();
2877         mono_gchandle_free (jit_tls->thrown_exc);
2878         jit_tls->thrown_exc = 0;
2879
2880         mono_memory_barrier ();
2881 }
2882
2883 /*
2884  * mono_llvm_match_exception:
2885  *
2886  *   Return the innermost clause containing REGION_START-REGION_END which can handle
2887  * the current exception.
2888  */
2889 gint32
2890 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
2891 {
2892         MonoJitTlsData *jit_tls = mono_get_jit_tls ();
2893         MonoObject *exc;
2894         gint32 index = -1;
2895
2896         g_assert (jit_tls->thrown_exc);
2897         exc = mono_gchandle_get_target (jit_tls->thrown_exc);
2898         for (int i = 0; i < jinfo->num_clauses; i++) {
2899                 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
2900                 MonoClass *catch_class;
2901
2902                 if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
2903                         continue;
2904
2905                 catch_class = ei->data.catch_class;
2906                 if (catch_class->byval_arg.type == MONO_TYPE_VAR || catch_class->byval_arg.type == MONO_TYPE_MVAR || catch_class->byval_arg.type == MONO_TYPE_GENERICINST) {
2907                         MonoGenericContext context;
2908                         MonoType *inflated_type;
2909
2910                         g_assert (rgctx || this_obj);
2911                         context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
2912                         inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
2913                         catch_class = mono_class_from_mono_type (inflated_type);
2914                         mono_metadata_free_type (inflated_type);
2915                 }
2916
2917                 // FIXME: Handle edge cases handled in get_exception_catch_class
2918                 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (exc, catch_class)) {
2919                         index = ei->clause_index;
2920                         break;
2921                 } else if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2922                         g_assert_not_reached ();
2923                 }
2924         }
2925
2926         return index;
2927 }
2928
2929 #ifdef ENABLE_LLVM
2930 _Unwind_Reason_Code 
2931 mono_debug_personality (int a, _Unwind_Action b,
2932 uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
2933 {
2934         g_assert_not_reached ();
2935 }
2936 #else
2937 void
2938 mono_debug_personality (void);
2939
2940 void
2941 mono_debug_personality (void)
2942 {
2943         g_assert_not_reached ();
2944 }
2945 #endif