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