2009-04-11 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
52 #ifndef MONO_ARCH_CONTEXT_DEF
53 #define MONO_ARCH_CONTEXT_DEF
54 #endif
55
56 static gpointer restore_context_func, call_filter_func;
57 static gpointer throw_exception_func, rethrow_exception_func;
58 static gpointer throw_exception_by_name_func, throw_corlib_exception_func;
59
60 static gpointer try_more_restore_tramp = NULL;
61 static gpointer restore_stack_protection_tramp = NULL;
62
63 static void try_more_restore (void);
64 static void restore_stack_protection (void);
65
66 void
67 mono_exceptions_init (void)
68 {
69 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
70         guint32 code_size;
71         MonoJumpInfo *ji;
72
73         if (mono_aot_only) {
74                 restore_context_func = mono_aot_get_named_code ("restore_context");
75                 call_filter_func = mono_aot_get_named_code ("call_filter");
76                 throw_exception_func = mono_aot_get_named_code ("throw_exception");
77                 rethrow_exception_func = mono_aot_get_named_code ("rethrow_exception");
78         } else {
79                 restore_context_func = mono_arch_get_restore_context_full (&code_size, &ji, FALSE);
80                 call_filter_func = mono_arch_get_call_filter_full (&code_size, &ji, FALSE);
81                 throw_exception_func = mono_arch_get_throw_exception_full (&code_size, &ji, FALSE);
82                 rethrow_exception_func = mono_arch_get_rethrow_exception_full (&code_size, &ji, FALSE);
83         }
84 #else
85         restore_context_func = mono_arch_get_restore_context ();
86         call_filter_func = mono_arch_get_call_filter ();
87         throw_exception_func = mono_arch_get_throw_exception ();
88         rethrow_exception_func = mono_arch_get_rethrow_exception ();
89 #endif
90 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
91         try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
92         restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
93 #endif
94
95 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
96         mono_arch_exceptions_init ();
97 #endif
98 }
99
100 gpointer
101 mono_get_throw_exception (void)
102 {
103         g_assert (throw_exception_func);
104         return throw_exception_func;
105 }
106
107 gpointer
108 mono_get_rethrow_exception (void)
109 {
110         g_assert (rethrow_exception_func);
111         return rethrow_exception_func;
112 }
113
114 gpointer
115 mono_get_call_filter (void)
116 {
117         g_assert (call_filter_func);
118         return call_filter_func;
119 }
120
121 gpointer
122 mono_get_restore_context (void)
123 {
124         g_assert (restore_context_func);
125         return restore_context_func;
126 }
127
128 gpointer
129 mono_get_throw_exception_by_name (void)
130 {
131         gpointer code = NULL;
132 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
133         guint32 code_size;
134         MonoJumpInfo *ji;
135 #endif
136
137         /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
138         if (throw_exception_by_name_func)
139                 return throw_exception_by_name_func;
140
141 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
142         if (mono_aot_only)
143                 code = mono_aot_get_named_code ("throw_exception_by_name");
144         else
145                 code = mono_arch_get_throw_exception_by_name_full (&code_size, &ji, FALSE);
146 #else
147                 code = mono_arch_get_throw_exception_by_name ();
148 #endif
149
150         mono_memory_barrier ();
151
152         throw_exception_by_name_func = code;
153
154         return throw_exception_by_name_func;
155 }
156
157 gpointer
158 mono_get_throw_corlib_exception (void)
159 {
160         gpointer code = NULL;
161 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
162         guint32 code_size;
163         MonoJumpInfo *ji;
164 #endif
165
166         /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
167         if (throw_corlib_exception_func)
168                 return throw_corlib_exception_func;
169
170 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
171 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
172         if (mono_aot_only)
173                 code = mono_aot_get_named_code ("throw_corlib_exception");
174         else
175                 code = mono_arch_get_throw_corlib_exception_full (&code_size, &ji, FALSE);
176 #else
177                 code = mono_arch_get_throw_corlib_exception ();
178 #endif
179 #else
180         g_assert_not_reached ();
181 #endif
182
183         mono_memory_barrier ();
184
185         throw_corlib_exception_func = code;
186
187         return throw_corlib_exception_func;
188 }
189
190 /* mono_find_jit_info:
191  *
192  * This function is used to gather information from @ctx. It return the 
193  * MonoJitInfo of the corresponding function, unwinds one stack frame and
194  * stores the resulting context into @new_ctx. It also stores a string 
195  * describing the stack location into @trace (if not NULL), and modifies
196  * the @lmf if necessary. @native_offset return the IP offset from the 
197  * start of the function or -1 if that info is not available.
198  */
199 MonoJitInfo *
200 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
201                     MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
202                     gboolean *managed)
203 {
204         gboolean managed2;
205         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
206         MonoJitInfo *ji;
207
208         if (trace)
209                 *trace = NULL;
210
211         if (native_offset)
212                 *native_offset = -1;
213
214         if (managed)
215                 *managed = FALSE;
216
217         ji = mono_arch_find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
218
219         if (ji == (gpointer)-1)
220                 return ji;
221
222         if (managed2 || ji->method->wrapper_type) {
223                 const char *real_ip, *start;
224                 gint32 offset;
225
226                 start = (const char *)ji->code_start;
227                 if (!managed2)
228                         /* ctx->ip points into native code */
229                         real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
230                 else
231                         real_ip = (const char*)ip;
232
233                 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
234                         offset = real_ip - start;
235                 else
236                         offset = -1;
237
238                 if (native_offset)
239                         *native_offset = offset;
240
241                 if (managed)
242                         if (!ji->method->wrapper_type)
243                                 *managed = TRUE;
244
245                 if (trace)
246                         *trace = mono_debug_print_stack_frame (ji->method, offset, domain);
247         } else {
248                 if (trace) {
249                         char *fname = mono_method_full_name (res->method, TRUE);
250                         *trace = g_strdup_printf ("in (unmanaged) %s", fname);
251                         g_free (fname);
252                 }
253         }
254
255         return ji;
256 }
257
258 static gpointer
259 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
260 {
261         MonoGenericJitInfo *gi;
262         gpointer info;
263
264         if (!ji->has_generic_jit_info)
265                 return NULL;
266         gi = mono_jit_info_get_generic_jit_info (ji);
267         if (!gi->has_this)
268                 return NULL;
269
270         if (gi->this_in_reg)
271                 info = mono_arch_context_get_int_reg (ctx, gi->this_reg);
272         else
273                 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
274                                                                           gi->this_offset);
275         if (mono_method_get_context (ji->method)->method_inst) {
276                 return info;
277         } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
278                 return info;
279         } else {
280                 /* Avoid returning a managed object */
281                 MonoObject *this_obj = info;
282
283                 return this_obj->vtable->klass;
284         }
285 }
286
287 static MonoGenericContext
288 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
289 {
290         MonoGenericContext context = { NULL, NULL };
291         MonoClass *class, *method_container_class;
292
293         g_assert (generic_info);
294
295         g_assert (ji->method->is_inflated);
296         if (mono_method_get_context (ji->method)->method_inst) {
297                 MonoMethodRuntimeGenericContext *mrgctx = generic_info;
298
299                 class = mrgctx->class_vtable->klass;
300                 context.method_inst = mrgctx->method_inst;
301                 g_assert (context.method_inst);
302         } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
303                 MonoVTable *vtable = generic_info;
304
305                 class = vtable->klass;
306         } else {
307                 class = generic_info;
308         }
309
310         if (class->generic_class || class->generic_container)
311                 context.class_inst = mini_class_get_context (class)->class_inst;
312
313         g_assert (!ji->method->klass->generic_container);
314         if (ji->method->klass->generic_class)
315                 method_container_class = ji->method->klass->generic_class->container_class;
316         else
317                 method_container_class = ji->method->klass;
318
319         if (class->generic_class)
320                 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class->container_class, method_container_class));
321         else
322                 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class));
323
324         return context;
325 }
326
327 static MonoMethod*
328 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
329 {
330         MonoGenericContext context;
331         MonoMethod *method;
332
333         if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
334                 return ji->method;
335         context = get_generic_context_from_stack_frame (ji, generic_info);
336
337         method = mono_method_get_declaring_generic_method (ji->method);
338         method = mono_class_inflate_generic_method (method, &context);
339
340         return method;
341 }
342
343 MonoString *
344 ves_icall_System_Exception_get_trace (MonoException *ex)
345 {
346         MonoDomain *domain = mono_domain_get ();
347         MonoString *res;
348         MonoArray *ta = ex->trace_ips;
349         int i, len;
350         GString *trace_str;
351
352         if (ta == NULL)
353                 /* Exception is not thrown yet */
354                 return NULL;
355
356         len = mono_array_length (ta) >> 1;
357         trace_str = g_string_new ("");
358         for (i = 0; i < len; i++) {
359                 MonoJitInfo *ji;
360                 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
361                 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
362
363                 ji = mono_jit_info_table_find (domain, ip);
364                 if (ji == NULL) {
365                         /* Unmanaged frame */
366                         g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
367                 } else {
368                         gchar *location;
369                         gint32 address;
370                         MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
371
372                         address = (char *)ip - (char *)ji->code_start;
373                         location = mono_debug_print_stack_frame (
374                                 method, address, ex->object.vtable->domain);
375
376                         g_string_append_printf (trace_str, "%s\n", location);
377                         g_free (location);
378                 }
379         }
380
381         res = mono_string_new (ex->object.vtable->domain, trace_str->str);
382         g_string_free (trace_str, TRUE);
383
384         return res;
385 }
386
387 MonoArray *
388 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
389 {
390         MonoDomain *domain = mono_domain_get ();
391         MonoArray *res;
392         MonoArray *ta = exc->trace_ips;
393         MonoDebugSourceLocation *location;
394         int i, len;
395
396         if (ta == NULL) {
397                 /* Exception is not thrown yet */
398                 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
399         }
400
401         len = mono_array_length (ta) >> 1;
402
403         res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
404
405         for (i = skip; i < len; i++) {
406                 MonoJitInfo *ji;
407                 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
408                 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
409                 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
410                 MonoMethod *method;
411
412                 ji = mono_jit_info_table_find (domain, ip);
413                 if (ji == NULL) {
414                         /* Unmanaged frame */
415                         mono_array_setref (res, i, sf);
416                         continue;
417                 }
418
419                 g_assert (ji != NULL);
420
421                 method = get_method_from_stack_frame (ji, generic_info);
422                 if (ji->method->wrapper_type) {
423                         char *s;
424
425                         sf->method = NULL;
426                         s = mono_method_full_name (method, TRUE);
427                         MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
428                         g_free (s);
429                 }
430                 else
431                         MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
432                 sf->native_offset = (char *)ip - (char *)ji->code_start;
433
434                 /*
435                  * mono_debug_lookup_source_location() returns both the file / line number information
436                  * and the IL offset.  Note that computing the IL offset is already an expensive
437                  * operation, so we shouldn't call this method twice.
438                  */
439                 location = mono_debug_lookup_source_location (ji->method, sf->native_offset, domain);
440                 if (location)
441                         sf->il_offset = location->il_offset;
442                 else
443                         sf->il_offset = 0;
444
445                 if (need_file_info) {
446                         if (location && location->source_file) {
447                                 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
448                                 sf->line = location->row;
449                                 sf->column = location->column;
450                         } else {
451                                 sf->line = sf->column = 0;
452                                 sf->filename = NULL;
453                         }
454                 }
455
456                 mono_debug_free_source_location (location);
457                 mono_array_setref (res, i, sf);
458         }
459
460         return res;
461 }
462
463 /**
464  * mono_walk_stack:
465  * @domain: starting appdomain
466  * @jit_tls: JIT data for the thread
467  * @start_ctx: starting state of the stack frame
468  * @func: callback to call for each stack frame
469  * @user_data: data passed to the callback
470  *
471  * This function walks the stack of a thread, starting from the state
472  * represented by jit_tls and start_ctx. For each frame the callback
473  * function is called with the relevant info. The walk ends when no more
474  * managed stack frames are found or when the callback returns a TRUE value.
475  * Note that the function can be used to walk the stack of a thread 
476  * different from the current.
477  */
478 void
479 mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gpointer user_data)
480 {
481         MonoLMF *lmf = mono_get_lmf ();
482         MonoJitInfo *ji, rji;
483         gint native_offset;
484         gboolean managed;
485         MonoContext ctx, new_ctx;
486
487         ctx = *start_ctx;
488
489         while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
490                 /* 
491                  * FIXME: mono_find_jit_info () will need to be able to return a different
492                  * MonoDomain when apddomain transitions are found on the stack.
493                  */
494                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
495                 if (!ji || ji == (gpointer)-1)
496                         return;
497
498                 if (func (domain, &new_ctx, ji, user_data))
499                         return;
500
501                 ctx = new_ctx;
502         }
503 }
504
505 void
506 mono_jit_walk_stack_from_ctx (MonoStackWalk func, MonoContext *start_ctx, gboolean do_il_offset, gpointer user_data)
507 {
508         MonoDomain *domain = mono_domain_get ();
509         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
510         MonoLMF *lmf = mono_get_lmf ();
511         MonoJitInfo *ji, rji;
512         gint native_offset, il_offset;
513         gboolean managed;
514         MonoContext ctx, new_ctx;
515
516         MONO_ARCH_CONTEXT_DEF
517
518         mono_arch_flush_register_windows ();
519
520         if (start_ctx) {
521                 memcpy (&ctx, start_ctx, sizeof (MonoContext));
522         } else {
523 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
524         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
525 #else
526     MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_jit_walk_stack_from_ctx);
527 #endif
528         }
529
530         while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
531                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
532                 g_assert (ji);
533
534                 if (ji == (gpointer)-1)
535                         return;
536
537                 if (do_il_offset) {
538                         MonoDebugSourceLocation *source;
539
540                         source = mono_debug_lookup_source_location (ji->method, native_offset, domain);
541                         il_offset = source ? source->il_offset : -1;
542                         mono_debug_free_source_location (source);
543                 } else
544                         il_offset = -1;
545
546                 if (func (ji->method, native_offset, il_offset, managed, user_data))
547                         return;
548                 
549                 ctx = new_ctx;
550         }
551 }
552
553 void
554 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data)
555 {
556         mono_jit_walk_stack_from_ctx (func, NULL, do_il_offset, user_data);
557 }
558
559 MonoBoolean
560 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
561                           MonoReflectionMethod **method, 
562                           gint32 *iloffset, gint32 *native_offset,
563                           MonoString **file, gint32 *line, gint32 *column)
564 {
565         MonoDomain *domain = mono_domain_get ();
566         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
567         MonoLMF *lmf = mono_get_lmf ();
568         MonoJitInfo *ji, rji;
569         MonoContext ctx, new_ctx, ji_ctx;
570         MonoDebugSourceLocation *location;
571         MonoMethod *last_method = NULL, *actual_method;
572
573         MONO_ARCH_CONTEXT_DEF;
574
575         mono_arch_flush_register_windows ();
576
577 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
578         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
579 #else
580         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
581 #endif
582
583         do {
584                 ji_ctx = ctx;
585                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, (int*) native_offset, NULL);
586                 ctx = new_ctx;
587
588                 if (ji && ji != (gpointer)-1 &&
589                                 MONO_CONTEXT_GET_IP (&ctx) >= ji->code_start &&
590                                 (guint8*)MONO_CONTEXT_GET_IP (&ctx) < (guint8*)ji->code_start + ji->code_size) {
591                         ji_ctx = ctx;
592                 }
593
594                 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_SP (&ctx) >= jit_tls->end_of_stack)
595                         return FALSE;
596
597                 /* skip all wrappers ??*/
598                 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
599                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
600                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
601                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
602                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE ||
603                         ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
604                         continue;
605
606                 if (ji->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE && ji->method == last_method) {
607                         /*
608                          * FIXME: Native-to-managed wrappers sometimes show up twice.
609                          * Probably the whole mono_find_jit_info () stuff needs to be fixed so this 
610                          * isn't needed.
611                          */
612                         continue;
613                 }
614
615                 last_method = ji->method;
616
617                 skip--;
618
619         } while (skip >= 0);
620
621         actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ji_ctx));
622
623         *method = mono_method_get_object (domain, actual_method, NULL);
624
625         location = mono_debug_lookup_source_location (ji->method, *native_offset, domain);
626         if (location)
627                 *iloffset = location->il_offset;
628         else
629                 *iloffset = 0;
630
631         if (need_file_info) {
632                 if (location) {
633                         *file = mono_string_new (domain, location->source_file);
634                         *line = location->row;
635                         *column = location->column;
636                 } else {
637                         *file = NULL;
638                         *line = *column = 0;
639                 }
640         }
641
642         mono_debug_free_source_location (location);
643
644         return TRUE;
645 }
646
647 typedef struct {
648         guint32 skips;
649         MonoSecurityFrame *frame;
650 } MonoFrameSecurityInfo;
651
652 static gboolean
653 callback_get_first_frame_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
654 {
655         MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
656
657         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
658         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
659             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
660             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
661             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
662             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
663                 return FALSE;
664         }
665
666         if (si->skips > 0) {
667                 si->skips--;
668                 return FALSE;
669         }
670
671         si->frame = mono_declsec_create_frame (domain, ji);
672
673         /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
674         return TRUE;
675 }
676
677 /**
678  * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
679  * @skip: the number of stack frames to skip
680  *
681  * This function returns a the security informations of a single stack frame 
682  * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
683  * and [NonCas]InheritanceDemand[Choice] as only the caller security is 
684  * evaluated.
685  */
686 MonoSecurityFrame*
687 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
688 {
689         MonoDomain *domain = mono_domain_get ();
690         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
691         MonoFrameSecurityInfo si;
692         MonoContext ctx;
693
694         MONO_ARCH_CONTEXT_DEF
695
696 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
697         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
698 #else
699         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
700 #endif
701
702 #if     defined(__ia64__) || defined(__s390__) || defined(__s390x__)
703         skip--;
704 #endif
705
706         si.skips = skip;
707         si.frame = NULL;
708         mono_walk_stack (domain, jit_tls, &ctx, callback_get_first_frame_security_info, (gpointer)&si);
709
710         return (si.skips == 0) ? si.frame : NULL;
711 }
712
713
714 typedef struct {
715         guint32 skips;
716         MonoArray *stack;
717         guint32 count;
718         guint32 maximum;
719 } MonoSecurityStack;
720
721 static void
722 grow_array (MonoSecurityStack *stack)
723 {
724         MonoDomain *domain = mono_domain_get ();
725         guint32 newsize = (stack->maximum << 1);
726         MonoArray *newstack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, newsize);
727         int i;
728         for (i=0; i < stack->maximum; i++) {
729                 gpointer frame = mono_array_get (stack->stack, gpointer, i);
730                 mono_array_setref (newstack, i, frame);
731         }
732         stack->maximum = newsize;
733         stack->stack = newstack;
734 }
735
736 static gboolean
737 callback_get_stack_frames_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
738 {
739         MonoSecurityStack *ss = (MonoSecurityStack*) data;
740
741         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
742         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
743             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
744             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
745             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
746             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
747                 return FALSE;
748         }
749
750         if (ss->skips > 0) {
751                 ss->skips--;
752                 return FALSE;
753         }
754
755         if (ss->count == ss->maximum)
756                 grow_array (ss);
757
758         mono_array_setref (ss->stack, ss->count++, mono_declsec_create_frame (domain, ji));
759
760         /* continue down the stack */
761         return FALSE;
762 }
763
764 static MonoArray *
765 glist_to_array (GList *list, MonoClass *eclass) 
766 {
767         MonoDomain *domain = mono_domain_get ();
768         MonoArray *res;
769         int len, i;
770
771         if (!list)
772                 return NULL;
773
774         len = g_list_length (list);
775         res = mono_array_new (domain, eclass, len);
776
777         for (i = 0; list; list = list->next, i++)
778                 mono_array_set (res, gpointer, i, list->data);
779
780         return res;
781 }
782
783 /**
784  * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
785  * @skip: the number of stack frames to skip
786  *
787  * This function returns an managed array of containing the security
788  * informations for each frame (after the skipped ones). This is used for
789  * [NonCas]Demand[Choice] where the complete evaluation of the stack is 
790  * required.
791  */
792 MonoArray*
793 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
794 {
795         MonoDomain *domain = mono_domain_get ();
796         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
797         MonoSecurityStack ss;
798         MonoContext ctx;
799
800         MONO_ARCH_CONTEXT_DEF
801
802 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
803         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
804 #else
805         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityStack);
806 #endif
807
808 #if     defined(__ia64__) || defined(__s390__) || defined(__s390x__)
809         skip--;
810 #endif
811
812         ss.skips = skip;
813         ss.count = 0;
814         ss.maximum = MONO_CAS_INITIAL_STACK_SIZE;
815         ss.stack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, ss.maximum);
816         mono_walk_stack (domain, jit_tls, &ctx, callback_get_stack_frames_security_info, (gpointer)&ss);
817         /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
818         return ss.stack;
819 }
820
821 static MonoClass*
822 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
823 {
824         MonoClass *catch_class = ei->data.catch_class;
825         MonoType *inflated_type;
826         MonoGenericContext context;
827
828         if (!catch_class)
829                 return NULL;
830
831         if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
832                 return catch_class;
833         context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
834
835         /* FIXME: we shouldn't inflate but instead put the
836            type in the rgctx and fetch it from there.  It
837            might be a good idea to do this lazily, i.e. only
838            when the exception is actually thrown, so as not to
839            waste space for exception clauses which might never
840            be encountered. */
841         inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
842         catch_class = mono_class_from_mono_type (inflated_type);
843         mono_metadata_free_type (inflated_type);
844
845         return catch_class;
846 }
847
848 /**
849  * mono_handle_exception_internal:
850  * @ctx: saved processor state
851  * @obj: the exception object
852  * @test_only: only test if the exception is caught, but dont call handlers
853  * @out_filter_idx: out parameter. if test_only is true, set to the index of 
854  * the first filter clause which caught the exception.
855  */
856 static gboolean
857 mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only, gint32 *out_filter_idx)
858 {
859         MonoDomain *domain = mono_domain_get ();
860         MonoJitInfo *ji, rji;
861         static int (*call_filter) (MonoContext *, gpointer) = NULL;
862         static void (*restore_context) (void *);
863         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
864         MonoLMF *lmf = mono_get_lmf ();
865         MonoArray *initial_trace_ips = NULL;
866         GList *trace_ips = NULL;
867         MonoException *mono_ex;
868         gboolean stack_overflow = FALSE;
869         MonoContext initial_ctx;
870         int frame_count = 0;
871         gboolean has_dynamic_methods = FALSE;
872         gint32 filter_idx, first_filter_idx;
873
874         g_assert (ctx != NULL);
875         if (!obj) {
876                 MonoException *ex = mono_get_exception_null_reference ();
877                 MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object"));
878                 obj = (MonoObject *)ex;
879         } 
880
881         /*
882          * Allocate a new exception object instead of the preconstructed ones.
883          */
884         if (obj == domain->stack_overflow_ex) {
885                 /*
886                  * It is not a good idea to try and put even more pressure on the little stack available.
887                  * obj = mono_get_exception_stack_overflow ();
888                  */
889                 stack_overflow = TRUE;
890         }
891         else if (obj == domain->null_reference_ex) {
892                 obj = mono_get_exception_null_reference ();
893         }
894
895         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
896                 mono_ex = (MonoException*)obj;
897                 initial_trace_ips = mono_ex->trace_ips;
898         } else {
899                 mono_ex = NULL;
900         }
901
902         if (mono_ex && jit_tls->class_cast_from && !strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) {
903                 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
904                 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
905                 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
906                 mono_ex->message = mono_string_new (domain, msg);
907                 g_free (from_name);
908                 g_free (to_name);
909                 g_free (msg);
910         }
911
912         if (!call_filter)
913                 call_filter = mono_get_call_filter ();
914
915         if (!restore_context)
916                 restore_context = mono_get_restore_context ();
917
918         g_assert (jit_tls->end_of_stack);
919         g_assert (jit_tls->abort_func);
920
921         if (!test_only) {
922                 MonoContext ctx_cp = *ctx;
923                 if (mono_trace_is_enabled ())
924                         g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
925                 mono_profiler_exception_thrown (obj);
926                 if (!mono_handle_exception_internal (&ctx_cp, obj, original_ip, TRUE, &first_filter_idx)) {
927                         if (mono_break_on_exc)
928                                 G_BREAKPOINT ();
929                         // FIXME: This runs managed code so it might cause another stack overflow when
930                         // we are handling a stack overflow
931                         mono_unhandled_exception (obj);
932                 }
933         }
934
935         if (out_filter_idx)
936                 *out_filter_idx = -1;
937         filter_idx = 0;
938         initial_ctx = *ctx;
939         memset (&rji, 0, sizeof (rji));
940
941         while (1) {
942                 MonoContext new_ctx;
943                 guint32 free_stack;
944
945                 ji = mono_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx, 
946                                                                  NULL, &lmf, NULL, NULL);
947                 if (!ji) {
948                         g_warning ("Exception inside function without unwind info");
949                         g_assert_not_reached ();
950                 }
951
952                 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))))) {
953                         /*
954                          * The exception was raised in native code and we got back to managed code 
955                          * using the LMF.
956                          */
957                         *ctx = new_ctx;
958                         continue;
959                 }
960
961                 if (ji != (gpointer)-1) {
962                         frame_count ++;
963                         //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
964
965                         if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
966                                 /* 
967                                  * Avoid overwriting the stack trace if the exception is
968                                  * rethrown. Also avoid giant stack traces during a stack
969                                  * overflow.
970                                  */
971                                 if (!initial_trace_ips && (frame_count < 1000)) {
972                                         trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
973                                         trace_ips = g_list_prepend (trace_ips,
974                                                 get_generic_info_from_stack_frame (ji, ctx));
975                                 }
976                         }
977
978                         if (ji->method->dynamic)
979                                 has_dynamic_methods = TRUE;
980
981                         if (stack_overflow)
982 #ifndef MONO_ARCH_STACK_GROWS_UP
983                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
984 #else
985                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
986 #endif
987                         else
988                                 free_stack = 0xffffff;
989
990                         /* 
991                          * During stack overflow, wait till the unwinding frees some stack
992                          * space before running handlers/finalizers.
993                          */
994                         if ((free_stack > (64 * 1024)) && ji->num_clauses) {
995                                 int i;
996                                 
997                                 for (i = 0; i < ji->num_clauses; i++) {
998                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
999                                         gboolean filtered = FALSE;
1000
1001 #if defined(__s390__)
1002                                         /* 
1003                                          * This is required in cases where a try block starts immediately after
1004                                          * a call which causes an exception. Testcase: tests/exception8.cs.
1005                                          * FIXME: Clean this up.
1006                                          */
1007                                         if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) && 
1008 #else
1009                                         if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
1010 #endif
1011                                             MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
1012                                                 /* catch block */
1013                                                 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1014
1015                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
1016                                                         /* store the exception object in bp + ei->exvar_offset */
1017                                                         *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
1018                                                 }
1019
1020                                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1021                                                         // mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
1022                                                         if (test_only) {
1023                                                                 mono_perfcounters->exceptions_filters++;
1024                                                                 filtered = call_filter (ctx, ei->data.filter);
1025                                                                 if (filtered && out_filter_idx)
1026                                                                         *out_filter_idx = filter_idx;
1027                                                         }
1028                                                         else {
1029                                                                 /* 
1030                                                                  * Filter clauses should only be run in the 
1031                                                                  * first pass of exception handling.
1032                                                                  */
1033                                                                 filtered = (filter_idx == first_filter_idx);
1034                                                         }
1035                                                         filter_idx ++;
1036                                                 }
1037
1038                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
1039                                                      mono_object_isinst (obj, catch_class)) || filtered) {
1040                                                         if (test_only) {
1041                                                                 if (mono_ex && !initial_trace_ips) {
1042                                                                         trace_ips = g_list_reverse (trace_ips);
1043                                                                         MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1044                                                                         if (has_dynamic_methods)
1045                                                                                 /* These methods could go away anytime, so compute the stack trace now */
1046                                                                                 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1047                                                                 }
1048                                                                 g_list_free (trace_ips);
1049
1050                                                                 return TRUE;
1051                                                         }
1052                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1053                                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1054                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1055                                                         mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1056                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1057                                                         *(mono_get_lmf_addr ()) = lmf;
1058                                                         mono_perfcounters->exceptions_depth += frame_count;
1059                                                         if (obj == domain->stack_overflow_ex)
1060                                                                 jit_tls->handling_stack_ovf = FALSE;
1061
1062                                                         return 0;
1063                                                 }
1064                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
1065                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
1066                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
1067                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1068                                                                 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1069                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1070                                                         mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1071                                                         call_filter (ctx, ei->handler_start);
1072                                                 }
1073                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
1074                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
1075                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
1076                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1077                                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1078                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1079                                                         mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1080                                                         mono_perfcounters->exceptions_finallys++;
1081                                                         call_filter (ctx, ei->handler_start);
1082                                                 }
1083                                                 
1084                                         }
1085                                 }
1086                         }
1087                         if (!test_only)
1088                                 mono_profiler_exception_method_leave (ji->method);
1089                 }
1090
1091                 *ctx = new_ctx;
1092
1093                 if (ji == (gpointer)-1) {
1094
1095                         if (!test_only) {
1096                                 *(mono_get_lmf_addr ()) = lmf;
1097
1098                                 jit_tls->abort_func (obj);
1099                                 g_assert_not_reached ();
1100                         } else {
1101                                 if (mono_ex && !initial_trace_ips) {
1102                                         trace_ips = g_list_reverse (trace_ips);
1103                                         MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1104                                         if (has_dynamic_methods)
1105                                                 /* These methods could go away anytime, so compute the stack trace now */
1106                                                 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1107                                 }
1108                                 g_list_free (trace_ips);
1109                                 return FALSE;
1110                         }
1111                 }
1112         }
1113
1114         g_assert_not_reached ();
1115 }
1116
1117 /**
1118  * mono_debugger_run_finally:
1119  * @start_ctx: saved processor state
1120  *
1121  * This method is called by the Mono Debugger to call all `finally' clauses of the
1122  * current stack frame.  It's used when the user issues a `return' command to make
1123  * the current stack frame return.  After returning from this method, the debugger
1124  * unwinds the stack one frame and gives control back to the user.
1125  *
1126  * NOTE: This method is only used when running inside the Mono Debugger.
1127  */
1128 void
1129 mono_debugger_run_finally (MonoContext *start_ctx)
1130 {
1131         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1132         MonoDomain *domain = mono_domain_get ();
1133         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1134         MonoLMF *lmf = mono_get_lmf ();
1135         MonoContext ctx, new_ctx;
1136         MonoJitInfo *ji, rji;
1137         int i;
1138
1139         ctx = *start_ctx;
1140
1141         ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1142         if (!ji || ji == (gpointer)-1)
1143                 return;
1144
1145         if (!call_filter)
1146                 call_filter = mono_get_call_filter ();
1147
1148         for (i = 0; i < ji->num_clauses; i++) {
1149                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1150
1151                 if ((ei->try_start <= MONO_CONTEXT_GET_IP (&ctx)) && 
1152                     (MONO_CONTEXT_GET_IP (&ctx) < ei->try_end) &&
1153                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1154                         call_filter (&ctx, ei->handler_start);
1155                 }
1156         }
1157 }
1158
1159 /**
1160  * mono_handle_exception:
1161  * @ctx: saved processor state
1162  * @obj: the exception object
1163  * @test_only: only test if the exception is caught, but dont call handlers
1164  */
1165 gboolean
1166 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
1167 {
1168         if (!test_only)
1169                 mono_perfcounters->exceptions_thrown++;
1170         return mono_handle_exception_internal (ctx, obj, original_ip, test_only, NULL);
1171 }
1172
1173 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1174
1175 #ifndef MONO_ARCH_USE_SIGACTION
1176 #error "Can't use sigaltstack without sigaction"
1177 #endif
1178
1179 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1180
1181 void
1182 mono_setup_altstack (MonoJitTlsData *tls)
1183 {
1184         size_t stsize = 0;
1185         struct sigaltstack sa;
1186         guint8 *staddr = NULL;
1187
1188         if (mono_running_on_valgrind ())
1189                 return;
1190
1191         mono_thread_get_stack_bounds (&staddr, &stsize);
1192
1193         g_assert (staddr);
1194
1195         tls->end_of_stack = staddr + stsize;
1196
1197         /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1198
1199         tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1200         tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
1201
1202         if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1203                 /* mprotect can fail for the main thread stack */
1204                 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);
1205                 g_assert (gaddr == tls->stack_ovf_guard_base);
1206         }
1207
1208         /*
1209          * threads created by nptl does not seem to have a guard page, and
1210          * since the main thread is not created by us, we can't even set one.
1211          * Increasing stsize fools the SIGSEGV signal handler into thinking this
1212          * is a stack overflow exception.
1213          */
1214         tls->stack_size = stsize + mono_pagesize ();
1215
1216         /* Setup an alternate signal stack */
1217         tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
1218         tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1219
1220         g_assert (tls->signal_stack);
1221
1222         sa.ss_sp = tls->signal_stack;
1223         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1224         sa.ss_flags = SS_ONSTACK;
1225         sigaltstack (&sa, NULL);
1226 }
1227
1228 void
1229 mono_free_altstack (MonoJitTlsData *tls)
1230 {
1231         struct sigaltstack sa;
1232         int err;
1233
1234         sa.ss_sp = tls->signal_stack;
1235         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1236         sa.ss_flags = SS_DISABLE;
1237         err = sigaltstack  (&sa, NULL);
1238         g_assert (err == 0);
1239
1240         if (tls->signal_stack)
1241                 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1242 }
1243
1244 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1245
1246 void
1247 mono_setup_altstack (MonoJitTlsData *tls)
1248 {
1249 }
1250
1251 void
1252 mono_free_altstack (MonoJitTlsData *tls)
1253 {
1254 }
1255
1256 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1257
1258 static gboolean
1259 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
1260 {
1261         gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
1262         /* we need to leave some room for throwing the exception */
1263         while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
1264                 unprotect_size -= mono_pagesize ();
1265         /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1266          * is sufficient stack
1267          */
1268         //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);
1269         if (unprotect_size)
1270                 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
1271         return unprotect_size == jit_tls->stack_ovf_guard_size;
1272 }
1273
1274 static void
1275 try_more_restore (void)
1276 {
1277         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1278         if (try_restore_stack_protection (jit_tls, 500))
1279                 jit_tls->restore_stack_prot = NULL;
1280 }
1281
1282 static void
1283 restore_stack_protection (void)
1284 {
1285         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1286         MonoException *ex = mono_domain_get ()->stack_overflow_ex;
1287         /* if we can't restore the stack protection, keep a callback installed so
1288          * we'll try to restore as much stack as we can at each return from unmanaged
1289          * code.
1290          */
1291         if (try_restore_stack_protection (jit_tls, 4096))
1292                 jit_tls->restore_stack_prot = NULL;
1293         else
1294                 jit_tls->restore_stack_prot = try_more_restore_tramp;
1295         /* here we also throw a stack overflow exception */
1296         ex->trace_ips = NULL;
1297         ex->stack_trace = NULL;
1298         mono_raise_exception (ex);
1299 }
1300
1301 gpointer
1302 mono_altstack_restore_prot (gssize *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
1303 {
1304         void (*func)(void) = (gpointer)tramp_data;
1305         func ();
1306         return NULL;
1307 }
1308
1309 gboolean
1310 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
1311 {
1312         /* we got a stack overflow in the soft-guard pages
1313          * There are two cases:
1314          * 1) managed code caused the overflow: we unprotect the soft-guard page
1315          * and let the arch-specific code trigger the exception handling mechanism
1316          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1317          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1318          * and hope we can continue with those enabled, at least until the hard-guard page
1319          * is hit. The alternative to continuing here is to just print a message and abort.
1320          * We may add in the future the code to protect the pages again in the codepath
1321          * when we return from unmanaged to managed code.
1322          */
1323         if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
1324                         fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
1325                 /* we unprotect the minimum amount we can */
1326                 guint32 guard_size;
1327                 gboolean handled = FALSE;
1328
1329                 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
1330                 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
1331                         guard_size -= mono_pagesize ();
1332                 }
1333                 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
1334                 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
1335                 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);
1336 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1337                 if (ji) {
1338                         mono_arch_handle_altstack_exception (ctx, fault_addr, TRUE);
1339                         handled = TRUE;
1340                 }
1341 #endif
1342                 if (!handled) {
1343                         /* We print a message: after this even managed stack overflows
1344                          * may crash the runtime
1345                          */
1346                         fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), fault_addr);
1347                         if (!jit_tls->handling_stack_ovf) {
1348                                 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
1349                                 jit_tls->handling_stack_ovf = 1;
1350                         } else {
1351                                 /*fprintf (stderr, "Already handling stack overflow\n");*/
1352                         }
1353                 }
1354                 return TRUE;
1355         }
1356         return FALSE;
1357 }
1358
1359 static gboolean
1360 print_stack_frame (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed, gpointer data)
1361 {
1362         FILE *stream = (FILE*)data;
1363
1364         if (method) {
1365                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1366                 fprintf (stream, "  %s\n", location);
1367                 g_free (location);
1368         } else
1369                 fprintf (stream, "  at <unknown> <0x%05x>\n", native_offset);
1370
1371         return FALSE;
1372 }
1373
1374 static G_GNUC_UNUSED gboolean
1375 print_stack_frame_to_string (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed,
1376                              gpointer data)
1377 {
1378         GString *p = (GString*)data;
1379
1380         if (method) {
1381                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1382                 g_string_append_printf (p, "  %s\n", location);
1383                 g_free (location);
1384         } else
1385                 g_string_append_printf (p, "  at <unknown> <0x%05x>\n", native_offset);
1386
1387         return FALSE;
1388 }
1389
1390 static gboolean handling_sigsegv = FALSE;
1391
1392 /*
1393  * mono_handle_native_sigsegv:
1394  *
1395  *   Handle a SIGSEGV received while in native code by printing diagnostic 
1396  * information and aborting.
1397  */
1398 void
1399 mono_handle_native_sigsegv (int signal, void *ctx)
1400 {
1401 #ifdef MONO_ARCH_USE_SIGACTION
1402         struct sigaction sa;
1403 #endif
1404         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1405
1406         if (handling_sigsegv)
1407                 return;
1408
1409         if (mini_get_debug_options ()->suspend_on_sigsegv) {
1410                 fprintf (stderr, "Received SIGSEGV, suspending...");
1411                 while (1)
1412                         ;
1413         }
1414
1415         /* To prevent infinite loops when the stack walk causes a crash */
1416         handling_sigsegv = TRUE;
1417
1418         /* !jit_tls means the thread was not registered with the runtime */
1419         if (jit_tls) {
1420                 fprintf (stderr, "Stacktrace:\n\n");
1421
1422                 mono_jit_walk_stack (print_stack_frame, TRUE, stderr);
1423
1424                 fflush (stderr);
1425         }
1426
1427 #ifdef HAVE_BACKTRACE_SYMBOLS
1428  {
1429         void *array [256];
1430         char **names;
1431         int i, size;
1432         const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
1433
1434         fprintf (stderr, "\nNative stacktrace:\n\n");
1435
1436         size = backtrace (array, 256);
1437         names = backtrace_symbols (array, size);
1438         for (i =0; i < size; ++i) {
1439                 fprintf (stderr, "\t%s\n", names [i]);
1440         }
1441         free (names);
1442
1443         fflush (stderr);
1444
1445         /* Try to get more meaningful information using gdb */
1446
1447 #if !defined(PLATFORM_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
1448         if (!mini_get_debug_options ()->no_gdb_backtrace && !mono_debug_using_mono_debugger ()) {
1449                 /* From g_spawn_command_line_sync () in eglib */
1450                 int res;
1451                 int stdout_pipe [2] = { -1, -1 };
1452                 pid_t pid;
1453                 const char *argv [16];
1454                 char buf1 [128];
1455                 int status;
1456                 char buffer [1024];
1457
1458                 res = pipe (stdout_pipe);
1459                 g_assert (res != -1);
1460                         
1461                 //pid = fork ();
1462                 /*
1463                  * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1464                  * it will deadlock. Call the syscall directly instead.
1465                  */
1466                 pid = syscall (SYS_fork);
1467                 if (pid == 0) {
1468                         close (stdout_pipe [0]);
1469                         dup2 (stdout_pipe [1], STDOUT_FILENO);
1470
1471                         for (i = getdtablesize () - 1; i >= 3; i--)
1472                                 close (i);
1473
1474                         argv [0] = g_find_program_in_path ("gdb");
1475                         if (argv [0] == NULL) {
1476                                 close (STDOUT_FILENO);
1477                                 exit (1);
1478                         }
1479
1480                         argv [1] = "-ex";
1481                         sprintf (buf1, "attach %ld", (long)getpid ());
1482                         argv [2] = buf1;
1483                         argv [3] = "--ex";
1484                         argv [4] = "info threads";
1485                         argv [5] = "--ex";
1486                         argv [6] = "thread apply all bt";
1487                         argv [7] = "--batch";
1488                         argv [8] = 0;
1489
1490                         execv (argv [0], (char**)argv);
1491                         exit (1);
1492                 }
1493
1494                 close (stdout_pipe [1]);
1495
1496                 fprintf (stderr, "\nDebug info from gdb:\n\n");
1497
1498                 while (1) {
1499                         int nread = read (stdout_pipe [0], buffer, 1024);
1500
1501                         if (nread <= 0)
1502                                 break;
1503                         write (STDERR_FILENO, buffer, nread);
1504                 }               
1505
1506                 waitpid (pid, &status, WNOHANG);
1507         }
1508 #endif
1509         /*
1510          * A SIGSEGV indicates something went very wrong so we can no longer depend
1511          * on anything working. So try to print out lots of diagnostics, starting 
1512          * with ones which have a greater chance of working.
1513          */
1514         fprintf (stderr,
1515                          "\n"
1516                          "=================================================================\n"
1517                          "Got a %s while executing native code. This usually indicates\n"
1518                          "a fatal error in the mono runtime or one of the native libraries \n"
1519                          "used by your application.\n"
1520                          "=================================================================\n"
1521                          "\n", signal_str);
1522
1523  }
1524 #endif
1525
1526 #ifdef MONO_ARCH_USE_SIGACTION
1527
1528         /* Remove our SIGABRT handler */
1529         sa.sa_handler = SIG_DFL;
1530         sigemptyset (&sa.sa_mask);
1531         sa.sa_flags = 0;
1532
1533         g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
1534
1535 #endif
1536
1537         abort ();
1538 }
1539
1540 /*
1541  * mono_print_thread_dump:
1542  *
1543  *   Print information about the current thread to stdout.
1544  * SIGCTX can be NULL, allowing this to be called from gdb.
1545  */
1546 void
1547 mono_print_thread_dump (void *sigctx)
1548 {
1549         MonoThread *thread = mono_thread_current ();
1550 #if defined(__i386__) || defined(__x86_64__)
1551         MonoContext ctx;
1552 #endif
1553         GString* text = g_string_new (0);
1554         char *name, *wapi_desc;
1555         GError *error = NULL;
1556
1557         if (thread->name) {
1558                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
1559                 g_assert (!error);
1560                 g_string_append_printf (text, "\n\"%s\"", name);
1561                 g_free (name);
1562         }
1563         else if (thread->threadpool_thread)
1564                 g_string_append (text, "\n\"<threadpool thread>\"");
1565         else
1566                 g_string_append (text, "\n\"<unnamed thread>\"");
1567
1568 #ifndef PLATFORM_WIN32
1569         wapi_desc = wapi_current_thread_desc ();
1570         g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread,  wapi_desc);
1571         free (wapi_desc);
1572 #endif
1573
1574 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
1575         if (!sigctx)
1576                 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
1577         else
1578                 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
1579
1580         mono_jit_walk_stack_from_ctx (print_stack_frame_to_string, &ctx, TRUE, text);
1581 #else
1582         printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
1583 #endif
1584
1585         fprintf (stdout, text->str);
1586         g_string_free (text, TRUE);
1587         fflush (stdout);
1588 }