2007-06-22 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mono / mini / mini-exceptions.c
1 /*
2  * mini-exceptions.c: generic exception support
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <signal.h>
13 #include <string.h>
14
15 #ifdef HAVE_EXECINFO_H
16 #include <execinfo.h>
17 #endif
18
19 #ifndef PLATFORM_WIN32
20 #include <sys/types.h>
21 #include <unistd.h>
22 #endif
23
24 #include <mono/metadata/appdomain.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/threads.h>
27 #include <mono/metadata/debug-helpers.h>
28 #include <mono/metadata/exception.h>
29 #include <mono/metadata/gc-internal.h>
30 #include <mono/metadata/mono-debug.h>
31 #include <mono/metadata/profiler.h>
32
33 #include "mini.h"
34 #include "trace.h"
35
36 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
37 #include <unistd.h>
38 #include <sys/mman.h>
39 #endif
40
41 /* FreeBSD and NetBSD need SA_STACK and MAP_ANON re-definitions */
42 #       if defined(__FreeBSD__) || defined(__NetBSD__) 
43 #               ifndef SA_STACK
44 #                       define SA_STACK SA_ONSTACK
45 #               endif
46 #               ifndef MAP_ANONYMOUS
47 #                       define MAP_ANONYMOUS MAP_ANON
48 #               endif
49 #       endif /* BSDs */
50
51 #define IS_ON_SIGALTSTACK(jit_tls) ((jit_tls) && ((guint8*)&(jit_tls) > (guint8*)(jit_tls)->signal_stack) && ((guint8*)&(jit_tls) < ((guint8*)(jit_tls)->signal_stack + (jit_tls)->signal_stack_size)))
52
53 #ifndef MONO_ARCH_CONTEXT_DEF
54 #define MONO_ARCH_CONTEXT_DEF
55 #endif
56
57 #ifndef mono_find_jit_info
58
59 /* mono_find_jit_info:
60  *
61  * This function is used to gather information from @ctx. It return the 
62  * MonoJitInfo of the corresponding function, unwinds one stack frame and
63  * stores the resulting context into @new_ctx. It also stores a string 
64  * describing the stack location into @trace (if not NULL), and modifies
65  * the @lmf if necessary. @native_offset return the IP offset from the 
66  * start of the function or -1 if that info is not available.
67  */
68 static MonoJitInfo *
69 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
70                     MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
71                     gboolean *managed)
72 {
73         gboolean managed2;
74         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
75         MonoJitInfo *ji;
76
77         if (trace)
78                 *trace = NULL;
79
80         if (native_offset)
81                 *native_offset = -1;
82
83         if (managed)
84                 *managed = FALSE;
85
86         ji = mono_arch_find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, NULL, lmf, NULL, &managed2);
87
88         if (ji == (gpointer)-1)
89                 return ji;
90
91         if (managed2 || ji->method->wrapper_type) {
92                 const char *real_ip, *start;
93                 gint32 offset;
94
95                 start = (const char *)ji->code_start;
96                 if (!managed2)
97                         /* ctx->ip points into native code */
98                         real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
99                 else
100                         real_ip = (const char*)ip;
101
102                 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
103                         offset = real_ip - start;
104                 else
105                         offset = -1;
106
107                 if (native_offset)
108                         *native_offset = offset;
109
110                 if (managed)
111                         if (!ji->method->wrapper_type)
112                                 *managed = TRUE;
113
114                 if (trace)
115                         *trace = mono_debug_print_stack_frame (ji->method, offset, domain);
116         } else {
117                 if (trace) {
118                         char *fname = mono_method_full_name (res->method, TRUE);
119                         *trace = g_strdup_printf ("in (unmanaged) %s", fname);
120                         g_free (fname);
121                 }
122         }
123
124         return ji;
125 }
126
127 #endif /* mono_find_jit_info */
128
129 MonoString *
130 ves_icall_System_Exception_get_trace (MonoException *ex)
131 {
132         MonoDomain *domain = mono_domain_get ();
133         MonoString *res;
134         MonoArray *ta = ex->trace_ips;
135         int i, len;
136         GString *trace_str;
137
138         if (ta == NULL)
139                 /* Exception is not thrown yet */
140                 return NULL;
141
142         len = mono_array_length (ta);
143         trace_str = g_string_new ("");
144         for (i = 0; i < len; i++) {
145                 MonoJitInfo *ji;
146                 gpointer ip = mono_array_get (ta, gpointer, i);
147
148                 ji = mono_jit_info_table_find (domain, ip);
149                 if (ji == NULL) {
150                         /* Unmanaged frame */
151                         g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
152                 } else {
153                         gchar *location;
154                         gint32 address;
155
156                         address = (char *)ip - (char *)ji->code_start;
157                         location = mono_debug_print_stack_frame (
158                                 ji->method, address, ex->object.vtable->domain);
159
160                         g_string_append_printf (trace_str, "%s\n", location);
161                         g_free (location);
162                 }
163         }
164
165         res = mono_string_new (ex->object.vtable->domain, trace_str->str);
166         g_string_free (trace_str, TRUE);
167
168         return res;
169 }
170
171 MonoArray *
172 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
173 {
174         MonoDomain *domain = mono_domain_get ();
175         MonoArray *res;
176         MonoArray *ta = exc->trace_ips;
177         MonoDebugSourceLocation *location;
178         int i, len;
179
180         if (ta == NULL) {
181                 /* Exception is not thrown yet */
182                 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
183         }
184         
185         len = mono_array_length (ta);
186
187         res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
188
189         for (i = skip; i < len; i++) {
190                 MonoJitInfo *ji;
191                 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
192                 gpointer ip = mono_array_get (ta, gpointer, i);
193
194                 ji = mono_jit_info_table_find (domain, ip);
195                 if (ji == NULL) {
196                         /* Unmanaged frame */
197                         mono_array_setref (res, i, sf);
198                         continue;
199                 }
200
201                 g_assert (ji != NULL);
202
203                 if (ji->method->wrapper_type) {
204                         char *s;
205
206                         sf->method = NULL;
207                         s = mono_method_full_name (ji->method, TRUE);
208                         MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
209                         g_free (s);
210                 }
211                 else
212                         MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, ji->method, NULL));
213                 sf->native_offset = (char *)ip - (char *)ji->code_start;
214
215                 /*
216                  * mono_debug_lookup_source_location() returns both the file / line number information
217                  * and the IL offset.  Note that computing the IL offset is already an expensive
218                  * operation, so we shouldn't call this method twice.
219                  */
220                 location = mono_debug_lookup_source_location (ji->method, sf->native_offset, domain);
221                 if (location)
222                         sf->il_offset = location->il_offset;
223                 else
224                         sf->il_offset = 0;
225
226                 if (need_file_info) {
227                         if (location) {
228                                 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
229                                 sf->line = location->row;
230                                 sf->column = location->column;
231                         } else {
232                                 sf->line = sf->column = 0;
233                                 sf->filename = NULL;
234                         }
235                 }
236
237                 mono_debug_free_source_location (location);
238                 mono_array_setref (res, i, sf);
239         }
240
241         return res;
242 }
243
244 /**
245  * mono_walk_stack:
246  * @domain: starting appdomain
247  * @jit_tls: JIT data for the thread
248  * @start_ctx: starting state of the stack frame
249  * @func: callback to call for each stack frame
250  * @user_data: data passed to the callback
251  *
252  * This function walks the stack of a thread, starting from the state
253  * represented by jit_tls and start_ctx. For each frame the callback
254  * function is called with the relevant info. The walk ends when no more
255  * managed stack frames are found or when the callback returns a TRUE value.
256  * Note that the function can be used to walk the stack of a thread 
257  * different from the current.
258  */
259 void
260 mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gpointer user_data)
261 {
262         MonoLMF *lmf = mono_get_lmf ();
263         MonoJitInfo *ji, rji;
264         gint native_offset;
265         gboolean managed;
266         MonoContext ctx, new_ctx;
267
268         ctx = *start_ctx;
269
270         while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
271                 /* 
272                  * FIXME: mono_find_jit_info () will need to be able to return a different
273                  * MonoDomain when apddomain transitions are found on the stack.
274                  */
275                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
276                 if (!ji || ji == (gpointer)-1)
277                         return;
278
279                 if (func (domain, &new_ctx, ji, user_data))
280                         return;
281
282                 ctx = new_ctx;
283         }
284 }
285
286 #ifndef CUSTOM_STACK_WALK
287
288 void
289 mono_jit_walk_stack_from_ctx (MonoStackWalk func, MonoContext *start_ctx, gboolean do_il_offset, gpointer user_data)
290 {
291         MonoDomain *domain = mono_domain_get ();
292         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
293         MonoLMF *lmf = mono_get_lmf ();
294         MonoJitInfo *ji, rji;
295         gint native_offset, il_offset;
296         gboolean managed;
297         MonoContext ctx, new_ctx;
298
299         MONO_ARCH_CONTEXT_DEF
300
301         mono_arch_flush_register_windows ();
302
303         if (start_ctx) {
304                 memcpy (&ctx, start_ctx, sizeof (MonoContext));
305         } else {
306 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
307         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
308 #else
309     MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_jit_walk_stack_from_ctx);
310 #endif
311         }
312
313         while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
314                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
315                 g_assert (ji);
316
317                 if (ji == (gpointer)-1)
318                         return;
319
320                 if (do_il_offset) {
321                         MonoDebugSourceLocation *source;
322
323                         source = mono_debug_lookup_source_location (ji->method, native_offset, domain);
324                         il_offset = source ? source->il_offset : -1;
325                         mono_debug_free_source_location (source);
326                 } else
327                         il_offset = -1;
328
329                 if (func (ji->method, native_offset, il_offset, managed, user_data))
330                         return;
331                 
332                 ctx = new_ctx;
333         }
334 }
335
336 void
337 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data)
338 {
339         mono_jit_walk_stack_from_ctx (func, NULL, do_il_offset, user_data);
340 }
341
342 MonoBoolean
343 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
344                           MonoReflectionMethod **method, 
345                           gint32 *iloffset, gint32 *native_offset,
346                           MonoString **file, gint32 *line, gint32 *column)
347 {
348         MonoDomain *domain = mono_domain_get ();
349         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
350         MonoLMF *lmf = mono_get_lmf ();
351         MonoJitInfo *ji, rji;
352         MonoContext ctx, new_ctx;
353         MonoDebugSourceLocation *location;
354
355         MONO_ARCH_CONTEXT_DEF;
356
357         mono_arch_flush_register_windows ();
358
359 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
360         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
361 #else
362         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
363 #endif
364
365         /* 
366          * FIXME: This is needed because of the LMF stuff which doesn't exist on ia64.
367          * Probably the whole mono_find_jit_info () stuff needs to be fixed so this isn't
368          * needed even on other platforms. This is also true for s390/s390x.
369          */
370 #if     !defined(__ia64__) && !defined(__s390__) && !defined(__s390x__)
371         skip++;
372 #endif
373
374         do {
375                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
376
377                 ctx = new_ctx;
378                 
379                 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_SP (&ctx) >= jit_tls->end_of_stack)
380                         return FALSE;
381
382                 /* skip all wrappers ??*/
383                 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
384                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
385                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
386                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
387                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
388                         continue;
389
390                 skip--;
391
392         } while (skip >= 0);
393
394         *method = mono_method_get_object (domain, ji->method, NULL);
395
396         location = mono_debug_lookup_source_location (ji->method, *native_offset, domain);
397         if (location)
398                 *iloffset = location->il_offset;
399         else
400                 *iloffset = 0;
401
402         if (need_file_info) {
403                 if (location) {
404                         *file = mono_string_new (domain, location->source_file);
405                         *line = location->row;
406                         *column = location->column;
407                 } else {
408                         *file = NULL;
409                         *line = *column = 0;
410                 }
411         }
412
413         mono_debug_free_source_location (location);
414
415         return TRUE;
416 }
417
418 #endif /* CUSTOM_STACK_WALK */
419
420 typedef struct {
421         guint32 skips;
422         MonoSecurityFrame *frame;
423 } MonoFrameSecurityInfo;
424
425 static gboolean
426 callback_get_first_frame_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
427 {
428         MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
429
430         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
431         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
432             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
433             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
434             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
435             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
436                 return FALSE;
437         }
438
439         if (si->skips > 0) {
440                 si->skips--;
441                 return FALSE;
442         }
443
444         si->frame = mono_declsec_create_frame (domain, ji);
445
446         /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
447         return TRUE;
448 }
449
450 /**
451  * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
452  * @skip: the number of stack frames to skip
453  *
454  * This function returns a the security informations of a single stack frame 
455  * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
456  * and [NonCas]InheritanceDemand[Choice] as only the caller security is 
457  * evaluated.
458  */
459 MonoSecurityFrame*
460 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
461 {
462         MonoDomain *domain = mono_domain_get ();
463         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
464         MonoFrameSecurityInfo si;
465         MonoContext ctx;
466
467         MONO_ARCH_CONTEXT_DEF
468
469 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
470         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
471 #else
472         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
473 #endif
474
475         si.skips = skip;
476         si.frame = NULL;
477         mono_walk_stack (domain, jit_tls, &ctx, callback_get_first_frame_security_info, (gpointer)&si);
478
479         return (si.skips == 0) ? si.frame : NULL;
480 }
481
482
483 typedef struct {
484         guint32 skips;
485         MonoArray *stack;
486         guint32 count;
487         guint32 maximum;
488 } MonoSecurityStack;
489
490 static void
491 grow_array (MonoSecurityStack *stack)
492 {
493         MonoDomain *domain = mono_domain_get ();
494         guint32 newsize = (stack->maximum << 1);
495         MonoArray *newstack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, newsize);
496         int i;
497         for (i=0; i < stack->maximum; i++) {
498                 gpointer frame = mono_array_get (stack->stack, gpointer, i);
499                 mono_array_setref (newstack, i, frame);
500         }
501         stack->maximum = newsize;
502         stack->stack = newstack;
503 }
504
505 static gboolean
506 callback_get_stack_frames_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
507 {
508         MonoSecurityStack *ss = (MonoSecurityStack*) data;
509
510         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
511         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
512             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
513             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
514             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
515             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
516                 return FALSE;
517         }
518
519         if (ss->skips > 0) {
520                 ss->skips--;
521                 return FALSE;
522         }
523
524         if (ss->count == ss->maximum)
525                 grow_array (ss);
526
527         mono_array_setref (ss->stack, ss->count++, mono_declsec_create_frame (domain, ji));
528
529         /* continue down the stack */
530         return FALSE;
531 }
532
533 static MonoArray *
534 glist_to_array (GList *list, MonoClass *eclass) 
535 {
536         MonoDomain *domain = mono_domain_get ();
537         MonoArray *res;
538         int len, i;
539
540         if (!list)
541                 return NULL;
542
543         len = g_list_length (list);
544         res = mono_array_new (domain, eclass, len);
545
546         for (i = 0; list; list = list->next, i++)
547                 mono_array_set (res, gpointer, i, list->data);
548
549         return res;
550 }
551
552 /**
553  * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
554  * @skip: the number of stack frames to skip
555  *
556  * This function returns an managed array of containing the security
557  * informations for each frame (after the skipped ones). This is used for
558  * [NonCas]Demand[Choice] where the complete evaluation of the stack is 
559  * required.
560  */
561 MonoArray*
562 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
563 {
564         MonoDomain *domain = mono_domain_get ();
565         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
566         MonoSecurityStack ss;
567         MonoContext ctx;
568
569         MONO_ARCH_CONTEXT_DEF
570
571 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
572         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
573 #else
574         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityStack);
575 #endif
576
577         ss.skips = skip;
578         ss.count = 0;
579         ss.maximum = MONO_CAS_INITIAL_STACK_SIZE;
580         ss.stack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, ss.maximum);
581         mono_walk_stack (domain, jit_tls, &ctx, callback_get_stack_frames_security_info, (gpointer)&ss);
582         /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
583         return ss.stack;
584 }
585
586 #ifndef CUSTOM_EXCEPTION_HANDLING
587
588 /**
589  * mono_handle_exception_internal:
590  * @ctx: saved processor state
591  * @obj: the exception object
592  * @test_only: only test if the exception is caught, but dont call handlers
593  * @out_filter_idx: out parameter. if test_only is true, set to the index of 
594  * the first filter clause which caught the exception.
595  */
596 static gboolean
597 mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only, gint32 *out_filter_idx)
598 {
599         MonoDomain *domain = mono_domain_get ();
600         MonoJitInfo *ji, rji;
601         static int (*call_filter) (MonoContext *, gpointer) = NULL;
602         static void (*restore_context) (void *);
603         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
604         MonoLMF *lmf = mono_get_lmf ();
605         MonoArray *initial_trace_ips = NULL;
606         GList *trace_ips = NULL;
607         MonoException *mono_ex;
608         gboolean stack_overflow = FALSE;
609         MonoContext initial_ctx;
610         int frame_count = 0;
611         gboolean gc_disabled = FALSE;
612         gboolean has_dynamic_methods = FALSE;
613         gint32 filter_idx, first_filter_idx;
614         
615         /*
616          * This function might execute on an alternate signal stack, and Boehm GC
617          * can't handle that.
618          * Also, since the altstack is small, stack space intensive operations like
619          * JIT compilation should be avoided.
620          */
621         if (IS_ON_SIGALTSTACK (jit_tls)) {
622                 /* 
623                  * FIXME: disabling/enabling GC while already on a signal stack might
624                  * not be safe either.
625                  */
626                 /* Have to reenable it later */
627                 gc_disabled = TRUE;
628                 mono_gc_disable ();
629         }
630
631         g_assert (ctx != NULL);
632         if (!obj) {
633                 MonoException *ex = mono_get_exception_null_reference ();
634                 MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object"));
635                 obj = (MonoObject *)ex;
636         } 
637
638         /*
639          * Allocate a new exception object instead of the preconstructed ones.
640          * We can't do this in sigsegv_signal_handler, since GC is not yet
641          * disabled.
642          */
643         if (obj == domain->stack_overflow_ex) {
644                 obj = mono_get_exception_stack_overflow ();
645                 stack_overflow = TRUE;
646         }
647         else if (obj == domain->null_reference_ex) {
648                 obj = mono_get_exception_null_reference ();
649         }
650
651         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
652                 mono_ex = (MonoException*)obj;
653                 initial_trace_ips = mono_ex->trace_ips;
654         } else {
655                 mono_ex = NULL;
656         }
657
658         if (!call_filter)
659                 call_filter = mono_arch_get_call_filter ();
660
661         if (!restore_context)
662                 restore_context = mono_arch_get_restore_context ();
663
664         g_assert (jit_tls->end_of_stack);
665         g_assert (jit_tls->abort_func);
666
667         if (!test_only) {
668                 MonoContext ctx_cp = *ctx;
669                 if (mono_trace_is_enabled ())
670                         g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
671                 mono_profiler_exception_thrown (obj);
672                 if (!mono_handle_exception_internal (&ctx_cp, obj, original_ip, TRUE, &first_filter_idx)) {
673                         if (mono_break_on_exc)
674                                 G_BREAKPOINT ();
675                         mono_unhandled_exception (obj);
676
677                         if (mono_debugger_unhandled_exception (original_ip, MONO_CONTEXT_GET_SP (ctx), obj)) {
678                                 /*
679                                  * If this returns true, then we're running inside the
680                                  * Mono Debugger and the debugger wants us to restore the
681                                  * context and continue (normally, the debugger inserts
682                                  * a breakpoint on the `original_ip', so it regains control
683                                  * immediately after restoring the context).
684                                  */
685                                 MONO_CONTEXT_SET_IP (ctx, original_ip);
686                                 restore_context (ctx);
687                                 g_assert_not_reached ();
688                         }
689                 }
690         }
691
692         if (out_filter_idx)
693                 *out_filter_idx = -1;
694         filter_idx = 0;
695         initial_ctx = *ctx;
696         memset (&rji, 0, sizeof (rji));
697
698         while (1) {
699                 MonoContext new_ctx;
700                 guint32 free_stack;
701
702                 ji = mono_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx, 
703                                                                  NULL, &lmf, NULL, NULL);
704                 if (!ji) {
705                         g_warning ("Exception inside function without unwind info");
706                         g_assert_not_reached ();
707                 }
708
709                 if (ji != (gpointer)-1) {
710                         frame_count ++;
711                         //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
712
713                         if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
714                                 /* 
715                                  * Avoid overwriting the stack trace if the exception is
716                                  * rethrown. Also avoid giant stack traces during a stack
717                                  * overflow.
718                                  */
719                                 if (!initial_trace_ips && (frame_count < 1000)) {
720                                         trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
721                                 }
722                         }
723
724                         if (ji->method->dynamic)
725                                 has_dynamic_methods = TRUE;
726
727                         if (stack_overflow)
728 #ifndef MONO_ARCH_STACK_GROWS_UP
729                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
730 #else
731                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
732 #endif
733                         else
734                                 free_stack = 0xffffff;
735
736                         /* 
737                          * During stack overflow, wait till the unwinding frees some stack
738                          * space before running handlers/finalizers.
739                          */
740                         if ((free_stack > (64 * 1024)) && ji->num_clauses) {
741                                 int i;
742                                 
743                                 for (i = 0; i < ji->num_clauses; i++) {
744                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
745                                         gboolean filtered = FALSE;
746
747 #ifdef __s390__
748                                         if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) && 
749 #else
750                                         if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
751 #endif
752                                             MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
753                                                 /* catch block */
754
755                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
756                                                         /* store the exception object in bp + ei->exvar_offset */
757                                                         *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
758                                                 }
759
760                                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
761                                                         // mono_debugger_handle_exception (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
762                                                         if (test_only) {
763                                                                 filtered = call_filter (ctx, ei->data.filter);
764                                                                 if (filtered && out_filter_idx)
765                                                                         *out_filter_idx = filter_idx;
766                                                         }
767                                                         else {
768                                                                 /* 
769                                                                  * Filter clauses should only be run in the 
770                                                                  * first pass of exception handling.
771                                                                  */
772                                                                 filtered = (filter_idx == first_filter_idx);
773                                                         }
774                                                         filter_idx ++;
775                                                 }
776
777                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
778                                                      mono_object_isinst (obj, ei->data.catch_class)) || filtered) {
779                                                         if (test_only) {
780                                                                 if (mono_ex && !initial_trace_ips) {
781                                                                         trace_ips = g_list_reverse (trace_ips);
782                                                                         MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
783                                                                         if (has_dynamic_methods)
784                                                                                 /* These methods could go away anytime, so compute the stack trace now */
785                                                                                 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
786                                                                 }
787                                                                 g_list_free (trace_ips);
788
789                                                                 if (gc_disabled)
790                                                                         mono_gc_enable ();
791                                                                 return TRUE;
792                                                         }
793                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
794                                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
795                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
796                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
797                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
798                                                         *(mono_get_lmf_addr ()) = lmf;
799
800                                                         if (gc_disabled)
801                                                                 mono_gc_enable ();
802                                                         return 0;
803                                                 }
804                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
805                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
806                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
807                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
808                                                                 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
809                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
810                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
811                                                         call_filter (ctx, ei->handler_start);
812                                                 }
813                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
814                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
815                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
816                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
817                                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
818                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
819                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
820                                                         call_filter (ctx, ei->handler_start);
821                                                 }
822                                                 
823                                         }
824                                 }
825                         }
826                         if (!test_only)
827                                 mono_profiler_exception_method_leave (ji->method);
828                 }
829
830                 *ctx = new_ctx;
831
832                 if (ji == (gpointer)-1) {
833                         if (gc_disabled)
834                                 mono_gc_enable ();
835
836                         if (!test_only) {
837                                 *(mono_get_lmf_addr ()) = lmf;
838
839                                 if (IS_ON_SIGALTSTACK (jit_tls)) {
840                                         /* Switch back to normal stack */
841                                         if (stack_overflow) {
842                                                 /* Free up some stack space */
843 #ifndef MONO_ARCH_STACK_GROWS_UP
844                                                 MONO_CONTEXT_SET_SP (&initial_ctx, (gssize)(MONO_CONTEXT_GET_SP (&initial_ctx)) + (64 * 1024));
845                                                 g_assert ((gssize)MONO_CONTEXT_GET_SP (&initial_ctx) < (gssize)jit_tls->end_of_stack);
846 #else
847                                                 MONO_CONTEXT_SET_SP (&initial_ctx, (gssize)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (64 * 1024));
848                                                 g_assert ((gssize)MONO_CONTEXT_GET_SP (&initial_ctx) > (gssize)jit_tls->end_of_stack);
849 #endif
850                                         }
851 #ifdef MONO_CONTEXT_SET_FUNC
852                                         /* jit_tls->abort_func is a function descriptor on ia64 */
853                                         MONO_CONTEXT_SET_FUNC (&initial_ctx, (gssize)jit_tls->abort_func);
854 #else
855                                         MONO_CONTEXT_SET_IP (&initial_ctx, (gssize)jit_tls->abort_func);
856 #endif
857                                         restore_context (&initial_ctx);
858                                 }
859                                 else
860                                         jit_tls->abort_func (obj);
861                                 g_assert_not_reached ();
862                         } else {
863                                 if (mono_ex && !initial_trace_ips) {
864                                         trace_ips = g_list_reverse (trace_ips);
865                                         MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
866                                         if (has_dynamic_methods)
867                                                 /* These methods could go away anytime, so compute the stack trace now */
868                                                 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
869                                 }
870                                 g_list_free (trace_ips);
871                                 return FALSE;
872                         }
873                 }
874         }
875
876         g_assert_not_reached ();
877 }
878
879 /**
880  * mono_debugger_run_finally:
881  * @start_ctx: saved processor state
882  *
883  * This method is called by the Mono Debugger to call all `finally' clauses of the
884  * current stack frame.  It's used when the user issues a `return' command to make
885  * the current stack frame return.  After returning from this method, the debugger
886  * unwinds the stack one frame and gives control back to the user.
887  *
888  * NOTE: This method is only used when running inside the Mono Debugger.
889  */
890 void
891 mono_debugger_run_finally (MonoContext *start_ctx)
892 {
893         static int (*call_filter) (MonoContext *, gpointer) = NULL;
894         MonoDomain *domain = mono_domain_get ();
895         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
896         MonoLMF *lmf = mono_get_lmf ();
897         MonoContext ctx, new_ctx;
898         MonoJitInfo *ji, rji;
899         int i;
900
901         ctx = *start_ctx;
902
903         ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
904         if (!ji || ji == (gpointer)-1)
905                 return;
906
907         if (!call_filter)
908                 call_filter = mono_arch_get_call_filter ();
909
910         for (i = 0; i < ji->num_clauses; i++) {
911                 MonoJitExceptionInfo *ei = &ji->clauses [i];
912
913                 if ((ei->try_start <= MONO_CONTEXT_GET_IP (&ctx)) && 
914                     (MONO_CONTEXT_GET_IP (&ctx) < ei->try_end) &&
915                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
916                         call_filter (&ctx, ei->handler_start);
917                 }
918         }
919 }
920
921 /**
922  * mono_handle_exception:
923  * @ctx: saved processor state
924  * @obj: the exception object
925  * @test_only: only test if the exception is caught, but dont call handlers
926  */
927 gboolean
928 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
929 {
930         return mono_handle_exception_internal (ctx, obj, original_ip, test_only, NULL);
931 }
932
933 #endif /* CUSTOM_EXCEPTION_HANDLING */
934
935 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
936
937 void
938 mono_setup_altstack (MonoJitTlsData *tls)
939 {
940         pthread_t self = pthread_self();
941         pthread_attr_t attr;
942         size_t stsize = 0;
943         struct sigaltstack sa;
944         guint8 *staddr = NULL;
945         guint8 *current = (guint8*)&staddr;
946
947         if (mono_running_on_valgrind ())
948                 return;
949
950         /* Determine stack boundaries */
951         pthread_attr_init( &attr );
952 #ifdef HAVE_PTHREAD_GETATTR_NP
953         pthread_getattr_np( self, &attr );
954 #else
955 #ifdef HAVE_PTHREAD_ATTR_GET_NP
956         pthread_attr_get_np( self, &attr );
957 #elif defined(sun)
958         pthread_attr_getstacksize( &attr, &stsize );
959 #else
960 #error "Not implemented"
961 #endif
962 #endif
963
964 #ifndef sun
965         pthread_attr_getstack( &attr, (void**)&staddr, &stsize );
966 #endif
967
968         pthread_attr_destroy (&attr); 
969
970         g_assert (staddr);
971
972         g_assert ((current > staddr) && (current < staddr + stsize));
973
974         tls->end_of_stack = staddr + stsize;
975
976         /*
977          * threads created by nptl does not seem to have a guard page, and
978          * since the main thread is not created by us, we can't even set one.
979          * Increasing stsize fools the SIGSEGV signal handler into thinking this
980          * is a stack overflow exception.
981          */
982         tls->stack_size = stsize + getpagesize ();
983
984         /* Setup an alternate signal stack */
985         tls->signal_stack = mmap (0, MONO_ARCH_SIGNAL_STACK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
986         tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
987
988         g_assert (tls->signal_stack);
989
990         sa.ss_sp = tls->signal_stack;
991         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
992         sa.ss_flags = SS_ONSTACK;
993         sigaltstack (&sa, NULL);
994 }
995
996 void
997 mono_free_altstack (MonoJitTlsData *tls)
998 {
999         struct sigaltstack sa;
1000         int err;
1001
1002         sa.ss_sp = tls->signal_stack;
1003         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1004         sa.ss_flags = SS_DISABLE;
1005         err = sigaltstack  (&sa, NULL);
1006         g_assert (err == 0);
1007
1008         if (tls->signal_stack)
1009                 munmap (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1010 }
1011
1012 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1013
1014 static gboolean
1015 print_stack_frame (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed, gpointer data)
1016 {
1017         FILE *stream = (FILE*)data;
1018
1019         if (method) {
1020                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1021                 fprintf (stream, "  %s\n", location);
1022                 g_free (location);
1023         } else
1024                 fprintf (stream, "  at <unknown> <0x%05x>\n", native_offset);
1025
1026         return FALSE;
1027 }
1028
1029 static gboolean handling_sigsegv = FALSE;
1030
1031 /*
1032  * mono_handle_native_sigsegv:
1033  *
1034  *   Handle a SIGSEGV received while in native code by printing diagnostic 
1035  * information and aborting.
1036  */
1037 void
1038 mono_handle_native_sigsegv (int signal, void *ctx)
1039 {
1040 #ifndef PLATFORM_WIN32
1041         struct sigaction sa;
1042 #endif
1043         if (handling_sigsegv)
1044                 return;
1045
1046         /* To prevent infinite loops when the stack walk causes a crash */
1047         handling_sigsegv = TRUE;
1048
1049         fprintf (stderr, "Stacktrace:\n\n");
1050
1051         mono_jit_walk_stack (print_stack_frame, TRUE, stderr);
1052
1053         fflush (stderr);
1054
1055 #ifdef HAVE_BACKTRACE_SYMBOLS
1056  {
1057         void *array [256];
1058         char **names;
1059         char cmd [1024];
1060         int i, size;
1061         gchar *out, *err;
1062         gint exit_status;
1063         const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
1064
1065         fprintf (stderr, "\nNative stacktrace:\n\n");
1066
1067         size = backtrace (array, 256);
1068         names = backtrace_symbols (array, size);
1069         for (i =0; i < size; ++i) {
1070                 fprintf (stderr, "\t%s\n", names [i]);
1071         }
1072         free (names);
1073
1074         fflush (stderr);
1075
1076         /* Try to get more meaningful information using gdb */
1077
1078 #ifndef PLATFORM_WIN32
1079         sprintf (cmd, "gdb --ex 'attach %ld' --ex 'info threads' --ex 'thread apply all bt' --batch", (long)getpid ());
1080         {
1081                 int res = g_spawn_command_line_sync (cmd, &out, &err, &exit_status, NULL);
1082
1083                 if (res) {
1084                         fprintf (stderr, "\nDebug info from gdb:\n\n");
1085                         fprintf (stderr, "%s\n", out);
1086                 }
1087         }
1088 #endif
1089         /*
1090          * A SIGSEGV indicates something went very wrong so we can no longer depend
1091          * on anything working. So try to print out lots of diagnostics, starting 
1092          * with ones which have a greater chance of working.
1093          */
1094         fprintf (stderr,
1095                          "\n"
1096                          "=================================================================\n"
1097                          "Got a %s while executing native code. This usually indicates\n"
1098                          "a fatal error in the mono runtime or one of the native libraries \n"
1099                          "used by your application.\n"
1100                          "=================================================================\n"
1101                          "\n", signal_str);
1102
1103  }
1104 #endif
1105
1106 #ifndef PLATFORM_WIN32
1107
1108         /* Remove our SIGABRT handler */
1109         sa.sa_handler = SIG_DFL;
1110         sigemptyset (&sa.sa_mask);
1111         sa.sa_flags = 0;
1112
1113         g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
1114
1115 #endif
1116
1117         abort ();
1118 }
1119
1120 /*
1121  * mono_print_thread_dump:
1122  *
1123  *   Print information about the current thread to stdout.
1124  */
1125 void
1126 mono_print_thread_dump (void *sigctx)
1127 {
1128         MonoThread *thread = mono_thread_current ();
1129 #ifdef __i386__
1130         MonoContext ctx;
1131 #endif
1132         char *name;
1133         GError *error = NULL;
1134
1135         if (thread->name) {
1136                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
1137                 g_assert (!error);
1138                 fprintf (stdout, "\n\"%s\"", name);
1139                 g_free (name);
1140         }
1141         else
1142                 fprintf (stdout, "\n\"\"");
1143
1144         fprintf (stdout, " tid=0x%p this=0x%p:\n", (gpointer)(gsize)thread->tid, thread);
1145
1146         /* FIXME: */
1147 #ifdef __i386__
1148         mono_arch_sigctx_to_monoctx (sigctx, &ctx);
1149
1150         mono_jit_walk_stack_from_ctx (print_stack_frame, &ctx, TRUE, stdout);
1151 #else
1152         printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
1153 #endif
1154
1155         fflush (stdout);
1156 }