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