2005-07-30 Zoltan Varga <vargaz@freemail.hu>
[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 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/threads.h>
18 #include <mono/metadata/debug-helpers.h>
19 #include <mono/metadata/exception.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/mono-debug.h>
22 #include <mono/metadata/mono-debug-debugger.h>
23
24 #include "mini.h"
25
26 #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)))
27
28 #ifndef MONO_ARCH_CONTEXT_DEF
29 #define MONO_ARCH_CONTEXT_DEF
30 #endif
31
32 #ifndef mono_find_jit_info
33
34 /* mono_find_jit_info:
35  *
36  * This function is used to gather information from @ctx. It return the 
37  * MonoJitInfo of the corresponding function, unwinds one stack frame and
38  * stores the resulting context into @new_ctx. It also stores a string 
39  * describing the stack location into @trace (if not NULL), and modifies
40  * the @lmf if necessary. @native_offset return the IP offset from the 
41  * start of the function or -1 if that info is not available.
42  */
43 static MonoJitInfo *
44 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
45                          MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
46                          gboolean *managed)
47 {
48         gboolean managed2;
49         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
50         MonoJitInfo *ji;
51
52         if (trace)
53                 *trace = NULL;
54
55         if (native_offset)
56                 *native_offset = -1;
57
58         if (managed)
59                 *managed = FALSE;
60
61         ji = mono_arch_find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, NULL, lmf, NULL, &managed2);
62
63         if (ji == (gpointer)-1)
64                 return ji;
65
66         if (managed2 || ji->method->wrapper_type) {
67                 char *source_location, *tmpaddr, *fname;
68                 gint32 offset, iloffset;
69
70                 if (!managed2)
71                         /* ctx->ip points into native code */
72                         offset = (char*)MONO_CONTEXT_GET_IP (new_ctx) - (char*)ji->code_start;
73                 else
74                         offset = (char *)ip - (char *)ji->code_start;
75
76                 if (native_offset)
77                         *native_offset = offset;
78
79                 if (managed)
80                         if (!ji->method->wrapper_type)
81                                 *managed = TRUE;
82
83                 if (trace) {
84                         source_location = mono_debug_source_location_from_address (ji->method, offset, NULL, domain);
85                         iloffset = mono_debug_il_offset_from_address (ji->method, offset, domain);
86
87                         if (iloffset < 0)
88                                 tmpaddr = g_strdup_printf ("<0x%05x>", offset);
89                         else
90                                 tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
91                 
92                         fname = mono_method_full_name (ji->method, TRUE);
93
94                         if (source_location)
95                                 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
96                         else
97                                 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
98
99                         g_free (fname);
100                         g_free (source_location);
101                         g_free (tmpaddr);
102                 }
103         }
104         else {
105                 if (trace) {
106                         char *fname = mono_method_full_name (res->method, TRUE);
107                         *trace = g_strdup_printf ("in (unmanaged) %s", fname);
108                         g_free (fname);
109                 }
110         }
111
112         return ji;
113 }
114
115 #endif /* mono_find_jit_info */
116
117 MonoString *
118 ves_icall_System_Exception_get_trace (MonoException *ex)
119 {
120         MonoDomain *domain = mono_domain_get ();
121         MonoString *res;
122         MonoArray *ta = ex->trace_ips;
123         int i, len;
124         GString *trace_str;
125         char tmpaddr [256];
126
127         if (ta == NULL)
128                 /* Exception is not thrown yet */
129                 return NULL;
130
131         len = mono_array_length (ta);
132         trace_str = g_string_new ("");
133         for (i = 0; i < len; i++) {
134                 MonoJitInfo *ji;
135                 gpointer ip = mono_array_get (ta, gpointer, i);
136
137                 ji = mono_jit_info_table_find (domain, ip);
138                 if (ji == NULL) {
139                         /* Unmanaged frame */
140                         g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
141                 } else {
142                         char *source_location, *fname;
143                         gint32 address, iloffset;
144
145                         address = (char *)ip - (char *)ji->code_start;
146
147                         source_location = mono_debug_source_location_from_address (ji->method, address, NULL, ex->object.vtable->domain);
148                         iloffset = mono_debug_il_offset_from_address (ji->method, address, ex->object.vtable->domain);
149
150                         if (iloffset < 0)
151                                 sprintf (tmpaddr, "<0x%05x>", address);
152                         else
153                                 sprintf (tmpaddr, "[0x%05x]", iloffset);
154                 
155                         fname = mono_method_full_name (ji->method, TRUE);
156
157                         if (source_location)
158                                 g_string_append_printf (trace_str, "in %s (at %s) %s\n", tmpaddr, source_location, fname);
159                         else
160                                 g_string_append_printf (trace_str, "in %s %s\n", tmpaddr, fname);
161
162                         g_free (fname);
163                         g_free (source_location);
164                 }
165         }
166
167         res = mono_string_new (ex->object.vtable->domain, trace_str->str);
168         g_string_free (trace_str, TRUE);
169
170         return res;
171 }
172
173 MonoArray *
174 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
175 {
176         MonoDomain *domain = mono_domain_get ();
177         MonoArray *res;
178         MonoArray *ta = exc->trace_ips;
179         int i, len;
180
181         if (ta == NULL) {
182                 /* Exception is not thrown yet */
183                 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
184         }
185         
186         len = mono_array_length (ta);
187
188         res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
189
190         for (i = skip; i < len; i++) {
191                 MonoJitInfo *ji;
192                 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
193                 gpointer ip = mono_array_get (ta, gpointer, i);
194
195                 ji = mono_jit_info_table_find (domain, ip);
196                 if (ji == NULL) {
197                         /* Unmanaged frame */
198                         mono_array_set (res, gpointer, i, sf);
199                         continue;
200                 }
201
202                 g_assert (ji != NULL);
203
204                 if (ji->method->wrapper_type) {
205                         char *s;
206
207                         sf->method = NULL;
208                         s = mono_method_full_name (ji->method, TRUE);
209                         sf->internal_method_name = mono_string_new (domain, s);
210                         g_free (s);
211                 }
212                 else
213                         sf->method = mono_method_get_object (domain, ji->method, NULL);
214                 sf->native_offset = (char *)ip - (char *)ji->code_start;
215
216                 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
217
218                 if (need_file_info) {
219                         gchar *filename;
220                         
221                         filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
222
223                         sf->filename = filename? mono_string_new (domain, filename): NULL;
224                         sf->column = 0;
225
226                         g_free (filename);
227                 }
228
229                 mono_array_set (res, gpointer, i, sf);
230         }
231
232         return res;
233 }
234
235 /**
236  * mono_walk_stack:
237  * @domain: starting appdomain
238  * @jit_tls: JIT data for the thread
239  * @start_ctx: starting state of the stack frame
240  * @func: callback to call for each stack frame
241  * @user_data: data passed to the callback
242  *
243  * This function walks the stack of a thread, starting from the state
244  * represented by jit_tls and start_ctx. For each frame the callback
245  * function is called with the relevant info. The walk ends when no more
246  * managed stack frames are found or when the callback returns a TRUE value.
247  * Note that the function can be used to walk the stack of a thread 
248  * different from the current.
249  */
250 void
251 mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gpointer user_data)
252 {
253         MonoLMF *lmf = jit_tls->lmf;
254         MonoJitInfo *ji, rji;
255         gint native_offset;
256         gboolean managed;
257         MonoContext ctx, new_ctx;
258
259         ctx = *start_ctx;
260
261         while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
262                 /* 
263                  * FIXME: mono_find_jit_info () will need to be able to return a different
264                  * MonoDomain when apddomain transitions are found on the stack.
265                  */
266                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
267                 if (!ji || ji == (gpointer)-1)
268                         return;
269
270                 if (func (domain, &new_ctx, ji, user_data))
271                         return;
272
273                 ctx = new_ctx;
274         }
275 }
276
277 #ifndef CUSTOM_STACK_WALK
278
279 void
280 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data) {
281         MonoDomain *domain = mono_domain_get ();
282         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
283         MonoLMF *lmf = jit_tls->lmf;
284         MonoJitInfo *ji, rji;
285         gint native_offset, il_offset;
286         gboolean managed;
287         MonoContext ctx, new_ctx;
288
289         MONO_ARCH_CONTEXT_DEF
290
291 #ifdef _MSC_VER
292         unsigned int stackptr, retaddr;
293         __asm mov stackptr, ebp;
294         __asm mov eax, DWORD PTR [ebp + 4];
295         __asm mov retaddr, eax;
296         MONO_CONTEXT_SET_IP (&ctx, retaddr);
297         /* FIXME: NOT WORKING -- THIS IS __builtin_frame_address (0) NOT (1) */
298         MONO_CONTEXT_SET_BP (&ctx, stackptr);
299 #else
300         mono_arch_flush_register_windows ();
301
302 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
303         MONO_INIT_CONTEXT_FROM_CURRENT(&ctx);
304 #else
305         MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
306         MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
307 #endif
308 #endif
309
310         while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
311                 
312                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
313                 g_assert (ji);
314
315                 if (ji == (gpointer)-1)
316                         return;
317
318                 il_offset = do_il_offset ? mono_debug_il_offset_from_address (ji->method, native_offset, domain): -1;
319
320                 if (func (ji->method, native_offset, il_offset, managed, user_data))
321                         return;
322                 
323                 ctx = new_ctx;
324         }
325 }
326
327 MonoBoolean
328 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
329                           MonoReflectionMethod **method, 
330                           gint32 *iloffset, gint32 *native_offset,
331                           MonoString **file, gint32 *line, gint32 *column)
332 {
333         MonoDomain *domain = mono_domain_get ();
334         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
335         MonoLMF *lmf = jit_tls->lmf;
336         MonoJitInfo *ji, rji;
337         MonoContext ctx, new_ctx;
338         gssize stackptr;
339
340         mono_arch_flush_register_windows ();
341
342 #ifdef _MSC_VER
343         __asm mov stackptr, ebp;
344 #else
345         stackptr = (gssize)__builtin_frame_address (0);
346 #endif
347
348         MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
349         MONO_CONTEXT_SET_BP (&ctx, stackptr);
350
351         skip++;
352
353         do {
354                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
355
356                 ctx = new_ctx;
357                 
358                 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
359                         return FALSE;
360
361                 /* skip all wrappers ??*/
362                 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
363                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
364                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
365                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
366                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
367                         continue;
368
369                 skip--;
370
371         } while (skip >= 0);
372
373         *method = mono_method_get_object (domain, ji->method, NULL);
374         *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset, domain);
375
376         if (need_file_info) {
377                 gchar *filename;
378
379                 filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
380
381                 *file = filename? mono_string_new (domain, filename): NULL;
382                 *column = 0;
383
384                 g_free (filename);
385         }
386
387         return TRUE;
388 }
389
390 #endif /* CUSTOM_STACK_WALK */
391
392 typedef struct {
393         guint32 skips;
394         MonoSecurityFrame *frame;
395 } MonoFrameSecurityInfo;
396
397 static gboolean
398 callback_get_first_frame_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
399 {
400         MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
401
402         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
403         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
404             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
405             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
406             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
407             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
408                 return FALSE;
409         }
410
411         if (si->skips > 0) {
412                 si->skips--;
413                 return FALSE;
414         }
415
416         si->frame = mono_declsec_create_frame (domain, ji);
417
418         /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
419         return TRUE;
420 }
421
422 /**
423  * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
424  * @skip: the number of stack frames to skip
425  *
426  * This function returns a the security informations of a single stack frame 
427  * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
428  * and [NonCas]InheritanceDemand[Choice] as only the caller security is 
429  * evaluated.
430  */
431 MonoSecurityFrame*
432 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
433 {
434         MonoDomain *domain = mono_domain_get ();
435         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
436         MonoFrameSecurityInfo si;
437         MonoContext ctx;
438
439         MONO_ARCH_CONTEXT_DEF
440
441 #ifdef _MSC_VER
442         /* seems that MSC doesn't like having __asm in macros */
443         unsigned int stackptr;
444         mono_arch_flush_register_windows ();
445         __asm mov stackptr, ebp;
446         MONO_CONTEXT_SET_IP (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
447         MONO_CONTEXT_SET_BP (&ctx, stackptr);
448 #else
449         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
450 #endif
451
452         si.skips = skip;
453         si.frame = NULL;
454         mono_walk_stack (domain, jit_tls, &ctx, callback_get_first_frame_security_info, (gpointer)&si);
455
456         return (si.skips == 0) ? si.frame : NULL;
457 }
458
459
460 typedef struct {
461         guint32 skips;
462         MonoArray *stack;
463         guint32 count;
464         guint32 maximum;
465 } MonoSecurityStack;
466
467 static void
468 grow_array (MonoSecurityStack *stack)
469 {
470         MonoDomain *domain = mono_domain_get ();
471         guint32 newsize = (stack->maximum << 1);
472         MonoArray *newstack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, newsize);
473         int i;
474         for (i=0; i < stack->maximum; i++) {
475                 gpointer frame = mono_array_get (stack->stack, gpointer, i);
476                 mono_array_set (newstack, gpointer, i, frame);
477         }
478         stack->maximum = newsize;
479         stack->stack = newstack;
480 }
481
482 static gboolean
483 callback_get_stack_frames_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
484 {
485         MonoSecurityStack *ss = (MonoSecurityStack*) data;
486
487         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
488         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
489             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
490             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
491             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
492             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
493                 return FALSE;
494         }
495
496         if (ss->skips > 0) {
497                 ss->skips--;
498                 return FALSE;
499         }
500
501         if (ss->count == ss->maximum)
502                 grow_array (ss);
503         
504         mono_array_set (ss->stack, gpointer, ss->count++, mono_declsec_create_frame (domain, ji));
505
506         /* continue down the stack */
507         return FALSE;
508 }
509
510 static MonoArray *
511 glist_to_array (GList *list, MonoClass *eclass) 
512 {
513         MonoDomain *domain = mono_domain_get ();
514         MonoArray *res;
515         int len, i;
516
517         if (!list)
518                 return NULL;
519
520         len = g_list_length (list);
521         res = mono_array_new (domain, eclass, len);
522
523         for (i = 0; list; list = list->next, i++)
524                 mono_array_set (res, gpointer, i, list->data);
525
526         return res;
527 }
528
529 /**
530  * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
531  * @skip: the number of stack frames to skip
532  *
533  * This function returns an managed array of containing the security
534  * informations for each frame (after the skipped ones). This is used for
535  * [NonCas]Demand[Choice] where the complete evaluation of the stack is 
536  * required.
537  */
538 MonoArray*
539 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
540 {
541         MonoDomain *domain = mono_domain_get ();
542         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
543         MonoSecurityStack ss;
544         MonoContext ctx;
545
546         MONO_ARCH_CONTEXT_DEF
547
548 #ifdef _MSC_VER
549         /* seems that MSC doesn't like having __asm in macros */
550         unsigned int stackptr;
551         mono_arch_flush_register_windows ();
552         __asm mov stackptr, ebp;
553         MONO_CONTEXT_SET_IP (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityStack);
554         MONO_CONTEXT_SET_BP (&ctx, stackptr);
555 #else
556         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityStack);
557 #endif
558
559         ss.skips = skip;
560         ss.count = 0;
561         ss.maximum = MONO_CAS_INITIAL_STACK_SIZE;
562         ss.stack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, ss.maximum);
563         mono_walk_stack (domain, jit_tls, &ctx, callback_get_stack_frames_security_info, (gpointer)&ss);
564         /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
565         return ss.stack;
566 }
567
568 #ifndef CUSTOM_EXCEPTION_HANDLING
569
570 /**
571  * mono_handle_exception:
572  * @ctx: saved processor state
573  * @obj: the exception object
574  * @test_only: only test if the exception is caught, but dont call handlers
575  *
576  */
577 gboolean
578 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
579 {
580         MonoDomain *domain = mono_domain_get ();
581         MonoJitInfo *ji, rji;
582         static int (*call_filter) (MonoContext *, gpointer) = NULL;
583         static void (*restore_context) (void *);
584         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
585         MonoLMF *lmf = jit_tls->lmf;            
586         MonoArray *initial_trace_ips = NULL;
587         GList *trace_ips = NULL;
588         MonoException *mono_ex;
589         gboolean stack_overflow = FALSE;
590         MonoContext initial_ctx;
591         int frame_count = 0;
592         gboolean gc_disabled = FALSE;
593         gboolean has_dynamic_methods = FALSE;
594         
595         /*
596          * This function might execute on an alternate signal stack, and Boehm GC
597          * can't handle that.
598          * Also, since the altstack is small, stack space intensive operations like
599          * JIT compilation should be avoided.
600          */
601         if (IS_ON_SIGALTSTACK (jit_tls)) {
602                 /* 
603                  * FIXME: disabling/enabling GC while already on a signal stack might
604                  * not be safe either.
605                  */
606                 /* Have to reenable it later */
607                 gc_disabled = TRUE;
608                 mono_gc_disable ();
609         }
610
611         g_assert (ctx != NULL);
612         if (!obj) {
613                 MonoException *ex = mono_get_exception_null_reference ();
614                 ex->message = mono_string_new (domain, "Object reference not set to an instance of an object");
615                 obj = (MonoObject *)ex;
616         } 
617
618         /*
619          * Allocate a new exception object instead of the preconstructed ones.
620          * We can't do this in sigsegv_signal_handler, since GC is not yet
621          * disabled.
622          */
623         if (obj == domain->stack_overflow_ex) {
624                 obj = mono_get_exception_stack_overflow ();
625                 stack_overflow = TRUE;
626         }
627         else if (obj == domain->null_reference_ex) {
628                 obj = mono_get_exception_null_reference ();
629         }
630
631         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
632                 mono_ex = (MonoException*)obj;
633                 initial_trace_ips = mono_ex->trace_ips;
634         } else {
635                 mono_ex = NULL;
636         }
637
638         if (!call_filter)
639                 call_filter = mono_arch_get_call_filter ();
640
641         if (!restore_context)
642                 restore_context = mono_arch_get_restore_context ();
643
644         g_assert (jit_tls->end_of_stack);
645         g_assert (jit_tls->abort_func);
646
647         if (!test_only) {
648                 MonoContext ctx_cp = *ctx;
649                 if (mono_jit_trace_calls != NULL)
650                         g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
651                 if (!mono_handle_exception (&ctx_cp, obj, original_ip, TRUE)) {
652                         if (mono_break_on_exc)
653                                 G_BREAKPOINT ();
654                         mono_unhandled_exception (obj);
655
656                         if (mono_debugger_unhandled_exception (original_ip, MONO_CONTEXT_GET_SP (ctx), obj)) {
657                                 /*
658                                  * If this returns true, then we're running inside the
659                                  * Mono Debugger and the debugger wants us to restore the
660                                  * context and continue (normally, the debugger inserts
661                                  * a breakpoint on the `original_ip', so it regains control
662                                  * immediately after restoring the context).
663                                  */
664                                 MONO_CONTEXT_SET_IP (ctx, original_ip);
665                                 restore_context (ctx);
666                                 g_assert_not_reached ();
667                         }
668                 }
669         }
670
671         initial_ctx = *ctx;
672         memset (&rji, 0, sizeof (rji));
673
674         while (1) {
675                 MonoContext new_ctx;
676                 guint32 free_stack;
677
678                 ji = mono_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx, 
679                                                                  NULL, &lmf, NULL, NULL);
680                 if (!ji) {
681                         g_warning ("Exception inside function without unwind info");
682                         g_assert_not_reached ();
683                 }
684
685                 if (ji != (gpointer)-1) {
686                         frame_count ++;
687                         //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
688
689                         if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
690                                 /* 
691                                  * Avoid overwriting the stack trace if the exception is
692                                  * rethrown. Also avoid giant stack traces during a stack
693                                  * overflow.
694                                  */
695                                 if (!initial_trace_ips && (frame_count < 1000)) {
696                                         trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
697                                 }
698                         }
699
700                         if (ji->method->dynamic)
701                                 has_dynamic_methods = TRUE;
702
703                         if (stack_overflow)
704                                 free_stack = (guint8*)(MONO_CONTEXT_GET_BP (ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
705                         else
706                                 free_stack = 0xffffff;
707
708                         /* 
709                          * During stack overflow, wait till the unwinding frees some stack
710                          * space before running handlers/finalizers.
711                          */
712                         if ((free_stack > (64 * 1024)) && ji->num_clauses) {
713                                 int i;
714                                 
715                                 for (i = 0; i < ji->num_clauses; i++) {
716                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
717                                         gboolean filtered = FALSE;
718
719 #ifdef __s390__
720                                         if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) && 
721 #else
722                                         if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
723 #endif
724                                             MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
725                                                 /* catch block */
726
727                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
728                                                         /* store the exception object in cfg->excvar */
729                                                         g_assert (ei->exvar_offset);
730                                                         *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
731                                                 }
732
733                                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
734                                                         // mono_debugger_handle_exception (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
735                                                         filtered = call_filter (ctx, ei->data.filter);
736                                                 }
737
738                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
739                                                      mono_object_isinst (obj, ei->data.catch_class)) || filtered) {
740                                                         if (test_only) {
741                                                                 if (mono_ex && !initial_trace_ips) {
742                                                                         trace_ips = g_list_reverse (trace_ips);
743                                                                         mono_ex->trace_ips = glist_to_array (trace_ips, mono_defaults.int_class);
744                                                                         if (has_dynamic_methods)
745                                                                                 /* These methods could go away anytime, so compute the stack trace now */
746                                                                                 mono_ex->stack_trace = ves_icall_System_Exception_get_trace (mono_ex);
747                                                                 }
748                                                                 g_list_free (trace_ips);
749
750                                                                 if (gc_disabled)
751                                                                         mono_gc_enable ();
752                                                                 return TRUE;
753                                                         }
754                                                         if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
755                                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
756                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
757                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
758                                                         jit_tls->lmf = lmf;
759
760                                                         if (gc_disabled)
761                                                                 mono_gc_enable ();
762                                                         return 0;
763                                                 }
764                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
765                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
766                                                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
767                                                         if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
768                                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
769                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
770                                                         call_filter (ctx, ei->handler_start);
771                                                 }
772                                                 
773                                         }
774                                 }
775                         }
776                 }
777
778                 *ctx = new_ctx;
779
780                 if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
781                         if (gc_disabled)
782                                 mono_gc_enable ();
783
784                         if (!test_only) {
785                                 jit_tls->lmf = lmf;
786
787                                 if (IS_ON_SIGALTSTACK (jit_tls)) {
788                                         /* Switch back to normal stack */
789                                         if (stack_overflow)
790                                                 /* Free up some stack space */
791                                                 MONO_CONTEXT_SET_SP (&initial_ctx, (gssize)(MONO_CONTEXT_GET_SP (&initial_ctx)) + (64 * 1024));
792                                         MONO_CONTEXT_SET_IP (&initial_ctx, (gssize)jit_tls->abort_func);
793                                         restore_context (&initial_ctx);
794                                 }
795                                 else
796                                         jit_tls->abort_func (obj);
797                                 g_assert_not_reached ();
798                         } else {
799                                 if (mono_ex && !initial_trace_ips) {
800                                         trace_ips = g_list_reverse (trace_ips);
801                                         mono_ex->trace_ips = glist_to_array (trace_ips, mono_defaults.int_class);
802                                         if (has_dynamic_methods)
803                                                 /* These methods could go away anytime, so compute the stack trace now */
804                                                 mono_ex->stack_trace = ves_icall_System_Exception_get_trace (mono_ex);
805                                 }
806                                 g_list_free (trace_ips);
807                                 return FALSE;
808                         }
809                 }
810         }
811
812         g_assert_not_reached ();
813 }
814 #endif /* CUSTOM_EXECPTION_HANDLING */
815