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