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