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