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