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