Fix guard interrupt protection.
[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/metadata/mono-endian.h>
47 #include <mono/utils/mono-mmap.h>
48
49 #include "mini.h"
50 #include "debug-mini.h"
51 #include "trace.h"
52 #include "debugger-agent.h"
53
54 #ifndef MONO_ARCH_CONTEXT_DEF
55 #define MONO_ARCH_CONTEXT_DEF
56 #endif
57
58 static gpointer restore_context_func, call_filter_func;
59 static gpointer throw_exception_func, rethrow_exception_func;
60 static gpointer throw_corlib_exception_func;
61
62 static gpointer try_more_restore_tramp = NULL;
63 static gpointer restore_stack_protection_tramp = NULL;
64
65 static void try_more_restore (void);
66 static void restore_stack_protection (void);
67
68 void
69 mono_exceptions_init (void)
70 {
71         if (mono_aot_only) {
72                 restore_context_func = mono_aot_get_trampoline ("restore_context");
73                 call_filter_func = mono_aot_get_trampoline ("call_filter");
74                 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
75                 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
76         } else {
77                 MonoTrampInfo *info;
78
79                 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
80                 if (info) {
81                         mono_save_trampoline_xdebug_info (info);
82                         mono_tramp_info_free (info);
83                 }
84                 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
85                 if (info) {
86                         mono_save_trampoline_xdebug_info (info);
87                         mono_tramp_info_free (info);
88                 }
89                 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
90                 if (info) {
91                         mono_save_trampoline_xdebug_info (info);
92                         mono_tramp_info_free (info);
93                 }
94                 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
95                 if (info) {
96                         mono_save_trampoline_xdebug_info (info);
97                         mono_tramp_info_free (info);
98                 }
99         }
100 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
101         try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
102         restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
103 #endif
104
105 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
106         mono_arch_exceptions_init ();
107 #endif
108 }
109
110 gpointer
111 mono_get_throw_exception (void)
112 {
113         g_assert (throw_exception_func);
114         return throw_exception_func;
115 }
116
117 gpointer
118 mono_get_rethrow_exception (void)
119 {
120         g_assert (rethrow_exception_func);
121         return rethrow_exception_func;
122 }
123
124 gpointer
125 mono_get_call_filter (void)
126 {
127         g_assert (call_filter_func);
128         return call_filter_func;
129 }
130
131 gpointer
132 mono_get_restore_context (void)
133 {
134         g_assert (restore_context_func);
135         return restore_context_func;
136 }
137
138 gpointer
139 mono_get_throw_corlib_exception (void)
140 {
141         gpointer code = NULL;
142         MonoTrampInfo *info;
143
144         /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
145         if (throw_corlib_exception_func)
146                 return throw_corlib_exception_func;
147
148         if (mono_aot_only)
149                 code = mono_aot_get_trampoline ("throw_corlib_exception");
150         else {
151                 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
152                 if (info) {
153                         mono_save_trampoline_xdebug_info (info);
154                         mono_tramp_info_free (info);
155                 }
156         }
157
158         mono_memory_barrier ();
159
160         throw_corlib_exception_func = code;
161
162         return throw_corlib_exception_func;
163 }
164
165 static gboolean
166 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
167 {
168         MonoTryBlockHoleTableJitInfo *table;
169         int i;
170         guint32 offset;
171         guint16 clause;
172
173         if (ei->try_start > ip || ip >= ei->try_end)
174                 return FALSE;
175
176         if (!ji->has_try_block_holes)
177                 return TRUE;
178
179         table = mono_jit_info_get_try_block_hole_table_info (ji);
180         offset = (guint32)((char*)ip - (char*)ji->code_start);
181         clause = (guint16)(ei - ji->clauses);
182         g_assert (clause < ji->num_clauses);
183
184         for (i = 0; i < table->num_holes; ++i) {
185                 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
186                 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
187                         return FALSE;
188         }
189         return TRUE;
190 }
191
192 /*
193  * find_jit_info:
194  *
195  * Translate between the mono_arch_find_jit_info function and the old API.
196  */
197 static MonoJitInfo *
198 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
199                            MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
200 {
201         StackFrameInfo frame;
202         MonoJitInfo *ji;
203         gboolean err;
204         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
205
206         /* Avoid costly table lookup during stack overflow */
207         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
208                 ji = prev_ji;
209         else
210                 ji = mini_jit_info_table_find (domain, ip, NULL);
211
212         if (managed)
213                 *managed = FALSE;
214
215         err = mono_arch_find_jit_info (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
216         if (!err)
217                 return (gpointer)-1;
218
219         /* Convert between the new and the old APIs */
220         switch (frame.type) {
221         case FRAME_TYPE_MANAGED:
222                 if (managed)
223                         *managed = TRUE;
224                 return frame.ji;
225         case FRAME_TYPE_MANAGED_TO_NATIVE:
226                 if (frame.ji)
227                         return frame.ji;
228                 else {
229                         memset (res, 0, sizeof (MonoJitInfo));
230                         res->method = frame.method;
231                         return res;
232                 }
233         case FRAME_TYPE_DEBUGGER_INVOKE: {
234                 MonoContext tmp_ctx;
235
236                 /*
237                  * The normal exception handling code can't handle this frame, so just
238                  * skip it.
239                  */
240                 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
241                 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
242                 return ji;
243         }
244         default:
245                 g_assert_not_reached ();
246                 return NULL;
247         }
248 }
249
250 /* mono_find_jit_info:
251  *
252  * This function is used to gather information from @ctx. It return the 
253  * MonoJitInfo of the corresponding function, unwinds one stack frame and
254  * stores the resulting context into @new_ctx. It also stores a string 
255  * describing the stack location into @trace (if not NULL), and modifies
256  * the @lmf if necessary. @native_offset return the IP offset from the 
257  * start of the function or -1 if that info is not available.
258  */
259 MonoJitInfo *
260 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
261                     MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
262                     gboolean *managed)
263 {
264         gboolean managed2;
265         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
266         MonoJitInfo *ji;
267
268         if (trace)
269                 *trace = NULL;
270
271         if (native_offset)
272                 *native_offset = -1;
273
274         if (managed)
275                 *managed = FALSE;
276
277         ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
278
279         if (ji == (gpointer)-1)
280                 return ji;
281
282         if (managed2 || (ji && ji->method->wrapper_type)) {
283                 const char *real_ip, *start;
284                 gint32 offset;
285
286                 start = (const char *)ji->code_start;
287                 if (!managed2)
288                         /* ctx->ip points into native code */
289                         real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
290                 else
291                         real_ip = (const char*)ip;
292
293                 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
294                         offset = real_ip - start;
295                 else
296                         offset = -1;
297
298                 if (native_offset)
299                         *native_offset = offset;
300
301                 if (managed)
302                         if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
303                                 *managed = TRUE;
304
305                 if (trace)
306                         *trace = mono_debug_print_stack_frame (ji->method, offset, domain);
307         } else {
308                 if (trace) {
309                         char *fname = mono_method_full_name (res->method, TRUE);
310                         *trace = g_strdup_printf ("in (unmanaged) %s", fname);
311                         g_free (fname);
312                 }
313         }
314
315         return ji;
316 }
317
318 /*
319  * mono_find_jit_info_ext:
320  *
321  *   A version of mono_find_jit_info which returns all data in the StackFrameInfo
322  * structure.
323  * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
324  * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
325  * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
326  * to obtain the last managed frame.
327  * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
328  * On return, it will be filled with the locations where callee saved registers are saved
329  * by the current frame. This is returned outside of StackFrameInfo because it can be
330  * quite large on some platforms.
331  */
332 gboolean
333 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, 
334                                                 MonoJitInfo *prev_ji, MonoContext *ctx,
335                                                 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
336                                                 mgreg_t **save_locations,
337                                                 StackFrameInfo *frame)
338 {
339         gboolean err;
340         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
341         MonoJitInfo *ji;
342         MonoDomain *target_domain;
343
344         if (trace)
345                 *trace = NULL;
346
347         /* Avoid costly table lookup during stack overflow */
348         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
349                 ji = prev_ji;
350         else
351                 ji = mini_jit_info_table_find (domain, ip, &target_domain);
352
353         if (!target_domain)
354                 target_domain = domain;
355
356         if (save_locations)
357                 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (mgreg_t*));
358
359         err = mono_arch_find_jit_info (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
360         if (!err)
361                 return FALSE;
362
363         if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
364                 /*
365                  * This type of frame is just a marker, the caller should unwind once more to get the
366                  * last managed frame.
367                  */
368                 frame->ji = NULL;
369                 frame->method = NULL;
370         }
371
372         frame->native_offset = -1;
373         frame->domain = target_domain;
374
375         ji = frame->ji;
376
377         if (frame->type == FRAME_TYPE_MANAGED)
378                 frame->method = ji->method;
379
380         if (ji && (frame->managed || ji->method->wrapper_type)) {
381                 const char *real_ip, *start;
382
383                 start = (const char *)ji->code_start;
384                 if (!frame->managed)
385                         /* ctx->ip points into native code */
386                         real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
387                 else
388                         real_ip = (const char*)ip;
389
390                 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
391                         frame->native_offset = real_ip - start;
392                 else
393                         frame->native_offset = -1;
394
395                 if (trace)
396                         *trace = mono_debug_print_stack_frame (ji->method, frame->native_offset, domain);
397         } else {
398                 if (trace && frame->method) {
399                         char *fname = mono_method_full_name (frame->method, TRUE);
400                         *trace = g_strdup_printf ("in (unmanaged) %s", fname);
401                         g_free (fname);
402                 }
403         }
404
405         return TRUE;
406 }
407
408 static gpointer
409 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
410 {
411         MonoGenericJitInfo *gi;
412         gpointer info;
413
414         if (!ji->has_generic_jit_info)
415                 return NULL;
416         gi = mono_jit_info_get_generic_jit_info (ji);
417         if (!gi->has_this)
418                 return NULL;
419
420         if (gi->this_in_reg)
421                 info = mono_arch_context_get_int_reg (ctx, gi->this_reg);
422         else
423                 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
424                                                                           gi->this_offset);
425         if (mono_method_get_context (ji->method)->method_inst) {
426                 return info;
427         } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
428                 return info;
429         } else {
430                 /* Avoid returning a managed object */
431                 MonoObject *this_obj = info;
432
433                 return this_obj->vtable->klass;
434         }
435 }
436
437 static MonoGenericContext
438 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
439 {
440         MonoGenericContext context = { NULL, NULL };
441         MonoClass *class, *method_container_class;
442
443         g_assert (generic_info);
444
445         g_assert (ji->method->is_inflated);
446         if (mono_method_get_context (ji->method)->method_inst) {
447                 MonoMethodRuntimeGenericContext *mrgctx = generic_info;
448
449                 class = mrgctx->class_vtable->klass;
450                 context.method_inst = mrgctx->method_inst;
451                 g_assert (context.method_inst);
452         } else if ((ji->method->flags & METHOD_ATTRIBUTE_STATIC) || ji->method->klass->valuetype) {
453                 MonoVTable *vtable = generic_info;
454
455                 class = vtable->klass;
456         } else {
457                 class = generic_info;
458         }
459
460         //g_assert (!ji->method->klass->generic_container);
461         if (ji->method->klass->generic_class)
462                 method_container_class = ji->method->klass->generic_class->container_class;
463         else
464                 method_container_class = ji->method->klass;
465
466         /* class might refer to a subclass of ji->method's class */
467         while (!(class == ji->method->klass || (class->generic_class && class->generic_class->container_class == method_container_class))) {
468                 class = class->parent;
469                 g_assert (class);
470         }
471
472         if (class->generic_class || class->generic_container)
473                 context.class_inst = mini_class_get_context (class)->class_inst;
474
475         if (class->generic_class)
476                 g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class->container_class, method_container_class));
477         else
478                 g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class));
479
480         return context;
481 }
482
483 static MonoMethod*
484 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
485 {
486         MonoGenericContext context;
487         MonoMethod *method;
488         
489         if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
490                 return ji->method;
491         context = get_generic_context_from_stack_frame (ji, generic_info);
492
493         method = mono_method_get_declaring_generic_method (ji->method);
494         method = mono_class_inflate_generic_method (method, &context);
495
496         return method;
497 }
498
499 MonoString *
500 ves_icall_System_Exception_get_trace (MonoException *ex)
501 {
502         MonoDomain *domain = mono_domain_get ();
503         MonoString *res;
504         MonoArray *ta = ex->trace_ips;
505         int i, len;
506         GString *trace_str;
507
508         if (ta == NULL)
509                 /* Exception is not thrown yet */
510                 return NULL;
511
512         len = mono_array_length (ta) >> 1;
513         trace_str = g_string_new ("");
514         for (i = 0; i < len; i++) {
515                 MonoJitInfo *ji;
516                 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
517                 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
518
519                 ji = mono_jit_info_table_find (domain, ip);
520                 if (ji == NULL) {
521                         /* Unmanaged frame */
522                         g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
523                 } else {
524                         gchar *location;
525                         gint32 address;
526                         MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
527
528                         address = (char *)ip - (char *)ji->code_start;
529                         location = mono_debug_print_stack_frame (
530                                 method, address, ex->object.vtable->domain);
531
532                         g_string_append_printf (trace_str, "%s\n", location);
533                         g_free (location);
534                 }
535         }
536
537         res = mono_string_new (ex->object.vtable->domain, trace_str->str);
538         g_string_free (trace_str, TRUE);
539
540         return res;
541 }
542
543 MonoArray *
544 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
545 {
546         MonoDomain *domain = mono_domain_get ();
547         MonoArray *res;
548         MonoArray *ta = exc->trace_ips;
549         MonoDebugSourceLocation *location;
550         int i, len;
551
552         if (ta == NULL) {
553                 /* Exception is not thrown yet */
554                 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
555         }
556
557         len = mono_array_length (ta) >> 1;
558
559         res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
560
561         for (i = skip; i < len; i++) {
562                 MonoJitInfo *ji;
563                 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
564                 gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
565                 gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
566                 MonoMethod *method;
567
568                 ji = mono_jit_info_table_find (domain, ip);
569                 if (ji == NULL) {
570                         /* Unmanaged frame */
571                         mono_array_setref (res, i, sf);
572                         continue;
573                 }
574
575                 g_assert (ji != NULL);
576
577                 method = get_method_from_stack_frame (ji, generic_info);
578                 if (ji->method->wrapper_type) {
579                         char *s;
580
581                         sf->method = NULL;
582                         s = mono_method_full_name (method, TRUE);
583                         MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
584                         g_free (s);
585                 }
586                 else
587                         MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
588                 sf->native_offset = (char *)ip - (char *)ji->code_start;
589
590                 /*
591                  * mono_debug_lookup_source_location() returns both the file / line number information
592                  * and the IL offset.  Note that computing the IL offset is already an expensive
593                  * operation, so we shouldn't call this method twice.
594                  */
595                 location = mono_debug_lookup_source_location (ji->method, sf->native_offset, domain);
596                 if (location)
597                         sf->il_offset = location->il_offset;
598                 else
599                         sf->il_offset = 0;
600
601                 if (need_file_info) {
602                         if (location && location->source_file) {
603                                 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
604                                 sf->line = location->row;
605                                 sf->column = location->column;
606                         } else {
607                                 sf->line = sf->column = 0;
608                                 sf->filename = NULL;
609                         }
610                 }
611
612                 mono_debug_free_source_location (location);
613                 mono_array_setref (res, i, sf);
614         }
615
616         return res;
617 }
618
619 typedef struct {
620         MonoStackWalk func;
621         gpointer user_data;
622 } StackWalkUserData;
623
624 static gboolean
625 stack_walk_adapter (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
626 {
627         StackWalkUserData *d = data;
628
629         switch (frame->type) {
630         case FRAME_TYPE_DEBUGGER_INVOKE:
631         case FRAME_TYPE_MANAGED_TO_NATIVE:
632                 return FALSE;
633         case FRAME_TYPE_MANAGED:
634                 g_assert (frame->ji);
635                 return d->func (frame->ji->method, frame->native_offset, frame->il_offset, frame->managed, d->user_data);
636                 break;
637         default:
638                 g_assert_not_reached ();
639                 return FALSE;
640         }
641 }
642
643 void
644 mono_jit_walk_stack_from_ctx (MonoStackWalk func, MonoContext *start_ctx, gboolean do_il_offset, gpointer user_data)
645 {
646         StackWalkUserData d;
647
648         d.func = func;
649         d.user_data = user_data;
650
651         mono_walk_stack (stack_walk_adapter, mono_domain_get (), start_ctx, do_il_offset, mono_thread_internal_current (), mono_get_lmf (), &d);
652 }
653
654 void
655 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data)
656 {
657         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
658
659         if (jit_tls && jit_tls->orig_ex_ctx_set)
660                 mono_jit_walk_stack_from_ctx (func, &jit_tls->orig_ex_ctx, do_il_offset, user_data);
661         else
662                 mono_jit_walk_stack_from_ctx (func, NULL, do_il_offset, user_data);
663 }
664
665 /**
666  * mono_walk_stack:
667  * @func: callback to call for each stack frame
668  * @domain: starting appdomain, can be NULL to use the current domain
669  * @do_il_offsets: whenever to compute IL offsets
670  * @start_ctx: starting state of the stack walk, can be NULL.
671  * @thread: the thread whose stack to walk, can be NULL to use the current thread
672  * @lmf: the LMF of @thread, can be NULL to use the LMF of the current thread
673  * @user_data: data passed to the callback
674  *
675  * This function walks the stack of a thread, starting from the state
676  * represented by start_ctx. For each frame the callback
677  * function is called with the relevant info. The walk ends when no more
678  * managed stack frames are found or when the callback returns a TRUE value.
679  */
680 void
681 mono_walk_stack (MonoJitStackWalk func, MonoDomain *domain, MonoContext *start_ctx, gboolean do_il_offset, MonoInternalThread *thread, MonoLMF *lmf, gpointer user_data)
682 {
683         MonoJitTlsData *jit_tls;
684         gint il_offset;
685         MonoContext ctx, new_ctx;
686         StackFrameInfo frame;
687         gboolean res;
688         
689         MONO_ARCH_CONTEXT_DEF
690
691         mono_arch_flush_register_windows ();
692
693         if (!thread) {
694                 thread = mono_thread_internal_current ();
695                 lmf = mono_get_lmf ();
696         }
697
698         /* A NULL thread->jit_data can happen in a small window during thread startup: the thread
699          * allocation happens, we do a stack walk (for example with
700          * --profile=log:nocalls and xsp) but the jit is not fully setup for the thread
701          *  yet. Of course there are no stack frames, so just returning is ok.
702          *  A NULL thread can happen during domain unload with the same test.
703          */
704         if (!thread || !thread->jit_data)
705                 return;
706         jit_tls = thread->jit_data;
707
708         if (start_ctx) {
709                 memcpy (&ctx, start_ctx, sizeof (MonoContext));
710         } else {
711 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
712                 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
713 #else
714                 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_jit_walk_stack_from_ctx);
715 #endif
716                 g_assert (thread == mono_thread_internal_current ());
717         }
718
719         while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
720                 frame.lmf = lmf;
721                 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
722                 if (!res)
723                         return;
724
725                 if (do_il_offset && frame.ji) {
726                         MonoDebugSourceLocation *source;
727
728                         source = mono_debug_lookup_source_location (frame.ji->method, frame.native_offset, domain);
729                         il_offset = source ? source->il_offset : -1;
730                         mono_debug_free_source_location (source);
731                 } else
732                         il_offset = -1;
733
734                 frame.il_offset = il_offset;
735
736                 if (frame.ji) {
737                         frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
738                 } else {
739                         frame.actual_method = frame.method;
740                 }
741
742                 if (func (&frame, &ctx, user_data))
743                         return;
744                 
745                 ctx = new_ctx;
746         }
747 }
748
749 MonoBoolean
750 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
751                           MonoReflectionMethod **method, 
752                           gint32 *iloffset, gint32 *native_offset,
753                           MonoString **file, gint32 *line, gint32 *column)
754 {
755         MonoDomain *domain = mono_domain_get ();
756         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
757         MonoLMF *lmf = mono_get_lmf ();
758         MonoJitInfo *ji = NULL;
759         MonoContext ctx, new_ctx;
760         MonoDebugSourceLocation *location;
761         MonoMethod *actual_method;
762         StackFrameInfo frame;
763         gboolean res;
764
765         MONO_ARCH_CONTEXT_DEF;
766
767         mono_arch_flush_register_windows ();
768
769 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
770         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
771 #else
772         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
773 #endif
774
775         new_ctx = ctx;
776         do {
777                 ctx = new_ctx;
778                 res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
779                 if (!res)
780                         return FALSE;
781
782                 if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || frame.type == FRAME_TYPE_DEBUGGER_INVOKE)
783                         continue;
784
785                 ji = frame.ji;
786                 *native_offset = frame.native_offset;
787
788                 /* skip all wrappers ??*/
789                 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
790                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
791                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
792                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
793                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE ||
794                         ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
795                         continue;
796
797                 skip--;
798         } while (skip >= 0);
799
800         actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
801
802         mono_gc_wbarrier_generic_store (method, (MonoObject*) mono_method_get_object (domain, actual_method, NULL));
803
804         location = mono_debug_lookup_source_location (ji->method, *native_offset, domain);
805         if (location)
806                 *iloffset = location->il_offset;
807         else
808                 *iloffset = 0;
809
810         if (need_file_info) {
811                 if (location) {
812                         mono_gc_wbarrier_generic_store (file, (MonoObject*) mono_string_new (domain, location->source_file));
813                         *line = location->row;
814                         *column = location->column;
815                 } else {
816                         *file = NULL;
817                         *line = *column = 0;
818                 }
819         }
820
821         mono_debug_free_source_location (location);
822
823         return TRUE;
824 }
825
826 typedef struct {
827         guint32 skips;
828         MonoSecurityFrame *frame;
829 } MonoFrameSecurityInfo;
830
831 static gboolean
832 callback_get_first_frame_security_info (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
833 {
834         MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
835         MonoJitInfo *ji = frame->ji;
836
837         if (!ji)
838                 return FALSE;
839
840         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
841         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
842             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
843             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
844             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
845             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
846                 return FALSE;
847         }
848
849         if (si->skips > 0) {
850                 si->skips--;
851                 return FALSE;
852         }
853
854         si->frame = mono_declsec_create_frame (frame->domain, ji);
855
856         /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
857         return TRUE;
858 }
859
860 /**
861  * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
862  * @skip: the number of stack frames to skip
863  *
864  * This function returns a the security informations of a single stack frame 
865  * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
866  * and [NonCas]InheritanceDemand[Choice] as only the caller security is 
867  * evaluated.
868  */
869 MonoSecurityFrame*
870 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
871 {
872         MonoDomain *domain = mono_domain_get ();
873         MonoFrameSecurityInfo si;
874
875         si.skips = skip;
876         si.frame = NULL;
877
878         mono_walk_stack (callback_get_first_frame_security_info, domain, NULL, FALSE, NULL, NULL, &si);
879
880         return (si.skips == 0) ? si.frame : NULL;
881 }
882
883
884 typedef struct {
885         guint32 skips;
886         MonoArray *stack;
887         guint32 count;
888         guint32 maximum;
889 } MonoSecurityStack;
890
891 static void
892 grow_array (MonoSecurityStack *stack)
893 {
894         MonoDomain *domain = mono_domain_get ();
895         guint32 newsize = (stack->maximum << 1);
896         MonoArray *newstack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, newsize);
897         int i;
898         for (i=0; i < stack->maximum; i++) {
899                 gpointer frame = mono_array_get (stack->stack, gpointer, i);
900                 mono_array_setref (newstack, i, frame);
901         }
902         stack->maximum = newsize;
903         stack->stack = newstack;
904 }
905
906 static gboolean
907 callback_get_stack_frames_security_info (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
908 {
909         MonoSecurityStack *ss = (MonoSecurityStack*) data;
910         MonoJitInfo *ji = frame->ji;
911
912         if (!ji)
913                 return FALSE;
914
915         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
916         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
917             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
918             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
919             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
920             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
921                 return FALSE;
922         }
923
924         if (ss->skips > 0) {
925                 ss->skips--;
926                 return FALSE;
927         }
928
929         if (ss->count == ss->maximum)
930                 grow_array (ss);
931
932         mono_array_setref (ss->stack, ss->count++, mono_declsec_create_frame (frame->domain, ji));
933
934         /* continue down the stack */
935         return FALSE;
936 }
937
938 static MonoArray *
939 glist_to_array (GList *list, MonoClass *eclass) 
940 {
941         MonoDomain *domain = mono_domain_get ();
942         MonoArray *res;
943         int len, i;
944
945         if (!list)
946                 return NULL;
947
948         len = g_list_length (list);
949         res = mono_array_new (domain, eclass, len);
950
951         for (i = 0; list; list = list->next, i++)
952                 mono_array_set (res, gpointer, i, list->data);
953
954         return res;
955 }
956
957 /**
958  * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
959  * @skip: the number of stack frames to skip
960  *
961  * This function returns an managed array of containing the security
962  * informations for each frame (after the skipped ones). This is used for
963  * [NonCas]Demand[Choice] where the complete evaluation of the stack is 
964  * required.
965  */
966 MonoArray*
967 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
968 {
969         MonoDomain *domain = mono_domain_get ();
970         MonoSecurityStack ss;
971
972 #if     defined(__ia64__) || defined(__s390__) || defined(__s390x__)
973         skip--;
974 #endif
975
976         ss.skips = skip;
977         ss.count = 0;
978         ss.maximum = MONO_CAS_INITIAL_STACK_SIZE;
979         ss.stack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, ss.maximum);
980         mono_walk_stack (callback_get_stack_frames_security_info, domain, NULL, FALSE, NULL, NULL, &ss);
981         /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
982         return ss.stack;
983 }
984
985 static MonoClass*
986 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
987 {
988         MonoClass *catch_class = ei->data.catch_class;
989         MonoType *inflated_type;
990         MonoGenericContext context;
991
992         /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
993         if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
994                 return NULL;
995
996         if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
997                 return catch_class;
998         context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
999
1000         /* FIXME: we shouldn't inflate but instead put the
1001            type in the rgctx and fetch it from there.  It
1002            might be a good idea to do this lazily, i.e. only
1003            when the exception is actually thrown, so as not to
1004            waste space for exception clauses which might never
1005            be encountered. */
1006         inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
1007         catch_class = mono_class_from_mono_type (inflated_type);
1008         mono_metadata_free_type (inflated_type);
1009
1010         return catch_class;
1011 }
1012
1013 /*
1014  * mini_jit_info_table_find:
1015  *
1016  *   Same as mono_jit_info_table_find, but search all the domains of the current thread
1017  * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1018  * OUT_DOMAIN if it is not NULL.
1019  */
1020 MonoJitInfo*
1021 mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
1022 {
1023         MonoJitInfo *ji;
1024         MonoInternalThread *t = mono_thread_internal_current ();
1025         GSList *l;
1026
1027         if (out_domain)
1028                 *out_domain = NULL;
1029
1030         ji = mono_jit_info_table_find (domain, addr);
1031         if (ji) {
1032                 if (out_domain)
1033                         *out_domain = domain;
1034                 return ji;
1035         }
1036
1037         /* maybe it is shared code, so we also search in the root domain */
1038         if (domain != mono_get_root_domain ()) {
1039                 ji = mono_jit_info_table_find (mono_get_root_domain (), addr);
1040                 if (ji) {
1041                         if (out_domain)
1042                                 *out_domain = mono_get_root_domain ();
1043                         return ji;
1044                 }
1045         }
1046
1047         for (l = t->appdomain_refs; l; l = l->next) {
1048                 if (l->data != domain) {
1049                         ji = mono_jit_info_table_find ((MonoDomain*)l->data, addr);
1050                         if (ji) {
1051                                 if (out_domain)
1052                                         *out_domain = (MonoDomain*)l->data;
1053                                 return ji;
1054                         }
1055                 }
1056         }
1057
1058         return NULL;
1059 }
1060
1061 /*
1062  * wrap_non_exception_throws:
1063  *
1064  *   Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
1065  * WrapNonExceptionThrows flag set.
1066  */
1067 static gboolean
1068 wrap_non_exception_throws (MonoMethod *m)
1069 {
1070         MonoAssembly *ass = m->klass->image->assembly;
1071         MonoCustomAttrInfo* attrs;
1072         static MonoClass *klass;
1073         int i;
1074         gboolean val = FALSE;
1075
1076         g_assert (ass);
1077         if (ass->wrap_non_exception_throws_inited)
1078                 return ass->wrap_non_exception_throws;
1079
1080         klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1081
1082         attrs = mono_custom_attrs_from_assembly (ass);
1083         if (attrs) {
1084                 for (i = 0; i < attrs->num_attrs; ++i) {
1085                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
1086                         const gchar *p;
1087                         int len, num_named, named_type, data_type, name_len;
1088                         char *name;
1089
1090                         if (!attr->ctor || attr->ctor->klass != klass)
1091                                 continue;
1092                         /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
1093                         len = attr->data_size;
1094                         p = (const char*)attr->data;
1095                         g_assert (read16 (p) == 0x0001);
1096                         p += 2;
1097                         num_named = read16 (p);
1098                         if (num_named != 1)
1099                                 continue;
1100                         p += 2;
1101                         named_type = *p;
1102                         p ++;
1103                         data_type = *p;
1104                         p ++;
1105                         /* Property */
1106                         if (named_type != 0x54)
1107                                 continue;
1108                         name_len = mono_metadata_decode_blob_size (p, &p);
1109                         name = g_malloc (name_len + 1);
1110                         memcpy (name, p, name_len);
1111                         name [name_len] = 0;
1112                         p += name_len;
1113                         g_assert (!strcmp (name, "WrapNonExceptionThrows"));
1114                         g_free (name);
1115                         /* The value is a BOOLEAN */
1116                         val = *p;
1117                 }
1118                 mono_custom_attrs_free (attrs);
1119         }
1120
1121         ass->wrap_non_exception_throws = val;
1122         mono_memory_barrier ();
1123         ass->wrap_non_exception_throws_inited = TRUE;
1124
1125         return val;
1126 }
1127
1128 #ifndef MONO_ARCH_STACK_GROWS_UP
1129 #define DOES_STACK_GROWS_UP 1
1130 #else
1131 #define DOES_STACK_GROWS_UP 0
1132 #endif
1133
1134 /*
1135  * mono_handle_exception_internal_first_pass:
1136  *
1137  *   The first pass of exception handling. Unwind the stack until a catch clause which can catch
1138  * OBJ is found. Run the index of the filter clause which caught the exception into
1139  * OUT_FILTER_IDX. Return TRUE if the exception is caught, FALSE otherwise.
1140  */
1141 static gboolean
1142 mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gpointer original_ip, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoObject *non_exception)
1143 {
1144         MonoDomain *domain = mono_domain_get ();
1145         MonoJitInfo *ji;
1146         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1147         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1148         MonoLMF *lmf = mono_get_lmf ();
1149         MonoArray *initial_trace_ips = NULL;
1150         GList *trace_ips = NULL;
1151         MonoException *mono_ex;
1152         gboolean stack_overflow = FALSE;
1153         MonoContext initial_ctx;
1154         int frame_count = 0;
1155         gboolean has_dynamic_methods = FALSE;
1156         gint32 filter_idx;
1157         int i;
1158         MonoObject *ex_obj;
1159
1160         g_assert (ctx != NULL);
1161
1162         if (obj == domain->stack_overflow_ex)
1163                 stack_overflow = TRUE;
1164
1165         mono_ex = (MonoException*)obj;
1166         initial_trace_ips = mono_ex->trace_ips;
1167
1168         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1169                 mono_ex = (MonoException*)obj;
1170                 initial_trace_ips = mono_ex->trace_ips;
1171         } else {
1172                 mono_ex = NULL;
1173         }
1174
1175         if (!call_filter)
1176                 call_filter = mono_get_call_filter ();
1177
1178         g_assert (jit_tls->end_of_stack);
1179         g_assert (jit_tls->abort_func);
1180
1181         if (out_filter_idx)
1182                 *out_filter_idx = -1;
1183         if (out_ji)
1184                 *out_ji = NULL;
1185         filter_idx = 0;
1186         initial_ctx = *ctx;
1187
1188         while (1) {
1189                 MonoContext new_ctx;
1190                 guint32 free_stack;
1191                 int clause_index_start = 0;
1192                 gboolean unwind_res = TRUE;
1193                 
1194                 StackFrameInfo frame;
1195
1196                 unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1197                 if (unwind_res) {
1198                         if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
1199                                 *ctx = new_ctx;
1200                                 continue;
1201                         }
1202                         g_assert (frame.type == FRAME_TYPE_MANAGED);
1203                         ji = frame.ji;
1204                 }
1205
1206                 if (!unwind_res) {
1207                         if (mono_ex && !initial_trace_ips) {
1208                                 trace_ips = g_list_reverse (trace_ips);
1209                                 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1210                                 if (has_dynamic_methods)
1211                                         /* These methods could go away anytime, so compute the stack trace now */
1212                                         MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1213                         }
1214                         g_list_free (trace_ips);
1215                         return FALSE;
1216                 }
1217
1218                 frame_count ++;
1219                 //printf ("M: %s %d.\n", mono_method_full_name (ji->method, TRUE), frame_count);
1220
1221                 if (mini_get_debug_options ()->reverse_pinvoke_exceptions && ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
1222                         g_error ("A native frame was found while unwinding the stack after an exception.\n"
1223                                          "The native frame called the managed method:\n%s\n",
1224                                          mono_method_full_name (ji->method, TRUE));
1225                 }
1226
1227                 if (ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1228                         /* 
1229                          * Avoid overwriting the stack trace if the exception is
1230                          * rethrown. Also avoid giant stack traces during a stack
1231                          * overflow.
1232                          */
1233                         if (!initial_trace_ips && (frame_count < 1000)) {
1234                                 trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1235                                 trace_ips = g_list_prepend (trace_ips,
1236                                                                                         get_generic_info_from_stack_frame (ji, ctx));
1237                         }
1238                 }
1239
1240                 if (ji->method->dynamic)
1241                         has_dynamic_methods = TRUE;
1242
1243                 if (stack_overflow) {
1244                         if (DOES_STACK_GROWS_UP)
1245                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1246                         else
1247                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1248                 } else {
1249                         free_stack = 0xffffff;
1250                 }
1251                                 
1252                 for (i = clause_index_start; i < ji->num_clauses; i++) {
1253                         MonoJitExceptionInfo *ei = &ji->clauses [i];
1254                         gboolean filtered = FALSE;
1255
1256                         /* 
1257                          * During stack overflow, wait till the unwinding frees some stack
1258                          * space before running handlers/finalizers.
1259                          */
1260                         if (free_stack <= (64 * 1024))
1261                                 continue;
1262
1263                         if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1264                                 /* catch block */
1265                                 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1266
1267                                 /*
1268                                  * Have to unwrap RuntimeWrappedExceptions if the
1269                                  * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1270                                  */
1271                                 if (non_exception && !wrap_non_exception_throws (ji->method))
1272                                         ex_obj = non_exception;
1273                                 else
1274                                         ex_obj = obj;
1275
1276                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1277                                         mono_perfcounters->exceptions_filters++;
1278                                         mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1279                                         if (mono_ex && !initial_trace_ips) {
1280                                                 trace_ips = g_list_reverse (trace_ips);
1281                                                 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1282
1283                                                 if (has_dynamic_methods)
1284                                                         /* These methods could go away anytime, so compute the stack trace now */
1285                                                         MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1286                                         }
1287                                         g_list_free (trace_ips);
1288                                         trace_ips = NULL;
1289
1290                                         if (ji->from_llvm) {
1291 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1292                                                 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1293 #else
1294                                                 g_assert_not_reached ();
1295 #endif
1296                                         } else {
1297                                                 /* store the exception object in bp + ei->exvar_offset */
1298                                                 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1299                                         }
1300
1301                                         mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx);
1302                                         filtered = call_filter (ctx, ei->data.filter);
1303                                         mono_debugger_agent_end_exception_filter (mono_ex, ctx, &initial_ctx);
1304                                         if (filtered && out_filter_idx)
1305                                                 *out_filter_idx = filter_idx;
1306                                         if (out_ji)
1307                                                 *out_ji = ji;
1308                                         filter_idx ++;
1309
1310                                         if (filtered) {
1311                                                 /* mono_debugger_agent_handle_exception () needs this */
1312                                                 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1313                                                 return TRUE;
1314                                         }
1315                                 }
1316
1317                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (ex_obj, catch_class)) {
1318                                         if (mono_ex && !initial_trace_ips) {
1319                                                 trace_ips = g_list_reverse (trace_ips);
1320                                                 MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1321                                                 if (has_dynamic_methods)
1322                                                         /* These methods could go away anytime, so compute the stack trace now */
1323                                                         MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1324                                         }
1325                                         g_list_free (trace_ips);
1326
1327                                         /* mono_debugger_agent_handle_exception () needs this */
1328                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1329                                         return TRUE;
1330                                 }
1331                         }
1332                 }
1333
1334                 *ctx = new_ctx;
1335         }
1336
1337         g_assert_not_reached ();
1338 }
1339
1340 /**
1341  * mono_handle_exception_internal:
1342  * @ctx: saved processor state
1343  * @obj: the exception object
1344  * @resume: whenever to resume unwinding based on the state in MonoJitTlsData.
1345  */
1346 static gboolean
1347 mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean resume, MonoJitInfo **out_ji)
1348 {
1349         MonoDomain *domain = mono_domain_get ();
1350         MonoJitInfo *ji;
1351         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1352         static void (*restore_context) (void *);
1353         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1354         MonoLMF *lmf = mono_get_lmf ();
1355         MonoException *mono_ex;
1356         gboolean stack_overflow = FALSE;
1357         MonoContext initial_ctx;
1358         int frame_count = 0;
1359         gint32 filter_idx, first_filter_idx;
1360         int i;
1361         MonoObject *ex_obj;
1362         MonoObject *non_exception = NULL;
1363
1364         g_assert (ctx != NULL);
1365         if (!obj) {
1366                 MonoException *ex = mono_get_exception_null_reference ();
1367                 MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object"));
1368                 obj = (MonoObject *)ex;
1369         } 
1370
1371         /*
1372          * Allocate a new exception object instead of the preconstructed ones.
1373          */
1374         if (obj == domain->stack_overflow_ex) {
1375                 /*
1376                  * It is not a good idea to try and put even more pressure on the little stack available.
1377                  * obj = mono_get_exception_stack_overflow ();
1378                  */
1379                 stack_overflow = TRUE;
1380         }
1381         else if (obj == domain->null_reference_ex) {
1382                 obj = mono_get_exception_null_reference ();
1383         }
1384
1385         if (!mono_object_isinst (obj, mono_defaults.exception_class)) {
1386                 non_exception = obj;
1387                 obj = mono_get_exception_runtime_wrapped (obj);
1388         }
1389
1390         mono_ex = (MonoException*)obj;
1391
1392         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1393                 mono_ex = (MonoException*)obj;
1394         } else {
1395                 mono_ex = NULL;
1396         }
1397
1398         if (mono_ex && jit_tls->class_cast_from) {
1399                 if (!strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) {
1400                         char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1401                         char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1402                         char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
1403                         mono_ex->message = mono_string_new (domain, msg);
1404                         g_free (from_name);
1405                         g_free (to_name);
1406                         g_free (msg);
1407                 }
1408                 if (!strcmp (mono_ex->object.vtable->klass->name, "ArrayTypeMismatchException")) {
1409                         char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1410                         char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1411                         char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
1412                         mono_ex->message = mono_string_new (domain, msg);
1413                         g_free (from_name);
1414                         g_free (to_name);
1415                         g_free (msg);
1416                 }
1417         }
1418
1419         if (!call_filter)
1420                 call_filter = mono_get_call_filter ();
1421
1422         if (!restore_context)
1423                 restore_context = mono_get_restore_context ();
1424
1425         g_assert (jit_tls->end_of_stack);
1426         g_assert (jit_tls->abort_func);
1427
1428         /*
1429          * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
1430          * end up being TRUE on any code path.
1431          */
1432         memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
1433
1434         if (!resume) {
1435                 gboolean res;
1436
1437                 MonoContext ctx_cp = *ctx;
1438                 if (mono_trace_is_enabled ()) {
1439                         MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0);
1440                         MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message);
1441                         MonoObject *message;
1442                         const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
1443                         char *msg = NULL;
1444                         MonoObject *exc = NULL;
1445                         if (get_message == NULL) {
1446                                 message = NULL;
1447                         } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
1448                                 message = NULL;
1449                                 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
1450                         } else {
1451                                 message = mono_runtime_invoke (get_message, obj, NULL, &exc);
1452                                 
1453                         }
1454                         if (msg == NULL) {
1455                                 msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
1456                         }
1457                         g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
1458                         g_free (msg);
1459                         if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
1460                                 mono_print_thread_dump_from_ctx (ctx);
1461                 }
1462                 jit_tls->orig_ex_ctx_set = TRUE;
1463                 mono_profiler_exception_thrown (obj);
1464                 jit_tls->orig_ex_ctx_set = FALSE;
1465
1466                 res = mono_handle_exception_internal_first_pass (&ctx_cp, obj, original_ip, &first_filter_idx, out_ji, non_exception);
1467
1468                 if (!res) {
1469                         if (mono_break_on_exc)
1470                                 G_BREAKPOINT ();
1471                         mono_debugger_agent_handle_exception (obj, ctx, NULL);
1472                         // FIXME: This runs managed code so it might cause another stack overflow when
1473                         // we are handling a stack overflow
1474                         mono_unhandled_exception (obj);
1475                 } else {
1476                         mono_debugger_agent_handle_exception (obj, ctx, &ctx_cp);
1477                 }
1478         }
1479
1480         if (out_ji)
1481                 *out_ji = NULL;
1482         filter_idx = 0;
1483         initial_ctx = *ctx;
1484
1485         while (1) {
1486                 MonoContext new_ctx;
1487                 guint32 free_stack;
1488                 int clause_index_start = 0;
1489                 gboolean unwind_res = TRUE;
1490                 
1491                 if (resume) {
1492                         resume = FALSE;
1493                         ji = jit_tls->resume_state.ji;
1494                         new_ctx = jit_tls->resume_state.new_ctx;
1495                         clause_index_start = jit_tls->resume_state.clause_index;
1496                         lmf = jit_tls->resume_state.lmf;
1497                         first_filter_idx = jit_tls->resume_state.first_filter_idx;
1498                         filter_idx = jit_tls->resume_state.filter_idx;
1499                 } else {
1500                         StackFrameInfo frame;
1501
1502                         unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1503                         if (unwind_res) {
1504                                 if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
1505                                         *ctx = new_ctx;
1506                                         continue;
1507                                 }
1508                                 g_assert (frame.type == FRAME_TYPE_MANAGED);
1509                                 ji = frame.ji;
1510                         }
1511                 }
1512
1513                 if (!unwind_res) {
1514                         *(mono_get_lmf_addr ()) = lmf;
1515
1516                         jit_tls->abort_func (obj);
1517                         g_assert_not_reached ();
1518                 }
1519
1520                 frame_count ++;
1521                 //printf ("M: %s %d.\n", mono_method_full_name (ji->method, TRUE), frame_count);
1522
1523                 if (stack_overflow) {
1524                         if (DOES_STACK_GROWS_UP)
1525                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1526                         else
1527                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
1528                 } else {
1529                         free_stack = 0xffffff;
1530                 }
1531                                 
1532                 for (i = clause_index_start; i < ji->num_clauses; i++) {
1533                         MonoJitExceptionInfo *ei = &ji->clauses [i];
1534                         gboolean filtered = FALSE;
1535
1536                         /* 
1537                          * During stack overflow, wait till the unwinding frees some stack
1538                          * space before running handlers/finalizers.
1539                          */
1540                         if (free_stack <= (64 * 1024))
1541                                 continue;
1542
1543                         if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) {
1544                                 /* catch block */
1545                                 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1546
1547                                 /*
1548                                  * Have to unwrap RuntimeWrappedExceptions if the
1549                                  * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1550                                  */
1551                                 if (non_exception && !wrap_non_exception_throws (ji->method))
1552                                         ex_obj = non_exception;
1553                                 else
1554                                         ex_obj = obj;
1555
1556                                 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
1557                                         if (ji->from_llvm) {
1558 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1559                                                 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1560 #else
1561                                                 g_assert_not_reached ();
1562 #endif
1563                                         } else {
1564                                                 /* store the exception object in bp + ei->exvar_offset */
1565                                                 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1566                                         }
1567                                 }
1568
1569                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1570                                         /* 
1571                                          * Filter clauses should only be run in the 
1572                                          * first pass of exception handling.
1573                                          */
1574                                         filtered = (filter_idx == first_filter_idx);
1575                                         filter_idx ++;
1576                                 }
1577
1578                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
1579                                          mono_object_isinst (ex_obj, catch_class)) || filtered) {
1580                                         /*
1581                                          * This guards against the situation that we abort a thread that is executing a finally clause
1582                                          * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
1583                                          * check for this situation here and resume interruption if we are below the guarded block.
1584                                          */
1585                                         if (G_UNLIKELY (jit_tls->handler_block_return_address)) {
1586                                                 gboolean is_outside = FALSE;
1587                                                 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
1588                                                 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
1589                                                 //FIXME make this stack direction aware
1590                                                 if (catch_bp > prot_bp) {
1591                                                         is_outside = TRUE;
1592                                                 } else if (catch_bp == prot_bp) {
1593                                                         /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
1594                                                          * So we check if the catch handler_start is protected by the guarded handler protected region
1595                                                          *
1596                                                          * Assumptions:
1597                                                          *      If there is an outstanding guarded_block return address, it means the current thread must be aborted.
1598                                                          *      This is the only way to reach out the guarded block as other cases are handled by the trampoline.
1599                                                          *      There aren't any further finally/fault handler blocks down the stack over this exception.
1600                                                          *   This must be ensured by the code that installs the guard trampoline.
1601                                                          */
1602                                                         g_assert (ji == mini_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
1603
1604                                                         if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
1605                                                                 is_outside = TRUE;
1606                                                         }
1607                                                 }
1608                                                 if (is_outside) {
1609                                                         jit_tls->handler_block_return_address = NULL;
1610                                                         jit_tls->handler_block = NULL;
1611                                                         mono_thread_resume_interruption (); /*We ignore the exception here, it will be raised later*/
1612                                                 }
1613                                         }
1614
1615                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1616                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1617                                         jit_tls->orig_ex_ctx_set = TRUE;
1618                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1619                                         jit_tls->orig_ex_ctx_set = FALSE;
1620                                         mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1621                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1622                                         *(mono_get_lmf_addr ()) = lmf;
1623                                         mono_perfcounters->exceptions_depth += frame_count;
1624                                         if (obj == domain->stack_overflow_ex)
1625                                                 jit_tls->handling_stack_ovf = FALSE;
1626
1627                                         return 0;
1628                                 }
1629                                 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1630                                         (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
1631                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1632                                                 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1633                                         jit_tls->orig_ex_ctx_set = TRUE;
1634                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1635                                         jit_tls->orig_ex_ctx_set = FALSE;
1636                                         mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1637                                         call_filter (ctx, ei->handler_start);
1638                                 }
1639                                 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
1640                                         (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
1641                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1642                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1643                                         jit_tls->orig_ex_ctx_set = TRUE;
1644                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1645                                         jit_tls->orig_ex_ctx_set = FALSE;
1646                                         mono_debugger_call_exception_handler (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), ex_obj);
1647                                         mono_perfcounters->exceptions_finallys++;
1648                                         *(mono_get_lmf_addr ()) = lmf;
1649                                         if (ji->from_llvm) {
1650                                                 /* 
1651                                                  * LLVM compiled finally handlers follow the design
1652                                                  * of the c++ ehabi, i.e. they call a resume function
1653                                                  * at the end instead of returning to the caller.
1654                                                  * So save the exception handling state,
1655                                                  * mono_resume_unwind () will call us again to continue
1656                                                  * the unwinding.
1657                                                  */
1658                                                 jit_tls->resume_state.ex_obj = obj;
1659                                                 jit_tls->resume_state.ji = ji;
1660                                                 jit_tls->resume_state.clause_index = i + 1;
1661                                                 jit_tls->resume_state.ctx = *ctx;
1662                                                 jit_tls->resume_state.new_ctx = new_ctx;
1663                                                 jit_tls->resume_state.lmf = lmf;
1664                                                 jit_tls->resume_state.first_filter_idx = first_filter_idx;
1665                                                 jit_tls->resume_state.filter_idx = filter_idx;
1666                                                 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1667                                                 return 0;
1668                                         } else {
1669                                                 call_filter (ctx, ei->handler_start);
1670                                         }
1671                                 }
1672                         }
1673                 }
1674
1675                 jit_tls->orig_ex_ctx_set = TRUE;
1676                 mono_profiler_exception_method_leave (ji->method);
1677                 jit_tls->orig_ex_ctx_set = FALSE;
1678
1679                 *ctx = new_ctx;
1680         }
1681
1682         g_assert_not_reached ();
1683 }
1684
1685 /*
1686  * mono_debugger_handle_exception:
1687  *
1688  *  Notify the debugger about exceptions.  Returns TRUE if the debugger wants us to stop
1689  *  at the exception and FALSE to resume with the normal exception handling.
1690  *
1691  *  The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
1692  *  MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
1693  *  `callq throw' instruction.
1694  */
1695 gboolean
1696 mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
1697 {
1698         MonoDebuggerExceptionAction action;
1699
1700         if (!mono_debug_using_mono_debugger ())
1701                 return FALSE;
1702
1703         if (!obj) {
1704                 MonoException *ex = mono_get_exception_null_reference ();
1705                 MONO_OBJECT_SETREF (ex, message, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
1706                 obj = (MonoObject *)ex;
1707         }
1708
1709         action = _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1710
1711         if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP) {
1712                 /*
1713                  * The debugger wants us to stop on the `throw' instruction.
1714                  * By the time we get here, it already inserted a breakpoint there.
1715                  */
1716                 return TRUE;
1717         } else if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED) {
1718                 MonoContext ctx_cp = *ctx;
1719                 MonoJitInfo *ji = NULL;
1720                 gboolean ret;
1721
1722                 /*
1723                  * The debugger wants us to stop only if this exception is user-unhandled.
1724                  */
1725
1726                 ret = mono_handle_exception_internal_first_pass (&ctx_cp, obj, MONO_CONTEXT_GET_IP (ctx), NULL, &ji, NULL);
1727                 if (ret && (ji != NULL) && (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
1728                         /*
1729                          * The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
1730                          * inside the method being invoked, so we handle it like a user-unhandled exception.
1731                          */
1732                         ret = FALSE;
1733                 }
1734
1735                 if (!ret) {
1736                         /*
1737                          * The exception is user-unhandled - tell the debugger to stop.
1738                          */
1739                         return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
1740                 }
1741
1742                 /*
1743                  * The exception is catched somewhere - resume with the normal exception handling and don't
1744                  * stop in the debugger.
1745                  */
1746         }
1747
1748         return FALSE;
1749 }
1750
1751 /**
1752  * mono_debugger_run_finally:
1753  * @start_ctx: saved processor state
1754  *
1755  * This method is called by the Mono Debugger to call all `finally' clauses of the
1756  * current stack frame.  It's used when the user issues a `return' command to make
1757  * the current stack frame return.  After returning from this method, the debugger
1758  * unwinds the stack one frame and gives control back to the user.
1759  *
1760  * NOTE: This method is only used when running inside the Mono Debugger.
1761  */
1762 void
1763 mono_debugger_run_finally (MonoContext *start_ctx)
1764 {
1765         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1766         MonoDomain *domain = mono_domain_get ();
1767         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1768         MonoLMF *lmf = mono_get_lmf ();
1769         MonoContext ctx, new_ctx;
1770         MonoJitInfo *ji, rji;
1771         int i;
1772
1773         ctx = *start_ctx;
1774
1775         ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1776         if (!ji || ji == (gpointer)-1)
1777                 return;
1778
1779         if (!call_filter)
1780                 call_filter = mono_get_call_filter ();
1781
1782         for (i = 0; i < ji->num_clauses; i++) {
1783                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1784
1785                 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
1786                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1787                         call_filter (&ctx, ei->handler_start);
1788                 }
1789         }
1790 }
1791
1792 /**
1793  * mono_handle_exception:
1794  * @ctx: saved processor state
1795  * @obj: the exception object
1796  * @test_only: only test if the exception is caught, but dont call handlers
1797  */
1798 gboolean
1799 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
1800 {
1801         if (!test_only)
1802                 mono_perfcounters->exceptions_thrown++;
1803
1804         g_assert (!test_only);
1805         return mono_handle_exception_internal (ctx, obj, original_ip, FALSE, NULL);
1806 }
1807
1808 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1809
1810 #ifndef MONO_ARCH_USE_SIGACTION
1811 #error "Can't use sigaltstack without sigaction"
1812 #endif
1813
1814 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
1815
1816 void
1817 mono_setup_altstack (MonoJitTlsData *tls)
1818 {
1819         size_t stsize = 0;
1820         struct sigaltstack sa;
1821         guint8 *staddr = NULL;
1822
1823         if (mono_running_on_valgrind ())
1824                 return;
1825
1826         mono_thread_get_stack_bounds (&staddr, &stsize);
1827
1828         g_assert (staddr);
1829
1830         tls->end_of_stack = staddr + stsize;
1831         tls->stack_size = stsize;
1832
1833         /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1834
1835         tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1836         tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
1837
1838         g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
1839
1840         if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1841                 /* mprotect can fail for the main thread stack */
1842                 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);
1843                 g_assert (gaddr == tls->stack_ovf_guard_base);
1844                 tls->stack_ovf_valloced = TRUE;
1845         }
1846
1847         /* Setup an alternate signal stack */
1848         tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
1849         tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1850
1851         g_assert (tls->signal_stack);
1852
1853         sa.ss_sp = tls->signal_stack;
1854         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1855         sa.ss_flags = SS_ONSTACK;
1856         sigaltstack (&sa, NULL);
1857 }
1858
1859 void
1860 mono_free_altstack (MonoJitTlsData *tls)
1861 {
1862         struct sigaltstack sa;
1863         int err;
1864
1865         sa.ss_sp = tls->signal_stack;
1866         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1867         sa.ss_flags = SS_DISABLE;
1868         err = sigaltstack  (&sa, NULL);
1869         g_assert (err == 0);
1870
1871         if (tls->signal_stack)
1872                 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1873         if (tls->stack_ovf_valloced)
1874                 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size);
1875         else
1876                 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
1877 }
1878
1879 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1880
1881 void
1882 mono_setup_altstack (MonoJitTlsData *tls)
1883 {
1884 }
1885
1886 void
1887 mono_free_altstack (MonoJitTlsData *tls)
1888 {
1889 }
1890
1891 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1892
1893 static gboolean
1894 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
1895 {
1896         gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
1897         /* we need to leave some room for throwing the exception */
1898         while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
1899                 unprotect_size -= mono_pagesize ();
1900         /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
1901          * is sufficient stack
1902          */
1903         //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);
1904         if (unprotect_size)
1905                 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
1906         return unprotect_size == jit_tls->stack_ovf_guard_size;
1907 }
1908
1909 static void
1910 try_more_restore (void)
1911 {
1912         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1913         if (try_restore_stack_protection (jit_tls, 500))
1914                 jit_tls->restore_stack_prot = NULL;
1915 }
1916
1917 static void
1918 restore_stack_protection (void)
1919 {
1920         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1921         MonoException *ex = mono_domain_get ()->stack_overflow_ex;
1922         /* if we can't restore the stack protection, keep a callback installed so
1923          * we'll try to restore as much stack as we can at each return from unmanaged
1924          * code.
1925          */
1926         if (try_restore_stack_protection (jit_tls, 4096))
1927                 jit_tls->restore_stack_prot = NULL;
1928         else
1929                 jit_tls->restore_stack_prot = try_more_restore_tramp;
1930         /* here we also throw a stack overflow exception */
1931         ex->trace_ips = NULL;
1932         ex->stack_trace = NULL;
1933         mono_raise_exception (ex);
1934 }
1935
1936 gpointer
1937 mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
1938 {
1939         void (*func)(void) = (gpointer)tramp_data;
1940         func ();
1941         return NULL;
1942 }
1943
1944 gboolean
1945 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
1946 {
1947         /* we got a stack overflow in the soft-guard pages
1948          * There are two cases:
1949          * 1) managed code caused the overflow: we unprotect the soft-guard page
1950          * and let the arch-specific code trigger the exception handling mechanism
1951          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
1952          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
1953          * and hope we can continue with those enabled, at least until the hard-guard page
1954          * is hit. The alternative to continuing here is to just print a message and abort.
1955          * We may add in the future the code to protect the pages again in the codepath
1956          * when we return from unmanaged to managed code.
1957          */
1958         if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
1959                         fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
1960                 /* we unprotect the minimum amount we can */
1961                 guint32 guard_size;
1962                 gboolean handled = FALSE;
1963
1964                 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
1965                 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
1966                         guard_size -= mono_pagesize ();
1967                 }
1968                 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
1969                 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
1970                 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);
1971 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1972                 if (ji) {
1973                         mono_arch_handle_altstack_exception (ctx, fault_addr, TRUE);
1974                         handled = TRUE;
1975                 }
1976 #endif
1977                 if (!handled) {
1978                         /* We print a message: after this even managed stack overflows
1979                          * may crash the runtime
1980                          */
1981                         fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), fault_addr);
1982                         if (!jit_tls->handling_stack_ovf) {
1983                                 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
1984                                 jit_tls->handling_stack_ovf = 1;
1985                         } else {
1986                                 /*fprintf (stderr, "Already handling stack overflow\n");*/
1987                         }
1988                 }
1989                 return TRUE;
1990         }
1991         return FALSE;
1992 }
1993
1994 static gboolean
1995 print_stack_frame (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed, gpointer data)
1996 {
1997         FILE *stream = (FILE*)data;
1998
1999         if (method) {
2000                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
2001                 fprintf (stream, "  %s\n", location);
2002                 g_free (location);
2003         } else
2004                 fprintf (stream, "  at <unknown> <0x%05x>\n", native_offset);
2005
2006         return FALSE;
2007 }
2008
2009 static G_GNUC_UNUSED gboolean
2010 print_stack_frame_to_string (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed,
2011                              gpointer data)
2012 {
2013         GString *p = (GString*)data;
2014
2015         if (method) {
2016                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
2017                 g_string_append_printf (p, "  %s\n", location);
2018                 g_free (location);
2019         } else
2020                 g_string_append_printf (p, "  at <unknown> <0x%05x>\n", native_offset);
2021
2022         return FALSE;
2023 }
2024
2025 static gboolean handling_sigsegv = FALSE;
2026
2027 /*
2028  * mono_handle_native_sigsegv:
2029  *
2030  *   Handle a SIGSEGV received while in native code by printing diagnostic 
2031  * information and aborting.
2032  */
2033 void
2034 mono_handle_native_sigsegv (int signal, void *ctx)
2035 {
2036 #ifdef MONO_ARCH_USE_SIGACTION
2037         struct sigaction sa;
2038 #endif
2039         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2040
2041         if (handling_sigsegv)
2042                 return;
2043
2044         if (mini_get_debug_options ()->suspend_on_sigsegv) {
2045                 fprintf (stderr, "Received SIGSEGV, suspending...");
2046                 while (1)
2047                         ;
2048         }
2049
2050         /* To prevent infinite loops when the stack walk causes a crash */
2051         handling_sigsegv = TRUE;
2052
2053         /* !jit_tls means the thread was not registered with the runtime */
2054         if (jit_tls && mono_thread_internal_current ()) {
2055                 fprintf (stderr, "Stacktrace:\n\n");
2056
2057                 mono_jit_walk_stack (print_stack_frame, TRUE, stderr);
2058
2059                 fflush (stderr);
2060         }
2061
2062 #ifdef HAVE_BACKTRACE_SYMBOLS
2063  {
2064         void *array [256];
2065         char **names;
2066         int i, size;
2067         const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
2068
2069         fprintf (stderr, "\nNative stacktrace:\n\n");
2070
2071         size = backtrace (array, 256);
2072         names = backtrace_symbols (array, size);
2073         for (i =0; i < size; ++i) {
2074                 fprintf (stderr, "\t%s\n", names [i]);
2075         }
2076         free (names);
2077
2078         fflush (stderr);
2079
2080         /* Try to get more meaningful information using gdb */
2081
2082 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
2083         if (!mini_get_debug_options ()->no_gdb_backtrace && !mono_debug_using_mono_debugger ()) {
2084                 /* From g_spawn_command_line_sync () in eglib */
2085                 int res;
2086                 int stdout_pipe [2] = { -1, -1 };
2087                 pid_t pid;
2088                 int status;
2089                 char buffer [1024];
2090
2091                 res = pipe (stdout_pipe);
2092                 g_assert (res != -1);
2093                         
2094                 //pid = fork ();
2095                 /*
2096                  * glibc fork acquires some locks, so if the crash happened inside malloc/free,
2097                  * it will deadlock. Call the syscall directly instead.
2098                  */
2099                 pid = mono_runtime_syscall_fork ();
2100
2101                 if (pid == 0) {
2102                         close (stdout_pipe [0]);
2103                         dup2 (stdout_pipe [1], STDOUT_FILENO);
2104
2105                         for (i = getdtablesize () - 1; i >= 3; i--)
2106                                 close (i);
2107
2108                         if (!mono_gdb_render_native_backtraces ())
2109                                 close (STDOUT_FILENO);
2110
2111                         exit (1);
2112                 }
2113
2114                 close (stdout_pipe [1]);
2115
2116                 fprintf (stderr, "\nDebug info from gdb:\n\n");
2117
2118                 while (1) {
2119                         int nread = read (stdout_pipe [0], buffer, 1024);
2120
2121                         if (nread <= 0)
2122                                 break;
2123                         write (STDERR_FILENO, buffer, nread);
2124                 }               
2125
2126                 waitpid (pid, &status, WNOHANG);
2127         }
2128 #endif
2129         /*
2130          * A SIGSEGV indicates something went very wrong so we can no longer depend
2131          * on anything working. So try to print out lots of diagnostics, starting 
2132          * with ones which have a greater chance of working.
2133          */
2134         fprintf (stderr,
2135                          "\n"
2136                          "=================================================================\n"
2137                          "Got a %s while executing native code. This usually indicates\n"
2138                          "a fatal error in the mono runtime or one of the native libraries \n"
2139                          "used by your application.\n"
2140                          "=================================================================\n"
2141                          "\n", signal_str);
2142
2143  }
2144 #endif
2145
2146 #ifdef MONO_ARCH_USE_SIGACTION
2147
2148         /* Remove our SIGABRT handler */
2149         sa.sa_handler = SIG_DFL;
2150         sigemptyset (&sa.sa_mask);
2151         sa.sa_flags = 0;
2152
2153         g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
2154
2155 #endif
2156
2157         abort ();
2158 }
2159
2160 static void
2161 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
2162 {
2163         MonoInternalThread *thread = mono_thread_internal_current ();
2164 #if defined(__i386__) || defined(__x86_64__)
2165         MonoContext ctx;
2166 #endif
2167         GString* text = g_string_new (0);
2168         char *name, *wapi_desc;
2169         GError *error = NULL;
2170
2171         if (thread->name) {
2172                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
2173                 g_assert (!error);
2174                 g_string_append_printf (text, "\n\"%s\"", name);
2175                 g_free (name);
2176         }
2177         else if (thread->threadpool_thread)
2178                 g_string_append (text, "\n\"<threadpool thread>\"");
2179         else
2180                 g_string_append (text, "\n\"<unnamed thread>\"");
2181
2182 #ifndef HOST_WIN32
2183         wapi_desc = wapi_current_thread_desc ();
2184         g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread,  wapi_desc);
2185         free (wapi_desc);
2186 #endif
2187
2188 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2189         if (start_ctx) {
2190                 memcpy (&ctx, start_ctx, sizeof (MonoContext));
2191         } else if (!sigctx)
2192                 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
2193         else
2194                 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
2195
2196         mono_jit_walk_stack_from_ctx (print_stack_frame_to_string, &ctx, TRUE, text);
2197 #else
2198         printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
2199 #endif
2200
2201         fprintf (stdout, "%s", text->str);
2202         g_string_free (text, TRUE);
2203         fflush (stdout);
2204 }
2205
2206 /*
2207  * mono_print_thread_dump:
2208  *
2209  *   Print information about the current thread to stdout.
2210  * SIGCTX can be NULL, allowing this to be called from gdb.
2211  */
2212 void
2213 mono_print_thread_dump (void *sigctx)
2214 {
2215         mono_print_thread_dump_internal (sigctx, NULL);
2216 }
2217
2218 void
2219 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2220 {
2221         mono_print_thread_dump_internal (NULL, ctx);
2222 }
2223
2224 /*
2225  * mono_resume_unwind:
2226  *
2227  *   This is called by a trampoline from LLVM compiled finally clauses to continue
2228  * unwinding.
2229  */
2230 void
2231 mono_resume_unwind (MonoContext *ctx)
2232 {
2233         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2234         static void (*restore_context) (MonoContext *);
2235         MonoContext new_ctx;
2236
2237         MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
2238         MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
2239         new_ctx = *ctx;
2240
2241         mono_handle_exception_internal (&new_ctx, jit_tls->resume_state.ex_obj, NULL, TRUE, NULL);
2242
2243         if (!restore_context)
2244                 restore_context = mono_get_restore_context ();
2245
2246         restore_context (&new_ctx);
2247 }
2248
2249 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
2250
2251 typedef struct {
2252         MonoJitInfo *ji;
2253         MonoContext ctx;
2254         MonoJitExceptionInfo *ei;
2255 } FindHandlerBlockData;
2256
2257 static gboolean
2258 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2259 {
2260         int i;
2261         gpointer ip;
2262         FindHandlerBlockData *pdata = data;
2263         MonoJitInfo *ji = frame->ji;
2264
2265         if (!ji)
2266                 return FALSE;
2267
2268         if (ji->method->wrapper_type)
2269                 return FALSE;
2270
2271         ip = MONO_CONTEXT_GET_IP (ctx);
2272
2273         for (i = 0; i < ji->num_clauses; ++i) {
2274                 MonoJitExceptionInfo *ei = ji->clauses + i;
2275                 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2276                         continue;
2277                 /*If ip points to the first instruction it means the handler block didn't start
2278                  so we can leave its execution to the EH machinery*/
2279                 if (ei->handler_start < ip && ip < ei->data.handler_end) {
2280                         pdata->ji = ji;
2281                         pdata->ei = ei;
2282                         pdata->ctx = *ctx;
2283                         break;
2284                 }
2285         }
2286         return FALSE;
2287 }
2288
2289
2290 static gpointer
2291 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
2292 {
2293         int i;
2294         MonoJitExceptionInfo *clause = NULL;
2295         gpointer ip;
2296
2297         ip = MONO_CONTEXT_GET_IP (ctx);
2298
2299         for (i = 0; i < ji->num_clauses; ++i) {
2300                 clause = &ji->clauses [i];
2301                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
2302                         continue;
2303                 if (clause->handler_start < ip && clause->data.handler_end > ip)
2304                         break;
2305         }
2306
2307         /*no matching finally */
2308         if (i == ji->num_clauses)
2309                 return NULL;
2310
2311         /*If we stopped on the instruction right before the try, we haven't actually started executing it*/
2312         if (ip == clause->handler_start)
2313                 return NULL;
2314
2315         return mono_arch_install_handler_block_guard (ji, clause, ctx, mono_create_handler_block_trampoline ());
2316 }
2317
2318 /*
2319  * Finds the bottom handler block running and install a block guard if needed.
2320  */
2321 gboolean
2322 mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx)
2323 {
2324         FindHandlerBlockData data = { 0 };
2325         MonoDomain *domain = mono_domain_get ();
2326         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
2327         gpointer resume_ip;
2328
2329         /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
2330          * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
2331          */
2332         if (!jit_tls || jit_tls->handler_block_return_address)
2333                 return FALSE;
2334
2335         mono_walk_stack (find_last_handler_block, domain, ctx, FALSE, NULL, NULL, &data);
2336
2337         if (!data.ji)
2338                 return FALSE;
2339
2340         memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
2341
2342         resume_ip = install_handler_block_guard (data.ji, &data.ctx);
2343         if (resume_ip == NULL)
2344                 return FALSE;
2345
2346         jit_tls->handler_block_return_address = resume_ip;
2347         jit_tls->handler_block = data.ei;
2348
2349 #ifndef HOST_WIN32
2350         /*Clear current thread from been wapi interrupted otherwise things can go south*/
2351         wapi_clear_interruption ();
2352 #endif
2353         return TRUE;
2354 }
2355
2356 #else
2357 gboolean
2358 mono_install_handler_block_guard (MonoInternalThread *thread, MonoContext *ctx)
2359 {
2360         return FALSE;
2361 }
2362
2363 #endif
2364