[runtime] Fix potential overflow when using mono_msec_ticks
[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         MonoDomain *domain = mono_domain_get ();
1352         MonoJitInfo *ji = NULL;
1353         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1354         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1355         MonoLMF *lmf = mono_get_lmf ();
1356         MonoArray *initial_trace_ips = NULL;
1357         GList *trace_ips = NULL;
1358         GSList *dynamic_methods = NULL;
1359         MonoException *mono_ex;
1360         gboolean stack_overflow = FALSE;
1361         MonoContext initial_ctx;
1362         MonoMethod *method;
1363         int frame_count = 0;
1364         gint32 filter_idx;
1365         int i;
1366         MonoObject *ex_obj;
1367
1368         g_assert (ctx != NULL);
1369
1370         if (obj == (MonoObject *)domain->stack_overflow_ex)
1371                 stack_overflow = TRUE;
1372
1373         mono_ex = (MonoException*)obj;
1374         initial_trace_ips = mono_ex->trace_ips;
1375
1376         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1377                 mono_ex = (MonoException*)obj;
1378                 initial_trace_ips = mono_ex->trace_ips;
1379         } else {
1380                 mono_ex = NULL;
1381         }
1382
1383         if (!call_filter)
1384                 call_filter = (int (*) (MonoContext *, void *))mono_get_call_filter ();
1385
1386         g_assert (jit_tls->end_of_stack);
1387         g_assert (jit_tls->abort_func);
1388
1389         if (out_filter_idx)
1390                 *out_filter_idx = -1;
1391         if (out_ji)
1392                 *out_ji = NULL;
1393         if (out_prev_ji)
1394                 *out_prev_ji = NULL;
1395         filter_idx = 0;
1396         initial_ctx = *ctx;
1397
1398         while (1) {
1399                 MonoContext new_ctx;
1400                 guint32 free_stack;
1401                 int clause_index_start = 0;
1402                 gboolean unwind_res = TRUE;
1403                 
1404                 StackFrameInfo frame;
1405
1406                 if (out_prev_ji)
1407                         *out_prev_ji = ji;
1408
1409                 unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1410                 if (unwind_res) {
1411                         if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
1412                                         frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
1413                                         frame.type == FRAME_TYPE_TRAMPOLINE) {
1414                                 *ctx = new_ctx;
1415                                 continue;
1416                         }
1417                         g_assert (frame.type == FRAME_TYPE_MANAGED);
1418                         ji = frame.ji;
1419                 }
1420
1421                 if (!unwind_res) {
1422                         setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
1423                         g_slist_free (dynamic_methods);
1424                         return FALSE;
1425                 }
1426
1427                 frame_count ++;
1428                 method = jinfo_get_method (ji);
1429                 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
1430
1431                 if (mini_get_debug_options ()->reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
1432                         g_error ("A native frame was found while unwinding the stack after an exception.\n"
1433                                          "The native frame called the managed method:\n%s\n",
1434                                          mono_method_full_name (method, TRUE));
1435                 }
1436
1437                 if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1438                         /* 
1439                          * Avoid overwriting the stack trace if the exception is
1440                          * rethrown. Also avoid giant stack traces during a stack
1441                          * overflow.
1442                          */
1443                         if (!initial_trace_ips && (frame_count < 1000)) {
1444                                 trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1445                                 trace_ips = g_list_prepend (trace_ips,
1446                                                                                         get_generic_info_from_stack_frame (ji, ctx));
1447                         }
1448                 }
1449
1450                 if (method->dynamic)
1451                         dynamic_methods = g_slist_prepend (dynamic_methods, method);
1452
1453                 if (stack_overflow) {
1454                         if (DOES_STACK_GROWS_UP)
1455                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1456                         else
1457                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1458                 } else {
1459                         free_stack = 0xffffff;
1460                 }
1461                                 
1462                 for (i = clause_index_start; i < ji->num_clauses; i++) {
1463                         MonoJitExceptionInfo *ei = &ji->clauses [i];
1464                         gboolean filtered = FALSE;
1465
1466                         /* 
1467                          * During stack overflow, wait till the unwinding frees some stack
1468                          * space before running handlers/finalizers.
1469                          */
1470                         if (free_stack <= (64 * 1024))
1471                                 continue;
1472
1473                         if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1474                                 /* catch block */
1475                                 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1476
1477                                 /*
1478                                  * Have to unwrap RuntimeWrappedExceptions if the
1479                                  * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1480                                  */
1481                                 if (non_exception && !wrap_non_exception_throws (method))
1482                                         ex_obj = non_exception;
1483                                 else
1484                                         ex_obj = obj;
1485
1486                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1487                                         gboolean is_user_frame = method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD;
1488 #ifndef DISABLE_PERFCOUNTERS
1489                                         mono_perfcounters->exceptions_filters++;
1490 #endif
1491                                         /*
1492                                         Here's the thing, if this is a filter clause done by a wrapper like runtime invoke, we don't want to
1493                                         trim the stackframe since if it returns FALSE we lose information.
1494
1495                                         FIXME Not 100% sure if it's a good idea even with user clauses.
1496                                         */
1497                                         if (is_user_frame)
1498                                                 setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
1499
1500 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1501                                         if (ji->from_llvm)
1502                                                 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1503                                         else
1504                                                 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
1505                                                 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1506 #else
1507                                         g_assert (!ji->from_llvm);
1508                                         /* store the exception object in bp + ei->exvar_offset */
1509                                         *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1510 #endif
1511
1512 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
1513                                         /*
1514                                          * Pass the original il clause index to the landing pad so it can
1515                                          * branch to the landing pad associated with the il clause.
1516                                          * This is needed because llvm compiled code assumes that the EH
1517                                          * code always branches to the innermost landing pad.
1518                                          */
1519                                         if (ji->from_llvm)
1520                                                 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
1521 #endif
1522
1523                                         mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx);
1524                                         filtered = call_filter (ctx, ei->data.filter);
1525                                         mono_debugger_agent_end_exception_filter (mono_ex, ctx, &initial_ctx);
1526                                         if (filtered && out_filter_idx)
1527                                                 *out_filter_idx = filter_idx;
1528                                         if (out_ji)
1529                                                 *out_ji = ji;
1530                                         filter_idx ++;
1531
1532                                         if (filtered) {
1533                                                 if (!is_user_frame)
1534                                                         setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
1535                                                 g_slist_free (dynamic_methods);
1536                                                 /* mono_debugger_agent_handle_exception () needs this */
1537                                                 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1538                                                 return TRUE;
1539                                         }
1540                                 }
1541
1542                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (ex_obj, catch_class)) {
1543                                         setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
1544                                         g_slist_free (dynamic_methods);
1545
1546                                         if (out_ji)
1547                                                 *out_ji = ji;
1548
1549                                         /* mono_debugger_agent_handle_exception () needs this */
1550                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1551                                         return TRUE;
1552                                 }
1553                         }
1554                 }
1555
1556                 *ctx = new_ctx;
1557         }
1558
1559         g_assert_not_reached ();
1560 }
1561
1562 /**
1563  * mono_handle_exception_internal:
1564  * @ctx: saved processor state
1565  * @obj: the exception object
1566  * @resume: whenever to resume unwinding based on the state in MonoJitTlsData.
1567  */
1568 static gboolean
1569 mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji)
1570 {
1571         MonoError error;
1572         MonoDomain *domain = mono_domain_get ();
1573         MonoJitInfo *ji, *prev_ji;
1574         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1575         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1576         MonoLMF *lmf = mono_get_lmf ();
1577         MonoException *mono_ex;
1578         gboolean stack_overflow = FALSE;
1579         MonoContext initial_ctx;
1580         MonoMethod *method;
1581         int frame_count = 0;
1582         gint32 filter_idx, first_filter_idx = 0;
1583         int i;
1584         MonoObject *ex_obj;
1585         MonoObject *non_exception = NULL;
1586
1587         g_assert (ctx != NULL);
1588         if (!obj) {
1589                 MonoException *ex = mono_get_exception_null_reference ();
1590                 MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object"));
1591                 obj = (MonoObject *)ex;
1592         } 
1593
1594         /*
1595          * Allocate a new exception object instead of the preconstructed ones.
1596          */
1597         if (obj == (MonoObject *)domain->stack_overflow_ex) {
1598                 /*
1599                  * It is not a good idea to try and put even more pressure on the little stack available.
1600                  * obj = mono_get_exception_stack_overflow ();
1601                  */
1602                 stack_overflow = TRUE;
1603         }
1604         else if (obj == (MonoObject *)domain->null_reference_ex) {
1605                 obj = (MonoObject *)mono_get_exception_null_reference ();
1606         }
1607
1608         if (!mono_object_isinst (obj, mono_defaults.exception_class)) {
1609                 non_exception = obj;
1610                 obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, &error);
1611                 mono_error_assert_ok (&error);
1612         }
1613
1614         mono_ex = (MonoException*)obj;
1615
1616         if (mini_get_debug_options ()->suspend_on_exception) {
1617                 mono_runtime_printf_err ("Exception thrown, suspending...");
1618                 while (1)
1619                         ;
1620         }
1621
1622         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1623                 mono_ex = (MonoException*)obj;
1624         } else {
1625                 mono_ex = NULL;
1626         }
1627
1628         if (mono_ex && jit_tls->class_cast_from) {
1629                 if (!strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) {
1630                         char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1631                         char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1632                         char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
1633                         mono_ex->message = mono_string_new (domain, msg);
1634                         g_free (from_name);
1635                         g_free (to_name);
1636                         g_free (msg);
1637                 }
1638                 if (!strcmp (mono_ex->object.vtable->klass->name, "ArrayTypeMismatchException")) {
1639                         char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1640                         char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1641                         char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
1642                         mono_ex->message = mono_string_new (domain, msg);
1643                         g_free (from_name);
1644                         g_free (to_name);
1645                         g_free (msg);
1646                 }
1647         }
1648
1649         if (!call_filter)
1650                 call_filter = (int (*)(MonoContext *, void*))mono_get_call_filter ();
1651
1652         g_assert (jit_tls->end_of_stack);
1653         g_assert (jit_tls->abort_func);
1654
1655         /*
1656          * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
1657          * end up being TRUE on any code path.
1658          */
1659         memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
1660
1661         if (!resume) {
1662                 gboolean res;
1663
1664                 MonoContext ctx_cp = *ctx;
1665                 if (mono_trace_is_enabled ()) {
1666                         MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0);
1667                         MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message);
1668                         MonoObject *message;
1669                         const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
1670                         char *msg = NULL;
1671                         if (get_message == NULL) {
1672                                 message = NULL;
1673                         } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
1674                                 message = NULL;
1675                                 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
1676                         } else {
1677                                 MonoObject *exc = NULL;
1678                                 message = mono_runtime_try_invoke (get_message, obj, NULL, &exc, &error);
1679                                 g_assert (exc == NULL);
1680                                 mono_error_assert_ok (&error);
1681                         }
1682                         if (msg == NULL) {
1683                                 msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
1684                         }
1685                         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);
1686                         g_free (msg);
1687                         if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
1688                                 mono_print_thread_dump_from_ctx (ctx);
1689                 }
1690                 jit_tls->orig_ex_ctx_set = TRUE;
1691                 mono_profiler_exception_thrown (obj);
1692                 jit_tls->orig_ex_ctx_set = FALSE;
1693
1694                 res = mono_handle_exception_internal_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception);
1695
1696                 if (!res) {
1697                         if (mini_get_debug_options ()->break_on_exc)
1698                                 G_BREAKPOINT ();
1699                         mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL);
1700
1701                         if (mini_get_debug_options ()->suspend_on_unhandled) {
1702                                 mono_runtime_printf_err ("Unhandled exception, suspending...");
1703                                 while (1)
1704                                         ;
1705                         }
1706
1707                         // FIXME: This runs managed code so it might cause another stack overflow when
1708                         // we are handling a stack overflow
1709                         mono_unhandled_exception (obj);
1710                 } else {
1711                         gboolean unhandled = FALSE;
1712
1713                         /*
1714                          * The exceptions caught by the mono_runtime_invoke_checked () calls
1715                          * in the threadpool needs to be treated as unhandled (#669836).
1716                          *
1717                          * FIXME: The check below is hackish, but its hard to distinguish
1718                          * these runtime invoke calls from others in the runtime.
1719                          */
1720                         if (ji && jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
1721                                 if (prev_ji && jinfo_get_method (prev_ji) == mono_defaults.threadpool_perform_wait_callback_method)
1722                                         unhandled = TRUE;
1723                         }
1724
1725                         if (unhandled)
1726                                 mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL);
1727                         else
1728                                 mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, &ctx_cp);
1729                 }
1730         }
1731
1732         if (out_ji)
1733                 *out_ji = NULL;
1734         filter_idx = 0;
1735         initial_ctx = *ctx;
1736
1737         while (1) {
1738                 MonoContext new_ctx;
1739                 guint32 free_stack;
1740                 int clause_index_start = 0;
1741                 gboolean unwind_res = TRUE;
1742                 
1743                 if (resume) {
1744                         resume = FALSE;
1745                         ji = jit_tls->resume_state.ji;
1746                         new_ctx = jit_tls->resume_state.new_ctx;
1747                         clause_index_start = jit_tls->resume_state.clause_index;
1748                         lmf = jit_tls->resume_state.lmf;
1749                         first_filter_idx = jit_tls->resume_state.first_filter_idx;
1750                         filter_idx = jit_tls->resume_state.filter_idx;
1751                 } else {
1752                         StackFrameInfo frame;
1753
1754                         unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1755                         if (unwind_res) {
1756                                 if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
1757                                                 frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
1758                                                 frame.type == FRAME_TYPE_TRAMPOLINE) {
1759                                         *ctx = new_ctx;
1760                                         continue;
1761                                 }
1762                                 g_assert (frame.type == FRAME_TYPE_MANAGED);
1763                                 ji = frame.ji;
1764                         }
1765                 }
1766
1767                 if (!unwind_res) {
1768                         *(mono_get_lmf_addr ()) = lmf;
1769
1770                         jit_tls->abort_func (obj);
1771                         g_assert_not_reached ();
1772                 }
1773
1774                 method = jinfo_get_method (ji);
1775                 frame_count ++;
1776                 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
1777
1778                 if (stack_overflow) {
1779                         if (DOES_STACK_GROWS_UP)
1780                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1781                         else
1782                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1783                 } else {
1784                         free_stack = 0xffffff;
1785                 }
1786                                 
1787                 for (i = clause_index_start; i < ji->num_clauses; i++) {
1788                         MonoJitExceptionInfo *ei = &ji->clauses [i];
1789                         gboolean filtered = FALSE;
1790
1791                         /* 
1792                          * During stack overflow, wait till the unwinding frees some stack
1793                          * space before running handlers/finalizers.
1794                          */
1795                         if (free_stack <= (64 * 1024))
1796                                 continue;
1797
1798                         if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1799                                 /* catch block */
1800                                 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1801
1802                                 /*
1803                                  * Have to unwrap RuntimeWrappedExceptions if the
1804                                  * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1805                                  */
1806                                 if (non_exception && !wrap_non_exception_throws (method))
1807                                         ex_obj = non_exception;
1808                                 else
1809                                         ex_obj = obj;
1810
1811                                 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
1812 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1813                                         MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1814 #else
1815                                         g_assert (!ji->from_llvm);
1816                                         /* store the exception object in bp + ei->exvar_offset */
1817                                         *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1818 #endif
1819                                 }
1820
1821 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
1822                                 if (ji->from_llvm)
1823                                         MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
1824 #endif
1825
1826                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1827                                         /* 
1828                                          * Filter clauses should only be run in the 
1829                                          * first pass of exception handling.
1830                                          */
1831                                         filtered = (filter_idx == first_filter_idx);
1832                                         filter_idx ++;
1833                                 }
1834
1835                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
1836                                          mono_object_isinst (ex_obj, catch_class)) || filtered) {
1837                                         /*
1838                                          * This guards against the situation that we abort a thread that is executing a finally clause
1839                                          * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
1840                                          * check for this situation here and resume interruption if we are below the guarded block.
1841                                          */
1842                                         if (G_UNLIKELY (jit_tls->handler_block_return_address)) {
1843                                                 gboolean is_outside = FALSE;
1844                                                 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
1845                                                 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
1846                                                 //FIXME make this stack direction aware
1847                                                 if (catch_bp > prot_bp) {
1848                                                         is_outside = TRUE;
1849                                                 } else if (catch_bp == prot_bp) {
1850                                                         /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
1851                                                          * So we check if the catch handler_start is protected by the guarded handler protected region
1852                                                          *
1853                                                          * Assumptions:
1854                                                          *      If there is an outstanding guarded_block return address, it means the current thread must be aborted.
1855                                                          *      This is the only way to reach out the guarded block as other cases are handled by the trampoline.
1856                                                          *      There aren't any further finally/fault handler blocks down the stack over this exception.
1857                                                          *   This must be ensured by the code that installs the guard trampoline.
1858                                                          */
1859                                                         g_assert (ji == mini_jit_info_table_find (domain, (char *)MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
1860
1861                                                         if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
1862                                                                 is_outside = TRUE;
1863                                                         }
1864                                                 }
1865                                                 if (is_outside) {
1866                                                         jit_tls->handler_block_return_address = NULL;
1867                                                         jit_tls->handler_block = NULL;
1868                                                         mono_thread_resume_interruption (); /*We ignore the exception here, it will be raised later*/
1869                                                 }
1870                                         }
1871
1872                                         if (mono_trace_is_enabled () && mono_trace_eval (method))
1873                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE));
1874                                         jit_tls->orig_ex_ctx_set = TRUE;
1875                                         mono_profiler_exception_clause_handler (method, ei->flags, i);
1876                                         jit_tls->orig_ex_ctx_set = FALSE;
1877                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1878                                         mono_set_lmf (lmf);
1879 #ifndef DISABLE_PERFCOUNTERS
1880                                         mono_perfcounters->exceptions_depth += frame_count;
1881 #endif
1882                                         if (obj == (MonoObject *)domain->stack_overflow_ex)
1883                                                 jit_tls->handling_stack_ovf = FALSE;
1884
1885                                         return 0;
1886                                 }
1887                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
1888                                         if (mono_trace_is_enabled () && mono_trace_eval (method))
1889                                                 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
1890                                         jit_tls->orig_ex_ctx_set = TRUE;
1891                                         mono_profiler_exception_clause_handler (method, ei->flags, i);
1892                                         jit_tls->orig_ex_ctx_set = FALSE;
1893                                         call_filter (ctx, ei->handler_start);
1894                                 }
1895                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
1896                                         if (mono_trace_is_enabled () && mono_trace_eval (method))
1897                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
1898                                         jit_tls->orig_ex_ctx_set = TRUE;
1899                                         mono_profiler_exception_clause_handler (method, ei->flags, i);
1900                                         jit_tls->orig_ex_ctx_set = FALSE;
1901 #ifndef DISABLE_PERFCOUNTERS
1902                                         mono_perfcounters->exceptions_finallys++;
1903 #endif
1904                                         mono_set_lmf (lmf);
1905                                         if (ji->from_llvm) {
1906                                                 /* 
1907                                                  * LLVM compiled finally handlers follow the design
1908                                                  * of the c++ ehabi, i.e. they call a resume function
1909                                                  * at the end instead of returning to the caller.
1910                                                  * So save the exception handling state,
1911                                                  * mono_resume_unwind () will call us again to continue
1912                                                  * the unwinding.
1913                                                  */
1914                                                 jit_tls->resume_state.ex_obj = obj;
1915                                                 jit_tls->resume_state.ji = ji;
1916                                                 jit_tls->resume_state.clause_index = i + 1;
1917                                                 jit_tls->resume_state.ctx = *ctx;
1918                                                 jit_tls->resume_state.new_ctx = new_ctx;
1919                                                 jit_tls->resume_state.lmf = lmf;
1920                                                 jit_tls->resume_state.first_filter_idx = first_filter_idx;
1921                                                 jit_tls->resume_state.filter_idx = filter_idx;
1922                                                 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1923                                                 return 0;
1924                                         } else {
1925                                                 call_filter (ctx, ei->handler_start);
1926                                         }
1927                                 }
1928                         }
1929                 }
1930
1931                 jit_tls->orig_ex_ctx_set = TRUE;
1932                 mono_profiler_exception_method_leave (method);
1933                 jit_tls->orig_ex_ctx_set = FALSE;
1934
1935                 *ctx = new_ctx;
1936         }
1937
1938         g_assert_not_reached ();
1939 }
1940
1941 /**
1942  * mono_debugger_run_finally:
1943  * @start_ctx: saved processor state
1944  *
1945  * This method is called by the Mono Debugger to call all `finally' clauses of the
1946  * current stack frame.  It's used when the user issues a `return' command to make
1947  * the current stack frame return.  After returning from this method, the debugger
1948  * unwinds the stack one frame and gives control back to the user.
1949  *
1950  * NOTE: This method is only used when running inside the Mono Debugger.
1951  */
1952 void
1953 mono_debugger_run_finally (MonoContext *start_ctx)
1954 {
1955         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1956         MonoDomain *domain = mono_domain_get ();
1957         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1958         MonoLMF *lmf = mono_get_lmf ();
1959         MonoContext ctx, new_ctx;
1960         MonoJitInfo *ji, rji;
1961         int i;
1962
1963         ctx = *start_ctx;
1964
1965         ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1966         if (!ji || ji == (gpointer)-1)
1967                 return;
1968
1969         if (!call_filter)
1970                 call_filter = (int (*)(MonoContext *, void *))mono_get_call_filter ();
1971
1972         for (i = 0; i < ji->num_clauses; i++) {
1973                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1974
1975                 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
1976                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1977                         call_filter (&ctx, ei->handler_start);
1978                 }
1979         }
1980 }
1981
1982 /**
1983  * mono_handle_exception:
1984  * @ctx: saved processor state
1985  * @obj: the exception object
1986  */
1987 gboolean
1988 mono_handle_exception (MonoContext *ctx, MonoObject *obj)
1989 {
1990 #ifndef DISABLE_PERFCOUNTERS
1991         mono_perfcounters->exceptions_thrown++;
1992 #endif
1993
1994         return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
1995 }
1996
1997 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1998
1999 #ifndef MONO_ARCH_USE_SIGACTION
2000 #error "Can't use sigaltstack without sigaction"
2001 #endif
2002
2003 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
2004
2005 void
2006 mono_setup_altstack (MonoJitTlsData *tls)
2007 {
2008         size_t stsize = 0;
2009         stack_t sa;
2010         guint8 *staddr = NULL;
2011
2012         if (mono_running_on_valgrind ())
2013                 return;
2014
2015         mono_thread_info_get_stack_bounds (&staddr, &stsize);
2016
2017         g_assert (staddr);
2018
2019         tls->end_of_stack = staddr + stsize;
2020         tls->stack_size = stsize;
2021
2022         /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
2023
2024         tls->stack_ovf_guard_base = staddr + mono_pagesize ();
2025         tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
2026
2027         g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
2028
2029         if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
2030                 /* mprotect can fail for the main thread stack */
2031                 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);
2032                 g_assert (gaddr == tls->stack_ovf_guard_base);
2033                 tls->stack_ovf_valloced = TRUE;
2034         }
2035
2036         /* Setup an alternate signal stack */
2037         tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
2038         tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
2039
2040         g_assert (tls->signal_stack);
2041
2042         sa.ss_sp = tls->signal_stack;
2043         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
2044         sa.ss_flags = 0;
2045         g_assert (sigaltstack (&sa, NULL) == 0);
2046
2047         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);
2048 }
2049
2050 void
2051 mono_free_altstack (MonoJitTlsData *tls)
2052 {
2053         stack_t sa;
2054         int err;
2055
2056         sa.ss_sp = tls->signal_stack;
2057         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
2058         sa.ss_flags = SS_DISABLE;
2059         err = sigaltstack  (&sa, NULL);
2060         g_assert (err == 0);
2061
2062         if (tls->signal_stack)
2063                 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
2064         if (tls->stack_ovf_valloced)
2065                 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size);
2066         else
2067                 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
2068 }
2069
2070 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
2071
2072 void
2073 mono_setup_altstack (MonoJitTlsData *tls)
2074 {
2075 }
2076
2077 void
2078 mono_free_altstack (MonoJitTlsData *tls)
2079 {
2080 }
2081
2082 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
2083
2084 static gboolean
2085 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
2086 {
2087         gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
2088         /* we need to leave some room for throwing the exception */
2089         while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
2090                 unprotect_size -= mono_pagesize ();
2091         /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
2092          * is sufficient stack
2093          */
2094         //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);
2095         if (unprotect_size)
2096                 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
2097         return unprotect_size == jit_tls->stack_ovf_guard_size;
2098 }
2099
2100 static G_GNUC_UNUSED void
2101 try_more_restore (void)
2102 {
2103         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
2104         if (try_restore_stack_protection (jit_tls, 500))
2105                 jit_tls->restore_stack_prot = NULL;
2106 }
2107
2108 static G_GNUC_UNUSED void
2109 restore_stack_protection (void)
2110 {
2111         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
2112         MonoException *ex = mono_domain_get ()->stack_overflow_ex;
2113         /* if we can't restore the stack protection, keep a callback installed so
2114          * we'll try to restore as much stack as we can at each return from unmanaged
2115          * code.
2116          */
2117         if (try_restore_stack_protection (jit_tls, 4096))
2118                 jit_tls->restore_stack_prot = NULL;
2119         else
2120                 jit_tls->restore_stack_prot = try_more_restore_tramp;
2121         /* here we also throw a stack overflow exception */
2122         ex->trace_ips = NULL;
2123         ex->stack_trace = NULL;
2124         mono_raise_exception (ex);
2125 }
2126
2127 gpointer
2128 mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
2129 {
2130         void (*func)(void) = (void (*)(void))tramp_data;
2131         func ();
2132         return NULL;
2133 }
2134
2135 gboolean
2136 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
2137 {
2138         if (mono_llvm_only)
2139                 return FALSE;
2140
2141         /* we got a stack overflow in the soft-guard pages
2142          * There are two cases:
2143          * 1) managed code caused the overflow: we unprotect the soft-guard page
2144          * and let the arch-specific code trigger the exception handling mechanism
2145          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
2146          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
2147          * and hope we can continue with those enabled, at least until the hard-guard page
2148          * is hit. The alternative to continuing here is to just print a message and abort.
2149          * We may add in the future the code to protect the pages again in the codepath
2150          * when we return from unmanaged to managed code.
2151          */
2152         if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
2153                         fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
2154                 /* we unprotect the minimum amount we can */
2155                 guint32 guard_size;
2156                 gboolean handled = FALSE;
2157
2158                 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
2159                 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
2160                         guard_size -= mono_pagesize ();
2161                 }
2162                 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
2163                 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
2164                 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);
2165 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2166                 if (ji) {
2167                         mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE);
2168                         handled = TRUE;
2169                 }
2170 #endif
2171                 if (!handled) {
2172                         /* We print a message: after this even managed stack overflows
2173                          * may crash the runtime
2174                          */
2175                         mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
2176                         if (!jit_tls->handling_stack_ovf) {
2177                                 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
2178                                 jit_tls->handling_stack_ovf = 1;
2179                         } else {
2180                                 /*fprintf (stderr, "Already handling stack overflow\n");*/
2181                         }
2182                 }
2183                 return TRUE;
2184         }
2185         return FALSE;
2186 }
2187
2188 typedef struct {
2189         MonoMethod *omethod;
2190         int count;
2191 } PrintOverflowUserData;
2192
2193 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2194 static gboolean
2195 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2196 {
2197         MonoMethod *method = NULL;
2198         PrintOverflowUserData *user_data = (PrintOverflowUserData *)data;
2199         gchar *location;
2200
2201         if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2202                 method = jinfo_get_method (frame->ji);
2203
2204         if (method) {
2205                 if (user_data->count == 0) {
2206                         /* The first frame is in its prolog, so a line number cannot be computed */
2207                         user_data->count ++;
2208                         return FALSE;
2209                 }
2210
2211                 /* If this is a one method overflow, skip the other instances */
2212                 if (method == user_data->omethod)
2213                         return FALSE;
2214
2215                 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2216                 mono_runtime_printf_err ("  %s", location);
2217                 g_free (location);
2218
2219                 if (user_data->count == 1) {
2220                         mono_runtime_printf_err ("  <...>");
2221                         user_data->omethod = method;
2222                 } else {
2223                         user_data->omethod = NULL;
2224                 }
2225
2226                 user_data->count ++;
2227         } else
2228                 mono_runtime_printf_err ("  at <unknown> <0x%05x>", frame->native_offset);
2229
2230         return FALSE;
2231 }
2232 #endif
2233
2234 void
2235 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
2236 {
2237 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2238         PrintOverflowUserData ud;
2239         MonoContext mctx;
2240 #endif
2241
2242         /* we don't do much now, but we can warn the user with a useful message */
2243         mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
2244
2245 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2246         mono_sigctx_to_monoctx (ctx, &mctx);
2247                         
2248         mono_runtime_printf_err ("Stacktrace:");
2249
2250         memset (&ud, 0, sizeof (ud));
2251
2252         mono_walk_stack_with_ctx (print_overflow_stack_frame, &mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
2253 #else
2254         if (ji && !ji->is_trampoline && jinfo_get_method (ji))
2255                 mono_runtime_printf_err ("At %s", mono_method_full_name (jinfo_get_method (ji), TRUE));
2256         else
2257                 mono_runtime_printf_err ("At <unmanaged>.");
2258 #endif
2259
2260         _exit (1);
2261 }
2262
2263 static gboolean
2264 print_stack_frame_to_stderr (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2265 {
2266         MonoMethod *method = NULL;
2267
2268         if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2269                 method = jinfo_get_method (frame->ji);
2270
2271         if (method) {
2272                 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2273                 mono_runtime_printf_err ("  %s", location);
2274                 g_free (location);
2275         } else
2276                 mono_runtime_printf_err ("  at <unknown> <0x%05x>", frame->native_offset);
2277
2278         return FALSE;
2279 }
2280
2281 static G_GNUC_UNUSED gboolean
2282 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2283 {
2284         GString *p = (GString*)data;
2285         MonoMethod *method = NULL;
2286
2287         if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2288                 method = jinfo_get_method (frame->ji);
2289
2290         if (method && frame->domain) {
2291                 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
2292                 g_string_append_printf (p, "  %s\n", location);
2293                 g_free (location);
2294         } else
2295                 g_string_append_printf (p, "  at <unknown> <0x%05x>\n", frame->native_offset);
2296
2297         return FALSE;
2298 }
2299
2300 #ifndef MONO_CROSS_COMPILE
2301
2302 static gboolean handling_sigsegv = FALSE;
2303
2304 /*
2305  * mono_handle_native_sigsegv:
2306  *
2307  *   Handle a SIGSEGV received while in native code by printing diagnostic 
2308  * information and aborting.
2309  */
2310 void
2311 mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
2312 {
2313 #ifdef MONO_ARCH_USE_SIGACTION
2314         struct sigaction sa;
2315 #endif
2316         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
2317         const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
2318
2319         if (handling_sigsegv)
2320                 return;
2321
2322         if (mini_get_debug_options ()->suspend_on_sigsegv) {
2323                 mono_runtime_printf_err ("Received SIGSEGV, suspending...");
2324 #ifdef HOST_WIN32
2325                 while (1)
2326                         ;
2327 #else
2328                 while (1) {
2329                         sleep (1);
2330                 }
2331 #endif
2332         }
2333
2334         /* To prevent infinite loops when the stack walk causes a crash */
2335         handling_sigsegv = TRUE;
2336
2337         /* !jit_tls means the thread was not registered with the runtime */
2338         if (jit_tls && mono_thread_internal_current ()) {
2339                 mono_runtime_printf_err ("Stacktrace:\n");
2340
2341                 /* FIXME: Is MONO_UNWIND_LOOKUP_IL_OFFSET correct here? */
2342                 mono_walk_stack (print_stack_frame_to_stderr, MONO_UNWIND_LOOKUP_IL_OFFSET, NULL);
2343         }
2344
2345 #ifdef HAVE_BACKTRACE_SYMBOLS
2346  {
2347         void *array [256];
2348         char **names;
2349         int i, size;
2350
2351         mono_runtime_printf_err ("\nNative stacktrace:\n");
2352
2353         size = backtrace (array, 256);
2354         names = backtrace_symbols (array, size);
2355         for (i =0; i < size; ++i) {
2356                 mono_runtime_printf_err ("\t%s", names [i]);
2357         }
2358         free (names);
2359
2360         /* Try to get more meaningful information using gdb */
2361
2362 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
2363         if (!mini_get_debug_options ()->no_gdb_backtrace) {
2364                 /* From g_spawn_command_line_sync () in eglib */
2365                 pid_t pid;
2366                 int status;
2367                 pid_t crashed_pid = getpid ();
2368
2369                 //pid = fork ();
2370                 /*
2371                  * glibc fork acquires some locks, so if the crash happened inside malloc/free,
2372                  * it will deadlock. Call the syscall directly instead.
2373                  */
2374                 pid = mono_runtime_syscall_fork ();
2375 #if defined (HAVE_PRCTL) && defined(PR_SET_PTRACER)
2376                 if (pid > 0) {
2377                         // Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to
2378                         // a value other than 0 (the most permissive ptrace scope). Most modern Linux
2379                         // distributions set the scope to 1 which allows attaching only to direct children of
2380                         // the current process
2381                         prctl (PR_SET_PTRACER, pid, 0, 0, 0);
2382                 }
2383 #endif
2384                 if (pid == 0) {
2385                         dup2 (STDERR_FILENO, STDOUT_FILENO);
2386
2387                         mono_gdb_render_native_backtraces (crashed_pid);
2388                         exit (1);
2389                 }
2390
2391                 mono_runtime_printf_err ("\nDebug info from gdb:\n");
2392                 waitpid (pid, &status, 0);
2393         }
2394 #endif
2395  }
2396 #elif defined (ENABLE_EXTENSION_MODULE)
2397         mono_extension_handle_native_sigsegv (ctx, info);
2398 #endif
2399
2400         /*
2401          * A SIGSEGV indicates something went very wrong so we can no longer depend
2402          * on anything working. So try to print out lots of diagnostics, starting 
2403          * with ones which have a greater chance of working.
2404          */
2405         mono_runtime_printf_err (
2406                          "\n"
2407                          "=================================================================\n"
2408                          "Got a %s while executing native code. This usually indicates\n"
2409                          "a fatal error in the mono runtime or one of the native libraries \n"
2410                          "used by your application.\n"
2411                          "=================================================================\n",
2412                         signal_str);
2413
2414
2415 #ifdef MONO_ARCH_USE_SIGACTION
2416
2417         /* Remove our SIGABRT handler */
2418         sa.sa_handler = SIG_DFL;
2419         sigemptyset (&sa.sa_mask);
2420         sa.sa_flags = 0;
2421
2422         g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
2423
2424 #endif
2425
2426         if (!mono_do_crash_chaining) {
2427                 /*Android abort is a fluke, it doesn't abort, it triggers another segv. */
2428 #if defined (PLATFORM_ANDROID)
2429                 exit (-1);
2430 #else
2431                 abort ();
2432 #endif
2433         }
2434 }
2435
2436 #else
2437
2438 void
2439 mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
2440 {
2441         g_assert_not_reached ();
2442 }
2443
2444 #endif /* !MONO_CROSS_COMPILE */
2445
2446 static void
2447 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
2448 {
2449         MonoInternalThread *thread = mono_thread_internal_current ();
2450 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2451         MonoContext ctx;
2452 #endif
2453         GString* text;
2454         char *name;
2455 #ifndef HOST_WIN32
2456         char *wapi_desc;
2457 #endif
2458         GError *error = NULL;
2459
2460         if (!thread)
2461                 return;
2462
2463         text = g_string_new (0);
2464         if (thread->name) {
2465                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
2466                 g_assert (!error);
2467                 g_string_append_printf (text, "\n\"%s\"", name);
2468                 g_free (name);
2469         }
2470         else if (thread->threadpool_thread)
2471                 g_string_append (text, "\n\"<threadpool thread>\"");
2472         else
2473                 g_string_append (text, "\n\"<unnamed thread>\"");
2474
2475 #ifndef HOST_WIN32
2476         wapi_desc = wapi_current_thread_desc ();
2477         g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread,  wapi_desc);
2478         free (wapi_desc);
2479 #endif
2480
2481 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2482         if (start_ctx) {
2483                 memcpy (&ctx, start_ctx, sizeof (MonoContext));
2484         } else if (!sigctx)
2485                 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
2486         else
2487                 mono_sigctx_to_monoctx (sigctx, &ctx);
2488
2489         mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
2490 #else
2491         mono_runtime_printf ("\t<Stack traces in thread dumps not supported on this platform>");
2492 #endif
2493
2494         mono_runtime_printf ("%s", text->str);
2495
2496 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
2497         OutputDebugStringA(text->str);
2498 #endif
2499
2500         g_string_free (text, TRUE);
2501         mono_runtime_stdout_fflush ();
2502 }
2503
2504 /*
2505  * mono_print_thread_dump:
2506  *
2507  *   Print information about the current thread to stdout.
2508  * SIGCTX can be NULL, allowing this to be called from gdb.
2509  */
2510 void
2511 mono_print_thread_dump (void *sigctx)
2512 {
2513         mono_print_thread_dump_internal (sigctx, NULL);
2514 }
2515
2516 void
2517 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2518 {
2519         mono_print_thread_dump_internal (NULL, ctx);
2520 }
2521
2522 /*
2523  * mono_resume_unwind:
2524  *
2525  *   This is called by a trampoline from LLVM compiled finally clauses to continue
2526  * unwinding.
2527  */
2528 void
2529 mono_resume_unwind (MonoContext *ctx)
2530 {
2531         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
2532         MonoContext new_ctx;
2533
2534         MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
2535         MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
2536         new_ctx = *ctx;
2537
2538         mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL);
2539
2540         mono_restore_context (&new_ctx);
2541 }
2542
2543 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
2544
2545 typedef struct {
2546         MonoJitInfo *ji;
2547         MonoContext ctx;
2548         MonoJitExceptionInfo *ei;
2549 } FindHandlerBlockData;
2550
2551 static gboolean
2552 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2553 {
2554         int i;
2555         gpointer ip;
2556         FindHandlerBlockData *pdata = (FindHandlerBlockData *)data;
2557         MonoJitInfo *ji = frame->ji;
2558
2559         if (!ji)
2560                 return FALSE;
2561
2562         ip = MONO_CONTEXT_GET_IP (ctx);
2563
2564         for (i = 0; i < ji->num_clauses; ++i) {
2565                 MonoJitExceptionInfo *ei = ji->clauses + i;
2566                 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2567                         continue;
2568                 /*If ip points to the first instruction it means the handler block didn't start
2569                  so we can leave its execution to the EH machinery*/
2570                 if (ei->handler_start < ip && ip < ei->data.handler_end) {
2571                         pdata->ji = ji;
2572                         pdata->ei = ei;
2573                         pdata->ctx = *ctx;
2574                         break;
2575                 }
2576         }
2577         return FALSE;
2578 }
2579
2580
2581 static gpointer
2582 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
2583 {
2584         int i;
2585         MonoJitExceptionInfo *clause = NULL;
2586         gpointer ip;
2587
2588         ip = MONO_CONTEXT_GET_IP (ctx);
2589
2590         for (i = 0; i < ji->num_clauses; ++i) {
2591                 clause = &ji->clauses [i];
2592                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2593                         continue;
2594                 if (clause->handler_start < ip && clause->data.handler_end > ip)
2595                         break;
2596         }
2597
2598         /*no matching finally */
2599         if (i == ji->num_clauses)
2600                 return NULL;
2601
2602         /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
2603         if (ip == clause->handler_start)
2604                 return NULL;
2605
2606         return mono_arch_install_handler_block_guard (ji, clause, ctx, mono_create_handler_block_trampoline ());
2607 }
2608
2609 /*
2610  * Finds the bottom handler block running and install a block guard if needed.
2611  * FIXME add full-aot support.
2612  */
2613 gboolean
2614 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
2615 {
2616         FindHandlerBlockData data = { 0 };
2617         MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
2618         gpointer resume_ip;
2619
2620         /* FIXME */
2621         if (mono_aot_only)
2622                 return FALSE;
2623
2624         /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
2625          * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
2626          */
2627         if (!jit_tls || jit_tls->handler_block_return_address)
2628                 return FALSE;
2629
2630         /* Do an async safe stack walk */
2631         mono_thread_info_set_is_async_context (TRUE);
2632         mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data);
2633         mono_thread_info_set_is_async_context (FALSE);
2634
2635         if (!data.ji)
2636                 return FALSE;
2637
2638         memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
2639
2640         resume_ip = install_handler_block_guard (data.ji, &data.ctx);
2641         if (resume_ip == NULL)
2642                 return FALSE;
2643
2644         jit_tls->handler_block_return_address = resume_ip;
2645         jit_tls->handler_block = data.ei;
2646
2647         return TRUE;
2648 }
2649
2650 #else
2651 gboolean
2652 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
2653 {
2654         return FALSE;
2655 }
2656
2657 #endif
2658
2659 void
2660 mono_set_cast_details (MonoClass *from, MonoClass *to)
2661 {
2662         MonoJitTlsData *jit_tls = NULL;
2663
2664         if (mini_get_debug_options ()->better_cast_details) {
2665                 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
2666                 jit_tls->class_cast_from = from;
2667                 jit_tls->class_cast_to = to;
2668         }
2669 }
2670
2671
2672 /*returns false if the thread is not attached*/
2673 gboolean
2674 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
2675 {
2676 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2677         MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
2678         if (!thread) {
2679                 ctx->valid = FALSE;
2680                 G_BREAKPOINT ();
2681                 return FALSE;
2682         }
2683
2684         if (sigctx) {
2685                 mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
2686
2687                 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2688                 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2689                 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2690         }
2691         else {
2692                 mono_thread_state_init (ctx);
2693         }
2694
2695         if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
2696                 return FALSE;
2697
2698         ctx->valid = TRUE;
2699         return TRUE;
2700 #else
2701         g_error ("Implement mono_arch_sigctx_to_monoctx for the current target");
2702         return FALSE;
2703 #endif
2704 }
2705
2706 void
2707 mono_thread_state_init (MonoThreadUnwindState *ctx)
2708 {
2709         MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
2710
2711 #if defined(MONO_CROSS_COMPILE)
2712         ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
2713 #elif MONO_ARCH_HAS_MONO_CONTEXT
2714         MONO_CONTEXT_GET_CURRENT (ctx->ctx);
2715 #else
2716         g_error ("Use a null sigctx requires a working mono-context");
2717 #endif
2718
2719         ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2720         ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2721         ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
2722         ctx->valid = TRUE;
2723 }
2724
2725
2726 gboolean
2727 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
2728 {
2729         MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
2730         if (!thread) {
2731                 ctx->valid = FALSE;
2732                 return FALSE;
2733         }
2734
2735         ctx->ctx = *mctx;
2736         ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2737         ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2738         ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2739         ctx->valid = TRUE;
2740         return TRUE;
2741 }
2742
2743 /*returns false if the thread is not attached*/
2744 gboolean
2745 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
2746 {
2747         MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
2748         MONO_ARCH_CONTEXT_DEF
2749
2750         mono_arch_flush_register_windows ();
2751
2752         if (!thread || !thread->jit_data) {
2753                 ctx->valid = FALSE;
2754                 return FALSE;
2755         }
2756 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
2757         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx->ctx);
2758 #else
2759         MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
2760 #endif
2761                 
2762         ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
2763         ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
2764         ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
2765         ctx->valid = TRUE;
2766         return TRUE;
2767 }
2768
2769 static void
2770 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
2771 {
2772         mono_handle_exception (ctx, (MonoObject *)exc);
2773         mono_restore_context (ctx);
2774 }
2775
2776 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
2777 void
2778 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
2779 {
2780 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
2781         MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
2782         jit_tls->ex_ctx = *ctx;
2783
2784         mono_arch_setup_async_callback (ctx, async_cb, user_data);
2785 #else
2786         g_error ("This target doesn't support mono_arch_setup_async_callback");
2787 #endif
2788 }
2789
2790 void
2791 mono_install_unhandled_exception_hook (MonoUnhandledExceptionFunc func, gpointer user_data)
2792 {
2793         unhandled_exception_hook = func;
2794         unhandled_exception_hook_data = user_data;
2795 }
2796
2797 void
2798 mono_invoke_unhandled_exception_hook (MonoObject *exc)
2799 {
2800         if (unhandled_exception_hook) {
2801                 unhandled_exception_hook (exc, unhandled_exception_hook_data);
2802         } else {
2803                 MonoObject *other = NULL;
2804                 MonoString *str = mono_object_to_string (exc, &other);
2805                 char *msg = NULL;
2806                 
2807                 if (str)
2808                         msg = mono_string_to_utf8 (str);
2809                 else if (other) {
2810                         char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
2811                         char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other);
2812
2813                         msg = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
2814                                 original_backtrace, nested_backtrace);
2815
2816                         g_free (original_backtrace);
2817                         g_free (nested_backtrace);
2818                 } else {
2819                         msg = g_strdup ("Nested exception trying to figure out what went wrong");
2820                 }
2821                 mono_runtime_printf_err ("[ERROR] FATAL UNHANDLED EXCEPTION: %s", msg);
2822                 g_free (msg);
2823 #if defined(HOST_IOS)
2824                 g_assertion_message ("Terminating runtime due to unhandled exception");
2825 #else
2826                 exit (mono_environment_exitcode_get ());
2827 #endif
2828         }
2829
2830         g_assert_not_reached ();
2831 }
2832
2833 /*
2834  * mono_restore_context:
2835  *
2836  *   Call the architecture specific restore context function.
2837  */
2838 void
2839 mono_restore_context (MonoContext *ctx)
2840 {
2841         static void (*restore_context) (MonoContext *);
2842
2843         if (!restore_context)
2844                 restore_context = (void (*)(MonoContext *))mono_get_restore_context ();
2845         restore_context (ctx);
2846         g_assert_not_reached ();
2847 }
2848
2849 /*
2850  * mono_jinfo_get_unwind_info:
2851  *
2852  *   Return the unwind info for JI.
2853  */
2854 guint8*
2855 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
2856 {
2857         if (ji->from_aot)
2858                 return mono_aot_get_unwind_info (ji, unwind_info_len);
2859         else
2860                 return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
2861 }
2862
2863 int
2864 mono_jinfo_get_epilog_size (MonoJitInfo *ji)
2865 {
2866         MonoArchEHJitInfo *info;
2867
2868         info = mono_jit_info_get_arch_eh_info (ji);
2869         g_assert (info);
2870
2871         return info->epilog_size;
2872 }
2873
2874 /*
2875  * LLVM/Bitcode exception handling.
2876  */
2877
2878 static void
2879 throw_exception (MonoObject *ex, gboolean rethrow)
2880 {
2881         MonoError error;
2882         MonoJitTlsData *jit_tls = mono_get_jit_tls ();
2883         MonoException *mono_ex;
2884
2885         if (!mono_object_isinst (ex, mono_defaults.exception_class)) {
2886                 mono_ex = mono_get_exception_runtime_wrapped_checked (ex, &error);
2887                 mono_error_assert_ok (&error);
2888         }
2889         else
2890                 mono_ex = (MonoException*)ex;
2891
2892         // Note: Not pinned
2893         jit_tls->thrown_exc = mono_gchandle_new ((MonoObject*)mono_ex, FALSE);
2894
2895         if (!rethrow) {
2896 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
2897                 GList *l, *ips = NULL;
2898                 GList *trace;
2899
2900                 _Unwind_Backtrace (build_stack_trace, &ips);
2901                 /* The list contains ip-gshared info pairs */
2902                 trace = NULL;
2903                 ips = g_list_reverse (ips);
2904                 for (l = ips; l; l = l->next) {
2905                         trace = g_list_append (trace, l->data);
2906                         trace = g_list_append (trace, NULL);
2907                 }
2908                 MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (trace, mono_defaults.int_class));
2909                 g_list_free (l);
2910                 g_list_free (trace);
2911 #endif
2912         }
2913
2914         mono_llvm_cpp_throw_exception ();
2915 }
2916
2917 void
2918 mono_llvm_throw_exception (MonoObject *ex)
2919 {
2920         throw_exception (ex, FALSE);
2921 }
2922
2923 void
2924 mono_llvm_rethrow_exception (MonoObject *ex)
2925 {
2926         throw_exception (ex, TRUE);
2927 }
2928
2929 void
2930 mono_llvm_raise_exception (MonoException *e)
2931 {
2932         mono_llvm_throw_exception ((MonoObject*)e);
2933 }
2934
2935 void
2936 mono_llvm_throw_corlib_exception (guint32 ex_token_index)
2937 {
2938         guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
2939         MonoException *ex;
2940
2941         ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token);
2942
2943         mono_llvm_throw_exception ((MonoObject*)ex);
2944 }
2945
2946 /*
2947  * mono_llvm_resume_exception:
2948  *
2949  *   Resume exception propagation.
2950  */
2951 void
2952 mono_llvm_resume_exception (void)
2953 {
2954         mono_llvm_cpp_throw_exception ();
2955 }
2956
2957 /*
2958  * mono_llvm_load_exception:
2959  *
2960  *   Return the currently thrown exception.
2961  */
2962 MonoObject *
2963 mono_llvm_load_exception (void)
2964 {
2965         MonoJitTlsData *jit_tls = mono_get_jit_tls ();
2966
2967         MonoException *mono_ex = (MonoException*)mono_gchandle_get_target (jit_tls->thrown_exc);
2968
2969         if (mono_ex->trace_ips) {
2970                 GList *trace_ips = NULL;
2971                 gpointer ip = __builtin_return_address (0);
2972
2973                 size_t upper = mono_array_length (mono_ex->trace_ips);
2974
2975                 for (int i = 0; i < upper; i+= 2) {
2976                         gpointer curr_ip = mono_array_get (mono_ex->trace_ips, gpointer, i);
2977                         gpointer curr_info = mono_array_get (mono_ex->trace_ips, gpointer, i + 1);
2978                         trace_ips = g_list_append (trace_ips, curr_ip);
2979                         trace_ips = g_list_append (trace_ips, curr_info);
2980
2981                         if (ip == curr_ip)
2982                                 break;
2983                 }
2984
2985                 // FIXME: Does this work correctly for rethrows?
2986                 // We may be discarding useful information
2987                 // when this gets GC'ed
2988                 MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (trace_ips, mono_defaults.int_class));
2989                 g_list_free (trace_ips);
2990
2991                 // FIXME:
2992                 //MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
2993         } else {
2994                 MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_array_new (mono_domain_get (), mono_defaults.int_class, 0));
2995                 MONO_OBJECT_SETREF (mono_ex, stack_trace, mono_array_new (mono_domain_get (), mono_defaults.stack_frame_class, 0));
2996         }
2997
2998         return &mono_ex->object;
2999 }
3000
3001 /*
3002  * mono_llvm_clear_exception:
3003  *
3004  *   Mark the currently thrown exception as handled.
3005  */
3006 void
3007 mono_llvm_clear_exception (void)
3008 {
3009         MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3010         mono_gchandle_free (jit_tls->thrown_exc);
3011         jit_tls->thrown_exc = 0;
3012
3013         mono_memory_barrier ();
3014 }
3015
3016 /*
3017  * mono_llvm_match_exception:
3018  *
3019  *   Return the innermost clause containing REGION_START-REGION_END which can handle
3020  * the current exception.
3021  */
3022 gint32
3023 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
3024 {
3025         MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3026         MonoObject *exc;
3027         gint32 index = -1;
3028
3029         g_assert (jit_tls->thrown_exc);
3030         exc = mono_gchandle_get_target (jit_tls->thrown_exc);
3031         for (int i = 0; i < jinfo->num_clauses; i++) {
3032                 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
3033                 MonoClass *catch_class;
3034
3035                 if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
3036                         continue;
3037
3038                 catch_class = ei->data.catch_class;
3039                 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) {
3040                         MonoError error;
3041                         MonoGenericContext context;
3042                         MonoType *inflated_type;
3043
3044                         g_assert (rgctx || this_obj);
3045                         context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
3046                         inflated_type = mono_class_inflate_generic_type_checked (&catch_class->byval_arg, &context, &error);
3047                         mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3048
3049                         catch_class = mono_class_from_mono_type (inflated_type);
3050                         mono_metadata_free_type (inflated_type);
3051                 }
3052
3053                 // FIXME: Handle edge cases handled in get_exception_catch_class
3054                 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (exc, catch_class)) {
3055                         index = ei->clause_index;
3056                         break;
3057                 } else if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3058                         g_assert_not_reached ();
3059                 }
3060         }
3061
3062         return index;
3063 }
3064
3065 #ifdef ENABLE_LLVM
3066 _Unwind_Reason_Code 
3067 mono_debug_personality (int a, _Unwind_Action b,
3068 uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
3069 {
3070         g_assert_not_reached ();
3071 }
3072 #else
3073 void
3074 mono_debug_personality (void);
3075
3076 void
3077 mono_debug_personality (void)
3078 {
3079         g_assert_not_reached ();
3080 }
3081 #endif