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