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