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