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