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