2010-07-08 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-exceptions.c
1 /*
2  * mini-exceptions.c: generic exception support
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Mono Team (mono-list@lists.ximian.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc.
9  * Copyright 2003-2008 Ximian, Inc.
10  */
11
12 #include <config.h>
13 #include <glib.h>
14 #include <signal.h>
15 #include <string.h>
16
17 #ifdef HAVE_EXECINFO_H
18 #include <execinfo.h>
19 #endif
20
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
23 #endif
24
25 #ifdef HAVE_SYS_WAIT_H
26 #include <sys/wait.h>
27 #endif
28
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
33 #ifdef HAVE_SYS_SYSCALL_H
34 #include <sys/syscall.h>
35 #endif
36
37 #include <mono/metadata/appdomain.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/threads-types.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include <mono/metadata/exception.h>
43 #include <mono/metadata/gc-internal.h>
44 #include <mono/metadata/mono-debug.h>
45 #include <mono/metadata/profiler.h>
46 #include <mono/utils/mono-mmap.h>
47
48 #include "mini.h"
49 #include "debug-mini.h"
50 #include "trace.h"
51 #include "debugger-agent.h"
52
53 #ifndef MONO_ARCH_CONTEXT_DEF
54 #define MONO_ARCH_CONTEXT_DEF
55 #endif
56
57 static gpointer restore_context_func, call_filter_func;
58 static gpointer throw_exception_func, rethrow_exception_func;
59 static gpointer throw_corlib_exception_func;
60
61 static gpointer try_more_restore_tramp = NULL;
62 static gpointer restore_stack_protection_tramp = NULL;
63
64 static void try_more_restore (void);
65 static void restore_stack_protection (void);
66 static void mono_walk_stack_full (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gboolean use_new_ctx, gpointer user_data);
67
68 void
69 mono_exceptions_init (void)
70 {
71         if (mono_aot_only) {
72                 restore_context_func = mono_aot_get_trampoline ("restore_context");
73                 call_filter_func = mono_aot_get_trampoline ("call_filter");
74                 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
75                 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
76         } else {
77                 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 (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1272                                 /* 
1273                                  * Avoid overwriting the stack trace if the exception is
1274                                  * rethrown. Also avoid giant stack traces during a stack
1275                                  * overflow.
1276                                  */
1277                                 if (!initial_trace_ips && (frame_count < 1000)) {
1278                                         trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1279                                         trace_ips = g_list_prepend (trace_ips,
1280                                                 get_generic_info_from_stack_frame (ji, ctx));
1281                                 }
1282                         }
1283
1284                         if (ji->method->dynamic)
1285                                 has_dynamic_methods = TRUE;
1286
1287                         if (stack_overflow)
1288 #ifndef MONO_ARCH_STACK_GROWS_UP
1289                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1290 #else
1291                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1292 #endif
1293                         else
1294                                 free_stack = 0xffffff;
1295
1296                         /* 
1297                          * During stack overflow, wait till the unwinding frees some stack
1298                          * space before running handlers/finalizers.
1299                          */
1300                         if ((free_stack > (64 * 1024)) && ji->num_clauses) {
1301                                 int i;
1302                                 
1303                                 for (i = clause_index_start; i < ji->num_clauses; i++) {
1304                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
1305                                         gboolean filtered = FALSE;
1306
1307 #if defined(__s390__)
1308                                         /* 
1309                                          * This is required in cases where a try block starts immediately after
1310                                          * a call which causes an exception. Testcase: tests/exception8.cs.
1311                                          * FIXME: Clean this up.
1312                                          */
1313                                         if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) && MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
1314 #else
1315                                         if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1316 #endif
1317                                                 /* catch block */
1318                                                 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1319
1320                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
1321                                                         if (ji->from_llvm) {
1322 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1323                                                                 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, obj);
1324 #else
1325                                                                 g_assert_not_reached ();
1326 #endif
1327                                                         } else {
1328                                                                 /* store the exception object in bp + ei->exvar_offset */
1329                                                                 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
1330                                                         }
1331                                                 }
1332
1333                                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1334                                                         if (test_only) {
1335                                                                 mono_perfcounters->exceptions_filters++;
1336                                                                 mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
1337                                                                 filtered = call_filter (ctx, ei->data.filter);
1338                                                                 if (filtered && out_filter_idx)
1339                                                                         *out_filter_idx = filter_idx;
1340                                                                 if (out_ji)
1341                                                                         *out_ji = ji;
1342                                                         }
1343                                                         else {
1344                                                                 /* 
1345                                                                  * Filter clauses should only be run in the 
1346                                                                  * first pass of exception handling.
1347                                                                  */
1348                                                                 filtered = (filter_idx == first_filter_idx);
1349                                                         }
1350                                                         filter_idx ++;
1351                                                 }
1352
1353                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
1354                                                      mono_object_isinst (obj, catch_class)) || filtered) {
1355                                                         if (test_only) {
1356                                                                 if (mono_ex && !initial_trace_ips) {
1357                                                                         trace_ips = g_list_reverse (trace_ips);
1358                                                                         MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1359                                                                         if (has_dynamic_methods)
1360                                                                                 /* These methods could go away anytime, so compute the stack trace now */
1361                                                                                 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1362                                                                 }
1363                                                                 g_list_free (trace_ips);
1364
1365                                                                 return TRUE;
1366                                                         }
1367                                                         /*
1368                                                          * This guards against the situation that we abort a thread that is executing a finally clause
1369                                                          * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
1370                                                          * check for this situation here and resume interruption if we are below the guarded block.
1371                                                          */
1372                                                         if (G_UNLIKELY (jit_tls->handler_block_return_address)) {
1373                                                                 gboolean is_outside = FALSE;
1374                                                                 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->ex_ctx);
1375                                                                 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
1376                                                                 //FIXME make this stack direction aware
1377                                                                 if (catch_bp > prot_bp) {
1378                                                                         is_outside = TRUE;
1379                                                                 } else if (catch_bp == prot_bp) {
1380                                                                         /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
1381                                                                          * So we check if the catch handler_start is protected by the guarded handler protected region
1382                                                                          *
1383                                                                          * Assumptions:
1384                                                                          *      If there is an outstanding guarded_block return address, it means the current thread must be aborted.
1385                                                                          *      This is the only way to reach out the guarded block as other cases are handled by the trampoline.
1386                                                                          *      There aren't any further finally/fault handler blocks down the stack over this exception.
1387                                                                          *   This must be ensured by the code that installs the guard trampoline.
1388                                                                          */
1389                                                                         g_assert (ji == mini_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (&jit_tls->ex_ctx), NULL));
1390
1391                                                                         if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
1392                                                                                 is_outside = TRUE;
1393                                                                         }
1394                                                                 }
1395                                                                 if (is_outside) {
1396                                                                         jit_tls->handler_block_return_address = NULL;
1397                                                                         jit_tls->handler_block = NULL;
1398                                                                         mono_thread_resume_interruption (); /*We ignore the exception here, it will be raised later*/
1399                                                                 }
1400                                                         }
1401
1402                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1403                                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1404                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1405                                                         mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1406                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1407                                                         *(mono_get_lmf_addr ()) = lmf;
1408                                                         mono_perfcounters->exceptions_depth += frame_count;
1409                                                         if (obj == domain->stack_overflow_ex)
1410                                                                 jit_tls->handling_stack_ovf = FALSE;
1411
1412                                                         return 0;
1413                                                 }
1414                                                 if (!test_only && is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1415                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
1416                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1417                                                                 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1418                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1419                                                         mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1420                                                         call_filter (ctx, ei->handler_start);
1421                                                 }
1422                                                 if (!test_only && is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1423                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
1424                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1425                                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1426                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1427                                                         mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1428                                                         mono_perfcounters->exceptions_finallys++;
1429                                                         *(mono_get_lmf_addr ()) = lmf;
1430                                                         if (ji->from_llvm) {
1431                                                                 /* 
1432                                                                  * LLVM compiled finally handlers follow the design
1433                                                                  * of the c++ ehabi, i.e. they call a resume function
1434                                                                  * at the end instead of returning to the caller.
1435                                                                  * So save the exception handling state,
1436                                                                  * mono_resume_unwind () will call us again to continue
1437                                                                  * the unwinding.
1438                                                                  */
1439                                                                 jit_tls->resume_state.ex_obj = obj;
1440                                                                 jit_tls->resume_state.ji = ji;
1441                                                                 jit_tls->resume_state.clause_index = i + 1;
1442                                                                 jit_tls->resume_state.ctx = *ctx;
1443                                                                 jit_tls->resume_state.new_ctx = new_ctx;
1444                                                                 jit_tls->resume_state.lmf = lmf;
1445                                                                 jit_tls->resume_state.first_filter_idx = first_filter_idx;
1446                                                                 jit_tls->resume_state.filter_idx = filter_idx;
1447                                                                 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1448                                                                 return 0;
1449                                                         } else {
1450                                                                 call_filter (ctx, ei->handler_start);
1451                                                         }
1452                                                 }
1453                                                 
1454                                         }
1455                                 }
1456                         }
1457                         if (!test_only)
1458                                 mono_profiler_exception_method_leave (ji->method);
1459                 }
1460
1461                 *ctx = new_ctx;
1462
1463                 if (ji == (gpointer)-1) {
1464
1465                         if (!test_only) {
1466                                 *(mono_get_lmf_addr ()) = lmf;
1467
1468                                 jit_tls->abort_func (obj);
1469                                 g_assert_not_reached ();
1470                         } else {
1471                                 if (mono_ex && !initial_trace_ips) {
1472                                         trace_ips = g_list_reverse (trace_ips);
1473                                         MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1474                                         if (has_dynamic_methods)
1475                                                 /* These methods could go away anytime, so compute the stack trace now */
1476                                                 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1477                                 }
1478                                 g_list_free (trace_ips);
1479                                 return FALSE;
1480                         }
1481                 }
1482         }
1483
1484         g_assert_not_reached ();
1485 }
1486
1487 /*
1488  * mono_debugger_handle_exception:
1489  *
1490  *  Notify the debugger about exceptions.  Returns TRUE if the debugger wants us to stop
1491  *  at the exception and FALSE to resume with the normal exception handling.
1492  *
1493  *  The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
1494  *  MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
1495  *  `callq throw' instruction.
1496  */
1497 gboolean
1498 mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
1499 {
1500         MonoDebuggerExceptionAction action;
1501
1502         if (!mono_debug_using_mono_debugger ())
1503                 return FALSE;
1504
1505         if (!obj) {
1506                 MonoException *ex = mono_get_exception_null_reference ();
1507                 MONO_OBJECT_SETREF (ex, message, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
1508                 obj = (MonoObject *)ex;
1509         }
1510
1511         action = _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1512
1513         if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP) {
1514                 /*
1515                  * The debugger wants us to stop on the `throw' instruction.
1516                  * By the time we get here, it already inserted a breakpoint there.
1517                  */
1518                 return TRUE;
1519         } else if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED) {
1520                 MonoContext ctx_cp = *ctx;
1521                 MonoJitInfo *ji = NULL;
1522                 gboolean ret;
1523
1524                 /*
1525                  * The debugger wants us to stop only if this exception is user-unhandled.
1526                  */
1527
1528                 ret = mono_handle_exception_internal (&ctx_cp, obj, MONO_CONTEXT_GET_IP (ctx), TRUE, FALSE, NULL, &ji);
1529                 if (ret && (ji != NULL) && (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
1530                         /*
1531                          * The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
1532                          * inside the method being invoked, so we handle it like a user-unhandled exception.
1533                          */
1534                         ret = FALSE;
1535                 }
1536
1537                 if (!ret) {
1538                         /*
1539                          * The exception is user-unhandled - tell the debugger to stop.
1540                          */
1541                         return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1542                 }
1543
1544                 /*
1545                  * The exception is catched somewhere - resume with the normal exception handling and don't
1546                  * stop in the debugger.
1547                  */
1548         }
1549
1550         return FALSE;
1551 }
1552
1553 /**
1554  * mono_debugger_run_finally:
1555  * @start_ctx: saved processor state
1556  *
1557  * This method is called by the Mono Debugger to call all `finally' clauses of the
1558  * current stack frame.  It's used when the user issues a `return' command to make
1559  * the current stack frame return.  After returning from this method, the debugger
1560  * unwinds the stack one frame and gives control back to the user.
1561  *
1562  * NOTE: This method is only used when running inside the Mono Debugger.
1563  */
1564 void
1565 mono_debugger_run_finally (MonoContext *start_ctx)
1566 {
1567         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1568         MonoDomain *domain = mono_domain_get ();
1569         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1570         MonoLMF *lmf = mono_get_lmf ();
1571         MonoContext ctx, new_ctx;
1572         MonoJitInfo *ji, rji;
1573         int i;
1574
1575         ctx = *start_ctx;
1576
1577         ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1578         if (!ji || ji == (gpointer)-1)
1579                 return;
1580
1581         if (!call_filter)
1582                 call_filter = mono_get_call_filter ();
1583
1584         for (i = 0; i < ji->num_clauses; i++) {
1585                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1586
1587                 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
1588                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1589                         call_filter (&ctx, ei->handler_start);
1590                 }
1591         }
1592 }
1593
1594 /**
1595  * mono_handle_exception:
1596  * @ctx: saved processor state
1597  * @obj: the exception object
1598  * @test_only: only test if the exception is caught, but dont call handlers
1599  */
1600 gboolean
1601 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
1602 {
1603         if (!test_only)
1604                 mono_perfcounters->exceptions_thrown++;
1605
1606         return mono_handle_exception_internal (ctx, obj, original_ip, test_only, FALSE, NULL, NULL);
1607 }
1608
1609 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1610
1611 #ifndef MONO_ARCH_USE_SIGACTION
1612 #error "Can't use sigaltstack without sigaction"
1613 #endif
1614
1615 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1616
1617 void
1618 mono_setup_altstack (MonoJitTlsData *tls)
1619 {
1620         size_t stsize = 0;
1621         struct sigaltstack sa;
1622         guint8 *staddr = NULL;
1623
1624         if (mono_running_on_valgrind ())
1625                 return;
1626
1627         mono_thread_get_stack_bounds (&staddr, &stsize);
1628
1629         g_assert (staddr);
1630
1631         tls->end_of_stack = staddr + stsize;
1632
1633         /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1634
1635         tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1636         tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
1637
1638         if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1639                 /* mprotect can fail for the main thread stack */
1640                 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);
1641                 g_assert (gaddr == tls->stack_ovf_guard_base);
1642                 tls->stack_ovf_valloced = TRUE;
1643         }
1644
1645         /*
1646          * threads created by nptl does not seem to have a guard page, and
1647          * since the main thread is not created by us, we can't even set one.
1648          * Increasing stsize fools the SIGSEGV signal handler into thinking this
1649          * is a stack overflow exception.
1650          */
1651         tls->stack_size = stsize + mono_pagesize ();
1652
1653         /* Setup an alternate signal stack */
1654         tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
1655         tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1656
1657         g_assert (tls->signal_stack);
1658
1659         sa.ss_sp = tls->signal_stack;
1660         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1661         sa.ss_flags = SS_ONSTACK;
1662         sigaltstack (&sa, NULL);
1663 }
1664
1665 void
1666 mono_free_altstack (MonoJitTlsData *tls)
1667 {
1668         struct sigaltstack sa;
1669         int err;
1670
1671         sa.ss_sp = tls->signal_stack;
1672         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1673         sa.ss_flags = SS_DISABLE;
1674         err = sigaltstack  (&sa, NULL);
1675         g_assert (err == 0);
1676
1677         if (tls->signal_stack)
1678                 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1679         if (tls->stack_ovf_valloced)
1680                 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size);
1681         else
1682                 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1683 }
1684
1685 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1686
1687 void
1688 mono_setup_altstack (MonoJitTlsData *tls)
1689 {
1690 }
1691
1692 void
1693 mono_free_altstack (MonoJitTlsData *tls)
1694 {
1695 }
1696
1697 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1698
1699 static gboolean
1700 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
1701 {
1702         gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
1703         /* we need to leave some room for throwing the exception */
1704         while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
1705                 unprotect_size -= mono_pagesize ();
1706         /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1707          * is sufficient stack
1708          */
1709         //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);
1710         if (unprotect_size)
1711                 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
1712         return unprotect_size == jit_tls->stack_ovf_guard_size;
1713 }
1714
1715 static void
1716 try_more_restore (void)
1717 {
1718         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1719         if (try_restore_stack_protection (jit_tls, 500))
1720                 jit_tls->restore_stack_prot = NULL;
1721 }
1722
1723 static void
1724 restore_stack_protection (void)
1725 {
1726         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1727         MonoException *ex = mono_domain_get ()->stack_overflow_ex;
1728         /* if we can't restore the stack protection, keep a callback installed so
1729          * we'll try to restore as much stack as we can at each return from unmanaged
1730          * code.
1731          */
1732         if (try_restore_stack_protection (jit_tls, 4096))
1733                 jit_tls->restore_stack_prot = NULL;
1734         else
1735                 jit_tls->restore_stack_prot = try_more_restore_tramp;
1736         /* here we also throw a stack overflow exception */
1737         ex->trace_ips = NULL;
1738         ex->stack_trace = NULL;
1739         mono_raise_exception (ex);
1740 }
1741
1742 gpointer
1743 mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
1744 {
1745         void (*func)(void) = (gpointer)tramp_data;
1746         func ();
1747         return NULL;
1748 }
1749
1750 gboolean
1751 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
1752 {
1753         /* we got a stack overflow in the soft-guard pages
1754          * There are two cases:
1755          * 1) managed code caused the overflow: we unprotect the soft-guard page
1756          * and let the arch-specific code trigger the exception handling mechanism
1757          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1758          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1759          * and hope we can continue with those enabled, at least until the hard-guard page
1760          * is hit. The alternative to continuing here is to just print a message and abort.
1761          * We may add in the future the code to protect the pages again in the codepath
1762          * when we return from unmanaged to managed code.
1763          */
1764         if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
1765                         fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
1766                 /* we unprotect the minimum amount we can */
1767                 guint32 guard_size;
1768                 gboolean handled = FALSE;
1769
1770                 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
1771                 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
1772                         guard_size -= mono_pagesize ();
1773                 }
1774                 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
1775                 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
1776                 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);
1777 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1778                 if (ji) {
1779                         mono_arch_handle_altstack_exception (ctx, fault_addr, TRUE);
1780                         handled = TRUE;
1781                 }
1782 #endif
1783                 if (!handled) {
1784                         /* We print a message: after this even managed stack overflows
1785                          * may crash the runtime
1786                          */
1787                         fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), fault_addr);
1788                         if (!jit_tls->handling_stack_ovf) {
1789                                 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
1790                                 jit_tls->handling_stack_ovf = 1;
1791                         } else {
1792                                 /*fprintf (stderr, "Already handling stack overflow\n");*/
1793                         }
1794                 }
1795                 return TRUE;
1796         }
1797         return FALSE;
1798 }
1799
1800 static gboolean
1801 print_stack_frame (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed, gpointer data)
1802 {
1803         FILE *stream = (FILE*)data;
1804
1805         if (method) {
1806                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1807                 fprintf (stream, "  %s\n", location);
1808                 g_free (location);
1809         } else
1810                 fprintf (stream, "  at <unknown> <0x%05x>\n", native_offset);
1811
1812         return FALSE;
1813 }
1814
1815 static G_GNUC_UNUSED gboolean
1816 print_stack_frame_to_string (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed,
1817                              gpointer data)
1818 {
1819         GString *p = (GString*)data;
1820
1821         if (method) {
1822                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1823                 g_string_append_printf (p, "  %s\n", location);
1824                 g_free (location);
1825         } else
1826                 g_string_append_printf (p, "  at <unknown> <0x%05x>\n", native_offset);
1827
1828         return FALSE;
1829 }
1830
1831 static gboolean handling_sigsegv = FALSE;
1832
1833 /*
1834  * mono_handle_native_sigsegv:
1835  *
1836  *   Handle a SIGSEGV received while in native code by printing diagnostic 
1837  * information and aborting.
1838  */
1839 void
1840 mono_handle_native_sigsegv (int signal, void *ctx)
1841 {
1842 #ifdef MONO_ARCH_USE_SIGACTION
1843         struct sigaction sa;
1844 #endif
1845         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1846
1847         if (handling_sigsegv)
1848                 return;
1849
1850         if (mini_get_debug_options ()->suspend_on_sigsegv) {
1851                 fprintf (stderr, "Received SIGSEGV, suspending...");
1852                 while (1)
1853                         ;
1854         }
1855
1856         /* To prevent infinite loops when the stack walk causes a crash */
1857         handling_sigsegv = TRUE;
1858
1859         /* !jit_tls means the thread was not registered with the runtime */
1860         if (jit_tls && mono_thread_internal_current ()) {
1861                 fprintf (stderr, "Stacktrace:\n\n");
1862
1863                 mono_jit_walk_stack (print_stack_frame, TRUE, stderr);
1864
1865                 fflush (stderr);
1866         }
1867
1868 #ifdef HAVE_BACKTRACE_SYMBOLS
1869  {
1870         void *array [256];
1871         char **names;
1872         int i, size;
1873         const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
1874
1875         fprintf (stderr, "\nNative stacktrace:\n\n");
1876
1877         size = backtrace (array, 256);
1878         names = backtrace_symbols (array, size);
1879         for (i =0; i < size; ++i) {
1880                 fprintf (stderr, "\t%s\n", names [i]);
1881         }
1882         free (names);
1883
1884         fflush (stderr);
1885
1886         /* Try to get more meaningful information using gdb */
1887
1888 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
1889         if (!mini_get_debug_options ()->no_gdb_backtrace && !mono_debug_using_mono_debugger ()) {
1890                 /* From g_spawn_command_line_sync () in eglib */
1891                 int res;
1892                 int stdout_pipe [2] = { -1, -1 };
1893                 pid_t pid;
1894                 int status;
1895                 char buffer [1024];
1896
1897                 res = pipe (stdout_pipe);
1898                 g_assert (res != -1);
1899                         
1900                 //pid = fork ();
1901                 /*
1902                  * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1903                  * it will deadlock. Call the syscall directly instead.
1904                  */
1905                 pid = mono_runtime_syscall_fork ();
1906
1907                 if (pid == 0) {
1908                         close (stdout_pipe [0]);
1909                         dup2 (stdout_pipe [1], STDOUT_FILENO);
1910
1911                         for (i = getdtablesize () - 1; i >= 3; i--)
1912                                 close (i);
1913
1914                         if (!mono_gdb_render_native_backtraces ())
1915                                 close (STDOUT_FILENO);
1916
1917                         exit (1);
1918                 }
1919
1920                 close (stdout_pipe [1]);
1921
1922                 fprintf (stderr, "\nDebug info from gdb:\n\n");
1923
1924                 while (1) {
1925                         int nread = read (stdout_pipe [0], buffer, 1024);
1926
1927                         if (nread <= 0)
1928                                 break;
1929                         write (STDERR_FILENO, buffer, nread);
1930                 }               
1931
1932                 waitpid (pid, &status, WNOHANG);
1933         }
1934 #endif
1935         /*
1936          * A SIGSEGV indicates something went very wrong so we can no longer depend
1937          * on anything working. So try to print out lots of diagnostics, starting 
1938          * with ones which have a greater chance of working.
1939          */
1940         fprintf (stderr,
1941                          "\n"
1942                          "=================================================================\n"
1943                          "Got a %s while executing native code. This usually indicates\n"
1944                          "a fatal error in the mono runtime or one of the native libraries \n"
1945                          "used by your application.\n"
1946                          "=================================================================\n"
1947                          "\n", signal_str);
1948
1949  }
1950 #endif
1951
1952 #ifdef MONO_ARCH_USE_SIGACTION
1953
1954         /* Remove our SIGABRT handler */
1955         sa.sa_handler = SIG_DFL;
1956         sigemptyset (&sa.sa_mask);
1957         sa.sa_flags = 0;
1958
1959         g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
1960
1961 #endif
1962
1963         abort ();
1964 }
1965
1966 static void
1967 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
1968 {
1969         MonoInternalThread *thread = mono_thread_internal_current ();
1970 #if defined(__i386__) || defined(__x86_64__)
1971         MonoContext ctx;
1972 #endif
1973         GString* text = g_string_new (0);
1974         char *name, *wapi_desc;
1975         GError *error = NULL;
1976
1977         if (thread->name) {
1978                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
1979                 g_assert (!error);
1980                 g_string_append_printf (text, "\n\"%s\"", name);
1981                 g_free (name);
1982         }
1983         else if (thread->threadpool_thread)
1984                 g_string_append (text, "\n\"<threadpool thread>\"");
1985         else
1986                 g_string_append (text, "\n\"<unnamed thread>\"");
1987
1988 #ifndef HOST_WIN32
1989         wapi_desc = wapi_current_thread_desc ();
1990         g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread,  wapi_desc);
1991         free (wapi_desc);
1992 #endif
1993
1994 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
1995         if (start_ctx) {
1996                 memcpy (&ctx, start_ctx, sizeof (MonoContext));
1997         } else if (!sigctx)
1998                 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
1999         else
2000                 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
2001
2002         mono_jit_walk_stack_from_ctx (print_stack_frame_to_string, &ctx, TRUE, text);
2003 #else
2004         printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
2005 #endif
2006
2007         fprintf (stdout, "%s", text->str);
2008         g_string_free (text, TRUE);
2009         fflush (stdout);
2010 }
2011
2012 /*
2013  * mono_print_thread_dump:
2014  *
2015  *   Print information about the current thread to stdout.
2016  * SIGCTX can be NULL, allowing this to be called from gdb.
2017  */
2018 void
2019 mono_print_thread_dump (void *sigctx)
2020 {
2021         mono_print_thread_dump_internal (sigctx, NULL);
2022 }
2023
2024 void
2025 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2026 {
2027         mono_print_thread_dump_internal (NULL, ctx);
2028 }
2029
2030 /*
2031  * mono_resume_unwind:
2032  *
2033  *   This is called by a trampoline from LLVM compiled finally clauses to continue
2034  * unwinding.
2035  */
2036 void
2037 mono_resume_unwind (MonoContext *ctx)
2038 {
2039         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2040         static void (*restore_context) (MonoContext *);
2041         MonoContext new_ctx;
2042
2043         MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
2044         MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
2045         new_ctx = *ctx;
2046
2047         mono_handle_exception_internal (&new_ctx, jit_tls->resume_state.ex_obj, NULL, FALSE, TRUE, NULL, NULL);
2048
2049         if (!restore_context)
2050                 restore_context = mono_get_restore_context ();
2051
2052         restore_context (&new_ctx);
2053 }
2054
2055 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
2056
2057 typedef struct {
2058         MonoJitInfo *ji;
2059         MonoContext ctx;
2060         MonoJitExceptionInfo *ei;
2061 } FindHandlerBlockData;
2062
2063 static gboolean
2064 find_last_handler_block (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
2065 {
2066         int i;
2067         gpointer ip;
2068         FindHandlerBlockData *pdata = data;
2069
2070         if (ji->method->wrapper_type)
2071                 return FALSE;
2072
2073         ip = MONO_CONTEXT_GET_IP (ctx);
2074
2075         for (i = 0; i < ji->num_clauses; ++i) {
2076                 MonoJitExceptionInfo *ei = ji->clauses + i;
2077                 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2078                         continue;
2079                 /*If ip points to the first instruction it means the handler block didn't start
2080                  so we can leave its execution to the EH machinery*/
2081                 if (ei->handler_start < ip && ip < ei->data.handler_end) {
2082                         pdata->ji = ji;
2083                         pdata->ei = ei;
2084                         pdata->ctx = *ctx;
2085                         break;
2086                 }
2087         }
2088         return FALSE;
2089 }
2090
2091
2092 static gpointer
2093 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
2094 {
2095         int i;
2096         MonoJitExceptionInfo *clause = NULL;
2097         gpointer ip;
2098
2099         ip = MONO_CONTEXT_GET_IP (ctx);
2100
2101         for (i = 0; i < ji->num_clauses; ++i) {
2102                 clause = &ji->clauses [i];
2103                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2104                         continue;
2105                 if (clause->handler_start < ip && clause->data.handler_end > ip)
2106                         break;
2107         }
2108
2109         /*no matching finally */
2110         if (i == ji->num_clauses)
2111                 return NULL;
2112
2113         /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
2114         if (ip == clause->handler_start)
2115                 return NULL;
2116
2117         return mono_arch_install_handler_block_guard (ji, clause, ctx, mono_create_handler_block_trampoline ());
2118 }
2119
2120 /*
2121  * Finds the bottom handler block running and install a block guard if needed.
2122  */
2123 gboolean
2124 mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx)
2125 {
2126         FindHandlerBlockData data = { 0 };
2127         MonoDomain *domain = mono_domain_get ();
2128         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2129         gpointer resume_ip;
2130
2131         if (jit_tls->handler_block_return_address)
2132                 return FALSE;
2133
2134         mono_walk_stack_full (domain, jit_tls, ctx, find_last_handler_block, FALSE, &data);
2135
2136         if (!data.ji)
2137                 return FALSE;
2138
2139         memcpy (&jit_tls->ex_ctx, &data.ctx, sizeof (MonoContext));
2140
2141         resume_ip = install_handler_block_guard (data.ji, &data.ctx);
2142         if (resume_ip == NULL)
2143                 return FALSE;
2144
2145         jit_tls->handler_block_return_address = resume_ip;
2146         jit_tls->handler_block = data.ei;
2147
2148 #ifndef HOST_WIN32
2149         /*Clear current thread from been wapi interrupted otherwise things can go south*/
2150         wapi_clear_interruption ();
2151 #endif
2152         return TRUE;
2153 }
2154
2155 #else
2156 gboolean
2157 mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx)
2158 {
2159         return FALSE;
2160 }
2161
2162 #endif
2163