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