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