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