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