2005-03-29 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                 if (ji->method->wrapper_type) {
197                         char *s;
198
199                         sf->method = NULL;
200                         s = mono_method_full_name (ji->method, TRUE);
201                         sf->internal_method_name = mono_string_new (domain, s);
202                         g_free (s);
203                 }
204                 else
205                         sf->method = mono_method_get_object (domain, ji->method, NULL);
206                 sf->native_offset = (char *)ip - (char *)ji->code_start;
207
208                 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
209
210                 if (need_file_info) {
211                         gchar *filename;
212                         
213                         filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
214
215                         sf->filename = filename? mono_string_new (domain, filename): NULL;
216                         sf->column = 0;
217
218                         g_free (filename);
219                 }
220
221                 mono_array_set (res, gpointer, i, sf);
222         }
223
224         return res;
225 }
226
227 /**
228  * mono_walk_stack:
229  * @domain: starting appdomain
230  * @jit_tls: JIT data for the thread
231  * @start_ctx: starting state of the stack frame
232  * @func: callback to call for each stack frame
233  * @user_data: data passed to the callback
234  *
235  * This function walks the stack of a thread, starting from the state
236  * represented by jit_tls and start_ctx. For each frame the callback
237  * function is called with the relevant info. The walk ends when no more
238  * managed stack frames are found or when the callback returns a TRUE value.
239  * Note that the function can be used to walk the stack of a thread 
240  * different from the current.
241  */
242 void
243 mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gpointer user_data)
244 {
245         MonoLMF *lmf = jit_tls->lmf;
246         MonoJitInfo *ji, rji;
247         gint native_offset;
248         gboolean managed;
249         MonoContext ctx, new_ctx;
250
251         ctx = *start_ctx;
252
253         while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
254                 /* 
255                  * FIXME: mono_find_jit_info () will need to be able to return a different
256                  * MonoDomain when apddomain transitions are found on the stack.
257                  */
258                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
259                 if (!ji || ji == (gpointer)-1)
260                         return;
261
262                 if (func (domain, &new_ctx, ji, user_data))
263                         return;
264
265                 ctx = new_ctx;
266         }
267 }
268
269 #ifndef CUSTOM_STACK_WALK
270
271 void
272 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data) {
273         MonoDomain *domain = mono_domain_get ();
274         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
275         MonoLMF *lmf = jit_tls->lmf;
276         MonoJitInfo *ji, rji;
277         gint native_offset, il_offset;
278         gboolean managed;
279
280         MonoContext ctx, new_ctx;
281
282 #ifdef _MSC_VER
283         unsigned int stackptr, retaddr;
284         __asm mov stackptr, ebp;
285         __asm mov eax, DWORD PTR [ebp + 4];
286         __asm mov retaddr, eax;
287         MONO_CONTEXT_SET_IP (&ctx, retaddr);
288         /* FIXME: NOT WORKING -- THIS IS __builtin_frame_address (0) NOT (1) */
289         MONO_CONTEXT_SET_BP (&ctx, stackptr);
290 #else
291         mono_arch_flush_register_windows ();
292
293         MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
294         MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
295 #endif
296         while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
297                 
298                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
299                 g_assert (ji);
300
301                 if (ji == (gpointer)-1)
302                         return;
303
304                 il_offset = do_il_offset ? mono_debug_il_offset_from_address (ji->method, native_offset, domain): -1;
305
306                 if (func (ji->method, native_offset, il_offset, managed, user_data))
307                         return;
308                 
309                 ctx = new_ctx;
310         }
311 }
312
313 MonoBoolean
314 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
315                           MonoReflectionMethod **method, 
316                           gint32 *iloffset, gint32 *native_offset,
317                           MonoString **file, gint32 *line, gint32 *column)
318 {
319         MonoDomain *domain = mono_domain_get ();
320         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
321         MonoLMF *lmf = jit_tls->lmf;
322         MonoJitInfo *ji, rji;
323         MonoContext ctx, new_ctx;
324         unsigned int stackptr;
325
326         mono_arch_flush_register_windows ();
327
328 #ifdef _MSC_VER
329         __asm mov stackptr, ebp;
330 #else
331         stackptr = (unsigned int) __builtin_frame_address (0);
332 #endif
333
334         MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
335         MONO_CONTEXT_SET_BP (&ctx, stackptr);
336
337         skip++;
338
339         do {
340                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
341
342                 ctx = new_ctx;
343                 
344                 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
345                         return FALSE;
346
347                 /* skip all wrappers ??*/
348                 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
349                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
350                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
351                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
352                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
353                         continue;
354
355                 skip--;
356
357         } while (skip >= 0);
358
359         *method = mono_method_get_object (domain, ji->method, NULL);
360         *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset, domain);
361
362         if (need_file_info) {
363                 gchar *filename;
364
365                 filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
366
367                 *file = filename? mono_string_new (domain, filename): NULL;
368                 *column = 0;
369
370                 g_free (filename);
371         }
372
373         return TRUE;
374 }
375
376 #endif /* CUSTOM_STACK_WALK */
377
378 typedef struct {
379         guint32 skips;
380         MonoSecurityFrame *frame;
381 } MonoFrameSecurityInfo;
382
383 static gboolean
384 callback_get_first_frame_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
385 {
386         MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
387
388         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
389         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
390             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
391             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
392             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
393             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
394                 return FALSE;
395         }
396
397         if (si->skips > 0) {
398                 si->skips--;
399                 return FALSE;
400         }
401
402         si->frame = mono_declsec_create_frame (domain, ji);
403
404         /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
405         return TRUE;
406 }
407
408 /**
409  * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
410  * @skip: the number of stack frames to skip
411  *
412  * This function returns a the security informations of a single stack frame 
413  * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
414  * and [NonCas]InheritanceDemand[Choice] as only the caller security is 
415  * evaluated.
416  */
417 MonoSecurityFrame*
418 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
419 {
420         MonoDomain *domain = mono_domain_get ();
421         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
422         MonoFrameSecurityInfo si;
423         MonoContext ctx;
424
425 #ifdef _MSC_VER
426         /* seems that MSC doesn't like having __asm in macros */
427         unsigned int stackptr;
428         mono_arch_flush_register_windows ();
429         __asm mov stackptr, ebp;
430         MONO_CONTEXT_SET_IP (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
431         MONO_CONTEXT_SET_BP (&ctx, stackptr);
432 #else
433         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
434 #endif
435
436         si.skips = skip;
437         si.frame = NULL;
438         mono_walk_stack (domain, jit_tls, &ctx, callback_get_first_frame_security_info, (gpointer)&si);
439
440         return (si.skips == 0) ? si.frame : NULL;
441 }
442
443
444 typedef struct {
445         guint32 skips;
446         GList *stack;
447 } MonoSecurityStack;
448
449 static gboolean
450 callback_get_stack_frames_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
451 {
452         MonoSecurityStack *ss = (MonoSecurityStack*) data;
453
454         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
455         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
456             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
457             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
458             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
459             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
460                 return FALSE;
461         }
462
463         if (ss->skips > 0) {
464                 ss->skips--;
465                 return FALSE;
466         }
467
468         ss->stack = g_list_prepend (ss->stack, mono_declsec_create_frame (domain, ji));
469
470         /* continue down the stack */
471         return FALSE;
472 }
473
474 static MonoArray *
475 glist_to_array (GList *list, MonoClass *eclass) 
476 {
477         MonoDomain *domain = mono_domain_get ();
478         MonoArray *res;
479         int len, i;
480
481         if (!list)
482                 return NULL;
483
484         len = g_list_length (list);
485         res = mono_array_new (domain, eclass, len);
486
487         for (i = 0; list; list = list->next, i++)
488                 mono_array_set (res, gpointer, i, list->data);
489
490         return res;
491 }
492
493 /**
494  * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
495  * @skip: the number of stack frames to skip
496  *
497  * This function returns an managed array of containing the security
498  * informations for each frame (after the skipped ones). This is used for
499  * [NonCas]Demand[Choice] where the complete evaluation of the stack is 
500  * required.
501  */
502 MonoArray*
503 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
504 {
505         MonoDomain *domain = mono_domain_get ();
506         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
507         MonoSecurityStack ss;
508         MonoContext ctx;
509         MonoArray *stack;
510
511 #ifdef _MSC_VER
512         /* seems that MSC doesn't like having __asm in macros */
513         unsigned int stackptr;
514         mono_arch_flush_register_windows ();
515         __asm mov stackptr, ebp;
516         MONO_CONTEXT_SET_IP (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityStack);
517         MONO_CONTEXT_SET_BP (&ctx, stackptr);
518 #else
519         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityStack);
520 #endif
521
522         ss.skips = skip;
523         ss.stack = NULL;
524         mono_walk_stack (domain, jit_tls, &ctx, callback_get_stack_frames_security_info, (gpointer)&ss);
525
526         stack = glist_to_array (ss.stack, mono_defaults.runtimesecurityframe_class);
527         if (ss.stack)
528                 g_list_free (ss.stack);
529
530         return stack;
531 }
532
533 #ifndef CUSTOM_EXCEPTION_HANDLING
534
535 /**
536  * mono_handle_exception:
537  * @ctx: saved processor state
538  * @obj: the exception object
539  * @test_only: only test if the exception is caught, but dont call handlers
540  *
541  */
542 gboolean
543 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
544 {
545         MonoDomain *domain = mono_domain_get ();
546         MonoJitInfo *ji, rji;
547         static int (*call_filter) (MonoContext *, gpointer) = NULL;
548         static void (*restore_context) (void *);
549         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
550         MonoLMF *lmf = jit_tls->lmf;            
551         MonoArray *initial_trace_ips = NULL;
552         GList *trace_ips = NULL;
553         MonoException *mono_ex;
554         gboolean stack_overflow = FALSE;
555         MonoContext initial_ctx;
556         int frame_count = 0;
557         gboolean gc_disabled = FALSE;
558         gboolean has_dynamic_methods = FALSE;
559         
560         /*
561          * This function might execute on an alternate signal stack, and Boehm GC
562          * can't handle that.
563          * Also, since the altstack is small, stack space intensive operations like
564          * JIT compilation should be avoided.
565          */
566         if (IS_ON_SIGALTSTACK (jit_tls)) {
567                 /* 
568                  * FIXME: disabling/enabling GC while already on a signal stack might
569                  * not be safe either.
570                  */
571                 /* Have to reenable it later */
572                 gc_disabled = TRUE;
573                 mono_gc_disable ();
574         }
575
576         g_assert (ctx != NULL);
577         if (!obj) {
578                 MonoException *ex = mono_get_exception_null_reference ();
579                 ex->message = mono_string_new (domain, "Object reference not set to an instance of an object");
580                 obj = (MonoObject *)ex;
581         } 
582
583         /*
584          * Allocate a new exception object instead of the preconstructed ones.
585          * We can't do this in sigsegv_signal_handler, since GC is not yet
586          * disabled.
587          */
588         if (obj == domain->stack_overflow_ex) {
589                 obj = mono_get_exception_stack_overflow ();
590                 stack_overflow = TRUE;
591         }
592         else if (obj == domain->null_reference_ex) {
593                 obj = mono_get_exception_null_reference ();
594         }
595
596         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
597                 mono_ex = (MonoException*)obj;
598                 initial_trace_ips = mono_ex->trace_ips;
599         } else {
600                 mono_ex = NULL;
601         }
602
603         if (!call_filter)
604                 call_filter = mono_arch_get_call_filter ();
605
606         if (!restore_context)
607                 restore_context = mono_arch_get_restore_context ();
608
609         g_assert (jit_tls->end_of_stack);
610         g_assert (jit_tls->abort_func);
611
612         if (!test_only) {
613                 MonoContext ctx_cp = *ctx;
614                 if (mono_jit_trace_calls != NULL)
615                         g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
616                 if (!mono_handle_exception (&ctx_cp, obj, original_ip, TRUE)) {
617                         if (mono_break_on_exc)
618                                 G_BREAKPOINT ();
619                         mono_unhandled_exception (obj);
620
621                         if (mono_debugger_unhandled_exception (original_ip, MONO_CONTEXT_GET_SP (ctx), obj)) {
622                                 /*
623                                  * If this returns true, then we're running inside the
624                                  * Mono Debugger and the debugger wants us to restore the
625                                  * context and continue (normally, the debugger inserts
626                                  * a breakpoint on the `original_ip', so it regains control
627                                  * immediately after restoring the context).
628                                  */
629                                 MONO_CONTEXT_SET_IP (ctx, original_ip);
630                                 restore_context (ctx);
631                                 g_assert_not_reached ();
632                         }
633                 }
634         }
635
636         initial_ctx = *ctx;
637         memset (&rji, 0, sizeof (rji));
638
639         while (1) {
640                 MonoContext new_ctx;
641                 guint32 free_stack;
642
643                 ji = mono_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx, 
644                                                                  NULL, &lmf, NULL, NULL);
645                 if (!ji) {
646                         g_warning ("Exception inside function without unwind info");
647                         g_assert_not_reached ();
648                 }
649
650                 if (ji != (gpointer)-1) {
651                         frame_count ++;
652                         //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
653
654                         if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
655                                 /* 
656                                  * Avoid overwriting the stack trace if the exception is
657                                  * rethrown. Also avoid giant stack traces during a stack
658                                  * overflow.
659                                  */
660                                 if (!initial_trace_ips && (frame_count < 1000)) {
661                                         trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
662                                 }
663                         }
664
665                         if (ji->method->dynamic)
666                                 has_dynamic_methods = TRUE;
667
668                         if (stack_overflow)
669                                 free_stack = (guint8*)(MONO_CONTEXT_GET_BP (ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
670                         else
671                                 free_stack = 0xffffff;
672
673                         /* 
674                          * During stack overflow, wait till the unwinding frees some stack
675                          * space before running handlers/finalizers.
676                          */
677                         if ((free_stack > (64 * 1024)) && ji->num_clauses) {
678                                 int i;
679                                 
680                                 for (i = 0; i < ji->num_clauses; i++) {
681                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
682                                         gboolean filtered = FALSE;
683
684 #ifdef __s390__
685                                         if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) && 
686 #else
687                                         if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
688 #endif
689                                             MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
690                                                 /* catch block */
691
692                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
693                                                         /* store the exception object in cfg->excvar */
694                                                         g_assert (ei->exvar_offset);
695                                                         *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
696                                                 }
697
698                                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
699                                                         mono_debugger_handle_exception (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
700                                                         filtered = call_filter (ctx, ei->data.filter);
701                                                 }
702
703                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
704                                                      mono_object_isinst (obj, ei->data.catch_class)) || filtered) {
705                                                         if (test_only) {
706                                                                 if (mono_ex && !initial_trace_ips) {
707                                                                         trace_ips = g_list_reverse (trace_ips);
708                                                                         mono_ex->trace_ips = glist_to_array (trace_ips, mono_defaults.int_class);
709                                                                         if (has_dynamic_methods)
710                                                                                 /* These methods could go away anytime, so compute the stack trace now */
711                                                                                 mono_ex->stack_trace = ves_icall_System_Exception_get_trace (mono_ex);
712                                                                 }
713                                                                 g_list_free (trace_ips);
714
715                                                                 if (gc_disabled)
716                                                                         mono_gc_enable ();
717                                                                 return TRUE;
718                                                         }
719                                                         if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
720                                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
721                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
722                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
723                                                         jit_tls->lmf = lmf;
724
725                                                         if (gc_disabled)
726                                                                 mono_gc_enable ();
727                                                         return 0;
728                                                 }
729                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
730                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
731                                                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
732                                                         if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
733                                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
734                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
735                                                         call_filter (ctx, ei->handler_start);
736                                                 }
737                                                 
738                                         }
739                                 }
740                         }
741                 }
742
743                 *ctx = new_ctx;
744
745                 if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
746                         if (gc_disabled)
747                                 mono_gc_enable ();
748
749                         if (!test_only) {
750                                 jit_tls->lmf = lmf;
751
752                                 if (IS_ON_SIGALTSTACK (jit_tls)) {
753                                         /* Switch back to normal stack */
754                                         if (stack_overflow)
755                                                 /* Free up some stack space */
756                                                 MONO_CONTEXT_SET_SP (&initial_ctx, (gssize)(MONO_CONTEXT_GET_SP (&initial_ctx)) + (64 * 1024));
757                                         MONO_CONTEXT_SET_IP (&initial_ctx, (gssize)jit_tls->abort_func);
758                                         restore_context (&initial_ctx);
759                                 }
760                                 else
761                                         jit_tls->abort_func (obj);
762                                 g_assert_not_reached ();
763                         } else {
764                                 if (mono_ex && !initial_trace_ips) {
765                                         trace_ips = g_list_reverse (trace_ips);
766                                         mono_ex->trace_ips = glist_to_array (trace_ips, mono_defaults.int_class);
767                                         if (has_dynamic_methods)
768                                                 /* These methods could go away anytime, so compute the stack trace now */
769                                                 mono_ex->stack_trace = ves_icall_System_Exception_get_trace (mono_ex);
770                                 }
771                                 g_list_free (trace_ips);
772                                 return FALSE;
773                         }
774                 }
775         }
776
777         g_assert_not_reached ();
778 }
779 #endif /* CUSTOM_EXECPTION_HANDLING */
780