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