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