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