2004-11-09 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / mini / exceptions-s390.c
1 /*------------------------------------------------------------------*/
2 /*                                                                  */
3 /* Name        - exceptions-s390.c                                  */
4 /*                                                                  */
5 /* Function    - Exception support for S/390.                       */
6 /*                                                                  */
7 /* Name        - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
8 /*                                                                  */
9 /* Date        - January, 2004                                      */
10 /*                                                                  */
11 /* Derivation  - From exceptions-x86 & exceptions-ppc               */
12 /*               Paolo Molaro (lupus@ximian.com)                    */
13 /*               Dietmar Maurer (dietmar@ximian.com)                */
14 /*                                                                  */
15 /* Copyright   - 2001 Ximian, Inc.                                  */
16 /*                                                                  */
17 /*------------------------------------------------------------------*/
18
19 /*------------------------------------------------------------------*/
20 /*                 D e f i n e s                                    */
21 /*------------------------------------------------------------------*/
22
23 #define MONO_CONTEXT_SET_IP(ctx,ip)                                     \
24         do {                                                            \
25                 (ctx)->uc_mcontext.gregs[14] = (unsigned long)ip;       \
26                 (ctx)->uc_mcontext.psw.addr = (unsigned long)ip;        \
27         } while (0); 
28
29 #define MONO_CONTEXT_SET_BP(ctx,bp)                                     \
30         do {                                                            \
31                 (ctx)->uc_mcontext.gregs[15] = (unsigned long)bp;       \
32                 (ctx)->uc_stack.ss_sp        = (unsigned long)bp;       \
33         } while (0); 
34
35 #define MONO_CONTEXT_GET_IP(ctx) context_get_ip ((ctx))
36 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->uc_mcontext.gregs[15]))
37
38 #define S390_CALLFILTER_INTREGS         S390_MINIMAL_STACK_SIZE
39 #define S390_CALLFILTER_FLTREGS         S390_CALLFILTER_INTREGS+(16*sizeof(gulong))
40 #define S390_CALLFILTER_ACCREGS         S390_CALLFILTER_FLTREGS+(16*sizeof(gdouble))
41 #define S390_CALLFILTER_SIZE            (S390_CALLFILTER_ACCREGS+(16*sizeof(gulong)))
42
43 #define S390_THROWSTACK_ACCPRM          S390_MINIMAL_STACK_SIZE
44 #define S390_THROWSTACK_FPCPRM          S390_THROWSTACK_ACCPRM+sizeof(gpointer)
45 #define S390_THROWSTACK_INTREGS         S390_THROWSTACK_FPCPRM+sizeof(gulong)
46 #define S390_THROWSTACK_FLTREGS         S390_THROWSTACK_INTREGS+(16*sizeof(gulong))
47 #define S390_THROWSTACK_ACCREGS         S390_THROWSTACK_FLTREGS+(16*sizeof(gdouble))
48 #define S390_THROWSTACK_SIZE            (S390_THROWSTACK_ACCREGS+(16*sizeof(gulong)))
49
50 /*========================= End of Defines =========================*/
51
52 /*------------------------------------------------------------------*/
53 /*                 I n c l u d e s                                  */
54 /*------------------------------------------------------------------*/
55
56 #include <config.h>
57 #include <glib.h>
58 #include <signal.h>
59 #include <string.h>
60 #include <ucontext.h>
61
62 #include <mono/arch/s390/s390-codegen.h>
63 #include <mono/metadata/appdomain.h>
64 #include <mono/metadata/tabledefs.h>
65 #include <mono/metadata/threads.h>
66 #include <mono/metadata/debug-helpers.h>
67 #include <mono/metadata/exception.h>
68 #include <mono/metadata/mono-debug.h>
69
70 #include "mini.h"
71 #include "mini-s390.h"
72
73 /*========================= End of Includes ========================*/
74
75 /*------------------------------------------------------------------*/
76 /*                 T y p e d e f s                                  */
77 /*------------------------------------------------------------------*/
78
79 typedef struct
80 {
81   void *prev;
82   void *unused[5];
83   void *regs[8];
84   void *return_address;
85 } MonoS390StackFrame;
86
87 /*========================= End of Typedefs ========================*/
88
89 /*------------------------------------------------------------------*/
90 /*                   P r o t o t y p e s                            */
91 /*------------------------------------------------------------------*/
92
93 gboolean mono_arch_handle_exception (void     *ctx,
94                                      gpointer obj, 
95                                      gboolean test_only);
96
97 /*========================= End of Prototypes ======================*/
98
99 /*------------------------------------------------------------------*/
100 /*                 G l o b a l   V a r i a b l e s                  */
101 /*------------------------------------------------------------------*/
102
103 /*====================== End of Global Variables ===================*/
104
105 /*------------------------------------------------------------------*/
106 /*                                                                  */
107 /* Name         - context_get_ip                                    */
108 /*                                                                  */
109 /* Function     - Extract the current instruction address from the  */
110 /*                context.                                          */
111 /*                                                                  */
112 /*------------------------------------------------------------------*/
113
114 static inline gpointer 
115 context_get_ip (MonoContext *ctx) 
116 {
117         gpointer ip;
118
119         ip = (gpointer) ((gint32) (ctx->uc_mcontext.psw.addr) & 0x7fffffff);
120         return ip;
121 }
122
123 /*========================= End of Function ========================*/
124
125 /*------------------------------------------------------------------*/
126 /*                                                                  */
127 /* Name         - mono_arch_has_unwind_info                         */
128 /*                                                                  */
129 /* Function     - Tests if a function has a DWARF exception table   */
130 /*                that is able to restore all caller saved registers*/
131 /*                                                                  */
132 /*------------------------------------------------------------------*/
133
134 gboolean
135 mono_arch_has_unwind_info (gconstpointer addr)
136 {
137         return FALSE;
138 }
139
140 /*========================= End of Function ========================*/
141
142 /*------------------------------------------------------------------*/
143 /*                                                                  */
144 /* Name         - arch_get_call_filter                              */
145 /*                                                                  */
146 /* Function     - Return a pointer to a method which calls an       */
147 /*                exception filter. We also use this function to    */
148 /*                call finally handlers (we pass NULL as @exc       */
149 /*                object in this case).                             */
150 /*                                                                  */
151 /*------------------------------------------------------------------*/
152
153 static gpointer
154 arch_get_call_filter (void)
155 {
156         static guint8 start [512];
157         static int inited = 0;
158         guint8 *code;
159         int alloc_size, pos, i;
160
161         if (inited)
162                 return start;
163
164         inited = 1;
165         /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
166         code = start;
167
168         s390_stm (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
169         s390_lr  (code, s390_r14, STK_BASE);
170         alloc_size = S390_ALIGN(S390_CALLFILTER_SIZE, S390_STACK_ALIGNMENT);
171         s390_ahi (code, STK_BASE, -alloc_size);
172         s390_st  (code, s390_r14, 0, STK_BASE, 0);
173
174         /*------------------------------------------------------*/
175         /* save general registers on stack                      */
176         /*------------------------------------------------------*/
177         s390_stm (code, s390_r0, s390_r13, STK_BASE, S390_CALLFILTER_INTREGS);
178
179         /*------------------------------------------------------*/
180         /* save floating point registers on stack               */
181         /*------------------------------------------------------*/
182 //      pos = S390_CALLFILTER_FLTREGS;
183 //      for (i = 0; i < 16; ++i) {
184 //              s390_std (code, i, 0, STK_BASE, pos);
185 //              pos += sizeof (gdouble);
186 //      }
187
188         /*------------------------------------------------------*/
189         /* save access registers on stack                       */
190         /*------------------------------------------------------*/
191 //      s390_stam (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
192
193         /*------------------------------------------------------*/
194         /* Get A(Context)                                       */
195         /*------------------------------------------------------*/
196         s390_lr   (code, s390_r13, s390_r2);
197
198         /*------------------------------------------------------*/
199         /* Get A(Handler Entry Point)                           */
200         /*------------------------------------------------------*/
201         s390_lr   (code, s390_r0, s390_r3);
202
203         /*------------------------------------------------------*/
204         /* Set parameter register with Exception                */
205         /*------------------------------------------------------*/
206         s390_lr   (code, s390_r2, s390_r4);
207
208         /*------------------------------------------------------*/
209         /* Load all registers with values from the context      */
210         /*------------------------------------------------------*/
211         s390_lm   (code, s390_r3, s390_r12, s390_r13, G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs[3]));
212         pos = G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs[0]);
213         for (i = 0; i < 16; ++i) {
214                 s390_ld  (code, i, 0, s390_r13, pos);
215                 pos += sizeof(gdouble);
216         }
217         
218         /*------------------------------------------------------*/
219         /* Point at the copied stack frame and call the filter  */
220         /*------------------------------------------------------*/
221         s390_lr   (code, s390_r1, s390_r0);
222         s390_basr (code, s390_r14, s390_r1);
223
224         /*------------------------------------------------------*/
225         /* Save return value                                    */
226         /*------------------------------------------------------*/
227         s390_lr   (code, s390_r14, s390_r2);
228
229         /*------------------------------------------------------*/
230         /* Restore all the regs from the stack                  */
231         /*------------------------------------------------------*/
232         s390_lm (code, s390_r0, s390_r13, STK_BASE, S390_CALLFILTER_INTREGS);
233 //      pos = S390_CALLFILTER_FLTREGS;
234 //      for (i = 0; i < 16; ++i) {
235 //              s390_ld (code, i, 0, STK_BASE, pos);
236 //              pos += sizeof (gdouble);
237 //      }
238
239         s390_lr   (code, s390_r2, s390_r14);
240 //      s390_lam  (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
241         s390_ahi  (code, s390_r15, alloc_size);
242         s390_lm   (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
243         s390_br   (code, s390_r14);
244
245         g_assert ((code - start) < sizeof(start));
246         return start;
247 }
248
249 /*========================= End of Function ========================*/
250
251 /*------------------------------------------------------------------*/
252 /*                                                                  */
253 /* Name         - throw_exception.                                  */
254 /*                                                                  */
255 /* Function     - Raise an exception based on the parameters passed.*/
256 /*                                                                  */
257 /*------------------------------------------------------------------*/
258
259 static void
260 throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp, 
261                  gulong *int_regs, gdouble *fp_regs, gulong *acc_regs, guint fpc)
262 {
263         static void (*restore_context) (MonoContext *);
264         MonoContext ctx;
265         int iReg;
266         
267         memset(&ctx, 0, sizeof(ctx));
268
269         getcontext(&ctx);
270
271         /* adjust eip so that it point into the call instruction */
272         ip -= 6;
273
274         for (iReg = 0; iReg < 16; iReg++) {
275                 ctx.uc_mcontext.gregs[iReg]         = int_regs[iReg];
276                 ctx.uc_mcontext.fpregs.fprs[iReg].d = fp_regs[iReg];
277                 ctx.uc_mcontext.aregs[iReg]         = acc_regs[iReg];
278         }
279
280         ctx.uc_mcontext.fpregs.fpc = fpc;
281
282         MONO_CONTEXT_SET_BP (&ctx, sp);
283         MONO_CONTEXT_SET_IP (&ctx, ip);
284         
285         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
286                 MonoException *mono_ex = (MonoException*)exc;
287                 mono_ex->stack_trace = NULL;
288         }
289         mono_arch_handle_exception (&ctx, exc, FALSE);
290         setcontext(&ctx);
291
292         g_assert_not_reached ();
293 }
294
295 /*========================= End of Function ========================*/
296
297 /*------------------------------------------------------------------*/
298 /*                                                                  */
299 /* Name         - arch_get_throw_exception_generic                  */
300 /*                                                                  */
301 /* Function     - Return a function pointer which can be used to    */
302 /*                raise exceptions. The returned function has the   */
303 /*                following signature:                              */
304 /*                void (*func) (MonoException *exc); or,            */
305 /*                void (*func) (char *exc_name);                    */
306 /*                                                                  */
307 /*------------------------------------------------------------------*/
308
309 static gpointer 
310 mono_arch_get_throw_exception_generic (guint8 *start, int size, int by_name)
311 {
312         guint8 *code;
313         int alloc_size, pos, i, offset;
314
315         code = start;
316
317         s390_stm (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
318         alloc_size = S390_ALIGN(S390_THROWSTACK_SIZE, S390_STACK_ALIGNMENT);
319         s390_lr   (code, s390_r14, STK_BASE);
320         s390_ahi  (code, STK_BASE, -alloc_size);
321         s390_st   (code, s390_r14, 0, STK_BASE, 0);
322         if (by_name) {
323                 s390_lr   (code, s390_r4, s390_r2);
324                 s390_bras (code, s390_r13, 6);
325                 s390_word (code, mono_defaults.corlib);
326                 s390_word (code, "System");
327                 s390_l    (code, s390_r2, 0, s390_r13, 0);
328                 s390_l    (code, s390_r3, 0, s390_r13, 4);
329                 offset = (guint32) S390_RELATIVE(mono_exception_from_name, code);
330                 s390_brasl(code, s390_r14, offset);
331         }
332         /*------------------------------------------------------*/
333         /* save the general registers on the stack              */
334         /*------------------------------------------------------*/
335         s390_stm (code, s390_r0, s390_r13, STK_BASE, S390_THROWSTACK_INTREGS);
336
337         s390_lr  (code, s390_r1, STK_BASE);
338         s390_ahi (code, s390_r1, alloc_size);
339         /*------------------------------------------------------*/
340         /* save the return address in the parameter register    */
341         /*------------------------------------------------------*/
342         s390_l   (code, s390_r3, 0, s390_r1, S390_RET_ADDR_OFFSET);
343
344         /*------------------------------------------------------*/
345         /* save the floating point registers                    */
346         /*------------------------------------------------------*/
347         pos = S390_THROWSTACK_FLTREGS;
348         for (i = 0; i < 16; ++i) {
349                 s390_std (code, i, 0,STK_BASE, pos);
350                 pos += sizeof (gdouble);
351         }
352         /*------------------------------------------------------*/
353         /* save the access registers                            */
354         /*------------------------------------------------------*/
355         s390_stam (code, s390_r0, s390_r15, STK_BASE, S390_THROWSTACK_ACCREGS);
356
357         /*------------------------------------------------------*/
358         /* call throw_exception (exc, ip, sp, gr, fr, ar)       */
359         /* exc is already in place in r2                        */
360         /*------------------------------------------------------*/
361         s390_lr   (code, s390_r4, s390_r1);        /* caller sp */
362         /*------------------------------------------------------*/
363         /* pointer to the saved int regs                        */
364         /*------------------------------------------------------*/
365         s390_la   (code, s390_r5, 0, STK_BASE, S390_THROWSTACK_INTREGS);
366         s390_la   (code, s390_r6, 0, STK_BASE, S390_THROWSTACK_FLTREGS);
367         s390_la   (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCREGS);
368         s390_st   (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCPRM);
369         s390_stfpc(code, STK_BASE, S390_THROWSTACK_FPCPRM);
370         offset = (guint32) S390_RELATIVE(throw_exception, code);
371         s390_brasl(code, s390_r14, offset);
372         /* we should never reach this breakpoint */
373         s390_break (code);
374         g_assert ((code - start) < size);
375         return start;
376 }
377
378 /*========================= End of Function ========================*/
379
380 /*------------------------------------------------------------------*/
381 /*                                                                  */
382 /* Name         - arch_get_throw_exception                          */
383 /*                                                                  */
384 /* Function     - Return a function pointer which can be used to    */
385 /*                raise exceptions. The returned function has the   */
386 /*                following signature:                              */
387 /*                void (*func) (MonoException *exc);                */
388 /*                                                                  */
389 /*------------------------------------------------------------------*/
390
391 gpointer 
392 mono_arch_get_throw_exception (void)
393 {
394         static guint8 start [256];
395         static int inited = 0;
396
397         if (inited)
398                 return start;
399         mono_arch_get_throw_exception_generic (start, sizeof (start), FALSE);
400         inited = 1;
401         return start;
402 }
403
404 /*========================= End of Function ========================*/
405
406 /*------------------------------------------------------------------*/
407 /*                                                                  */
408 /* Name         - arch_get_throw_exception_by_name                  */
409 /*                                                                  */
410 /* Function     - Return a function pointer which can be used to    */
411 /*                raise corlib exceptions. The return function has  */
412 /*                the following signature:                          */
413 /*                void (*func) (char *exc_name);                    */
414 /*                                                                  */
415 /*------------------------------------------------------------------*/
416
417 gpointer 
418 mono_arch_get_throw_exception_by_name (void)
419 {
420         static guint8 start [160];
421         static int inited = 0;
422
423         if (inited)
424                 return start;
425         mono_arch_get_throw_exception_generic (start, sizeof (start), TRUE);
426         inited = 1;
427         return start;
428 }       
429
430 /*========================= End of Function ========================*/
431
432 /*------------------------------------------------------------------*/
433 /*                                                                  */
434 /* Name         - glist_to_array                                    */
435 /*                                                                  */
436 /* Function     - Convert a list to a mono array.                   */
437 /*                                                                  */
438 /*------------------------------------------------------------------*/
439
440 static MonoArray *
441 glist_to_array (GList *list) 
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, mono_defaults.int_class, 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 /*========================= End of Function ========================*/
460
461 /*------------------------------------------------------------------*/
462 /*                                                                  */
463 /* Name         - mono_arch_find_jit_info                           */
464 /*                                                                  */
465 /* Function     - This function is used to gather informatoin from  */
466 /*                @ctx. It returns the MonoJitInfo of the corres-   */
467 /*                ponding function, unwinds one stack frame and     */
468 /*                stores the resulting context into @new_ctx. It    */
469 /*                also stores a string describing the stack location*/
470 /*                into @trace (if not NULL), and modifies the @lmf  */
471 /*                if necessary. @native_offset returns the IP off-  */
472 /*                set from the start of the function or -1 if that  */
473 /*                informatoin is not available.                     */
474 /*                                                                  */
475 /*------------------------------------------------------------------*/
476
477 MonoJitInfo *
478 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
479                          MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
480                          MonoContext *new_ctx, char **trace, MonoLMF **lmf, 
481                          int *native_offset, gboolean *managed)
482 {
483         MonoJitInfo *ji;
484         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
485         unsigned long *ptr;
486         char *p;
487         MonoS390StackFrame *sframe;
488
489         if (prev_ji && 
490             (ip > prev_ji->code_start && 
491             ((guint8 *) ip < ((guint8 *) prev_ji->code_start) + prev_ji->code_size)))
492                 ji = prev_ji;
493         else
494                 ji = mono_jit_info_table_find (domain, ip);
495
496         if (trace)
497                 *trace = NULL;
498
499         if (native_offset)
500                 *native_offset = -1;
501
502         if (managed)
503                 *managed = FALSE;
504
505         if (ji != NULL) {
506                 char *source_location, *tmpaddr, *fname;
507                 gint32 address, iloffset;
508                 int offset;
509
510                 *new_ctx = *ctx;
511
512                 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
513                         /* remove any unused lmf */
514                         *lmf = (*lmf)->previous_lmf;
515                 }
516
517                 address = (char *)ip - (char *)ji->code_start;
518
519                 if (native_offset)
520                         *native_offset = address;
521
522                 if (managed)
523                         if (!ji->method->wrapper_type)
524                                 *managed = TRUE;
525
526                 if (trace) {
527                         source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
528                         iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
529
530                         if (iloffset < 0)
531                                 tmpaddr = g_strdup_printf ("<0x%08x>", address);
532                         else
533                                 tmpaddr = g_strdup_printf ("[0x%08x]", iloffset);
534                 
535                         fname = mono_method_full_name (ji->method, TRUE);
536
537                         if (source_location)
538                                 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
539                         else
540                                 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
541
542                         g_free (fname);
543                         g_free (source_location);
544                         g_free (tmpaddr);
545                 }
546                 sframe = (MonoS390StackFrame *) MONO_CONTEXT_GET_BP (ctx);
547                 MONO_CONTEXT_SET_BP (new_ctx, sframe->prev);
548                 sframe = (MonoS390StackFrame *) sframe->prev;
549                 MONO_CONTEXT_SET_IP (new_ctx, sframe->return_address);
550                 memcpy (&new_ctx->uc_mcontext.gregs[6], sframe->regs, (8*sizeof(gint32)));
551                 *res = *ji;
552                 return res;
553         } else if (*lmf) {
554                 
555                 *new_ctx = *ctx;
556
557                 if (!(*lmf)->method)
558                         return (gpointer)-1;
559
560                 if (trace)
561                         *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
562                 
563                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
564                         *res = *ji;
565                 } else {
566                         memset (res, 0, sizeof (MonoJitInfo));
567                         res->method = (*lmf)->method;
568                 }
569
570                 memcpy(new_ctx->uc_mcontext.gregs, (*lmf)->gregs, sizeof((*lmf)->gregs));
571                 memcpy(new_ctx->uc_mcontext.fpregs.fprs, (*lmf)->fregs, sizeof((*lmf)->fregs));
572
573                 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
574                 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
575                 *lmf = (*lmf)->previous_lmf;
576
577                 return res;
578                 
579         }
580
581         return NULL;
582 }
583
584 /*========================= End of Function ========================*/
585
586 /*------------------------------------------------------------------*/
587 /*                                                                  */
588 /* Name         - ves_icall_get_trace                               */
589 /*                                                                  */
590 /* Function     -                                                   */
591 /*                                                                  */
592 /*------------------------------------------------------------------*/
593
594 MonoArray *
595 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
596 {
597         MonoDomain *domain = mono_domain_get ();
598         MonoArray *res;
599         MonoArray *ta = exc->trace_ips;
600         int i, len;
601         
602         if (ta == NULL) {
603                 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
604         }
605
606         len = mono_array_length (ta);
607
608         res = mono_array_new (domain, mono_defaults.stack_frame_class, 
609                               len > skip ? len - skip : 0);
610
611         for (i = skip; i < len; i++) {
612                 MonoJitInfo *ji;
613                 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
614                 gpointer ip = mono_array_get (ta, gpointer, i);
615
616                 ji = mono_jit_info_table_find (domain, ip);
617                 if (ji == NULL) {
618                         mono_array_set (res, gpointer, i, sf);
619                         continue;
620                 }
621
622                 sf->method = mono_method_get_object (domain, ji->method, NULL);
623                 sf->native_offset = (char *)ip - (char *)ji->code_start;
624
625                 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
626
627                 if (need_file_info) {
628                         gchar *filename;
629                         
630                         filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
631
632                         sf->filename = filename? mono_string_new (domain, filename): NULL;
633                         sf->column = 0;
634
635                         g_free (filename);
636                 }
637
638                 mono_array_set (res, gpointer, i, sf);
639         }
640
641         return res;
642 }
643
644 /*========================= End of Function ========================*/
645
646 /*------------------------------------------------------------------*/
647 /*                                                                  */
648 /* Name         - mono_jit_walk_stack                               */
649 /*                                                                  */
650 /* Function     -                                                   */
651 /*                                                                  */
652 /*------------------------------------------------------------------*/
653
654 void
655 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data) {
656         MonoDomain *domain = mono_domain_get ();
657         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
658         MonoLMF *lmf = jit_tls->lmf;
659         MonoJitInfo *ji, rji;
660         gint native_offset, il_offset;
661         gboolean managed;
662         MonoContext ctx, new_ctx;
663
664         MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
665         MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
666
667         while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
668                 
669                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, NULL, 
670                                               &ctx, &new_ctx, NULL, &lmf, 
671                                               &native_offset, &managed);
672                 g_assert (ji);
673
674                 if (ji == (gpointer)-1)
675                         return;
676
677                 il_offset = do_il_offset ? mono_debug_il_offset_from_address (ji->method, native_offset, domain): -1;
678
679                 if (func (ji->method, native_offset, il_offset, managed, user_data))
680                         return;
681                 
682                 ctx = new_ctx;
683         }
684 }
685
686 /*========================= End of Function ========================*/
687
688 /*------------------------------------------------------------------*/
689 /*                                                                  */
690 /* Name         - ves_icall_get_frame_info                          */
691 /*                                                                  */
692 /* Function     -                                                   */
693 /*                                                                  */
694 /*------------------------------------------------------------------*/
695
696 MonoBoolean
697 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
698                           MonoReflectionMethod **method, 
699                           gint32 *iloffset, gint32 *native_offset,
700                           MonoString **file, gint32 *line, gint32 *column)
701 {
702         MonoDomain *domain = mono_domain_get ();
703         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
704         MonoLMF *lmf = jit_tls->lmf;
705         MonoJitInfo *ji, rji;
706         MonoContext ctx, new_ctx;
707
708         MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
709         MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
710
711         skip++;
712
713         do {
714                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, NULL, 
715                                               &ctx, &new_ctx, NULL, &lmf, 
716                                               native_offset, NULL);
717
718                 ctx = new_ctx;
719                 
720                 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
721                         return FALSE;
722
723                 /* skip all wrappers ??*/
724                 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
725                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
726                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
727                         continue;
728
729                 skip--;
730
731         } while (skip >= 0);
732
733         *method = mono_method_get_object (domain, ji->method, NULL);
734         *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset, domain);
735
736         if (need_file_info) {
737                 gchar *filename;
738
739                 filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
740
741                 *file = filename? mono_string_new (domain, filename): NULL;
742                 *column = 0;
743
744                 g_free (filename);
745         }
746
747         return TRUE;
748 }
749
750 /*========================= End of Function ========================*/
751
752 /*------------------------------------------------------------------*/
753 /*                                                                  */
754 /* Name         - mono_arch_handle_exception                        */
755 /*                                                                  */
756 /* Function     - Handle an exception raised by the JIT code.       */
757 /*                                                                  */
758 /* Parameters   - ctx       - Saved processor state                 */
759 /*                obj       - The exception object                  */
760 /*                test_only - Only test if the exception is caught, */
761 /*                            but don't call handlers               */
762 /*                                                                  */
763 /*------------------------------------------------------------------*/
764
765 gboolean
766 mono_arch_handle_exception (void *uc, gpointer obj, gboolean test_only)
767 {
768         MonoContext     *ctx = uc;
769         MonoDomain      *domain = mono_domain_get ();
770         MonoJitInfo     *ji, rji;
771         static int      (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
772         MonoJitTlsData  *jit_tls = TlsGetValue (mono_jit_tls_id);
773         MonoLMF         *lmf = jit_tls->lmf;            
774         GList           *trace_ips = NULL;
775         GString         *traceStr  = NULL;
776         MonoException   *mono_ex;
777         MonoString      *initialStackTrace = NULL;
778         int             frameCount = 0;
779
780         g_assert (ctx != NULL);
781         memset(&rji, 0, sizeof(rji));
782         if (!obj) {
783                 MonoException *ex = mono_get_exception_null_reference ();
784                 ex->message = mono_string_new (domain, 
785                         "Object reference not set to an instance of an object");
786                 obj = (MonoObject *)ex;
787         } 
788
789         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
790                 mono_ex = (MonoException*)obj;
791                 mono_ex->stack_trace = NULL;
792         } else {
793                 mono_ex = NULL;
794         }
795
796
797         if (!call_filter)
798                 call_filter = arch_get_call_filter ();
799
800         g_assert (jit_tls->end_of_stack);
801         g_assert (jit_tls->abort_func);
802
803         if (!test_only) {
804                 MonoContext ctx_cp = *ctx;
805                 if (mono_jit_trace_calls != NULL)
806                         g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
807                 if (!mono_arch_handle_exception (&ctx_cp, obj, TRUE)) {
808                         if (mono_break_on_exc)
809                                 G_BREAKPOINT ();
810                         mono_unhandled_exception (obj);
811                 }
812         }
813
814         memset (&rji, 0, sizeof(rji));
815
816         while (1) {
817                 MonoContext new_ctx;
818                 char *trace = NULL;
819                 gboolean needTrace = FALSE;
820
821                 if (test_only && (frameCount < 1000)) {
822                         needTrace = TRUE;
823                         if (!traceStr)
824                                 traceStr = g_string_new ("");
825                 }       
826                 
827                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx, 
828                                               test_only ? &trace : NULL, &lmf, NULL, NULL);
829                 if (!ji) {
830                         g_warning ("Exception inside function without unwind info");
831                         g_assert_not_reached ();
832                 }
833
834                 if (ji != (gpointer)-1) {
835                         frameCount++;
836
837                         if ((test_only) && 
838                             (ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) && 
839                             (mono_ex)) {
840                                 if (!initialStackTrace && (frameCount < 1000)) {
841                                         trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
842                                         g_string_append   (traceStr, trace);
843                                         g_string_append_c (traceStr, '\n');
844                                 }
845                         }               
846                         
847                         if (ji->num_clauses) {
848                                 int i;
849                                 
850                                 g_assert (ji->clauses);
851                         
852                                 for (i = 0; i < ji->num_clauses; i++) {
853                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
854                                         gboolean filtered = FALSE;
855
856                                         if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) && 
857                                             MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
858                                                 /* catch block */
859                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) ||
860                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
861                                                         g_assert (ji->exvar_offset);
862                                                         *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
863                                                         if (!initialStackTrace &&
864                                                             traceStr) {
865                                                                 mono_ex->stack_trace =  mono_string_new (domain, traceStr->str);
866                                                         }
867                                                 }
868
869                                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) 
870                                                       filtered = call_filter (ctx, ei->data.filter, obj);
871
872                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) &&
873                                                     (mono_object_isinst (obj, ei->data.catch_class)) || 
874                                                     (filtered)) {
875                                                         if (test_only) {
876                                                                 if (mono_ex) {
877                                                                         trace_ips = g_list_reverse (trace_ips);
878                                                                         mono_ex->trace_ips = glist_to_array (trace_ips);
879                                                                 }
880                                                                 g_list_free (trace_ips);
881                                                                 g_free (trace);
882                                                                 if (traceStr)
883                                                                         g_string_free (traceStr, TRUE);
884
885                                                                 return TRUE;
886                                                         }
887
888                                                         if (mono_jit_trace_calls != NULL)
889                                                                 g_print ("EXCEPTION: catch found at clause %d of %s - caught at %p with sp %p\n", 
890                                                                          i, mono_method_full_name (ji->method, TRUE),
891                                                                          ei->handler_start,
892                                                                          MONO_CONTEXT_GET_BP(ctx));
893                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
894                                                         jit_tls->lmf = lmf;
895                                                         g_free (trace);
896                                                         if (traceStr)
897                                                                 g_string_free (traceStr, TRUE);
898                                                         return FALSE;
899                                                 }
900
901                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
902                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
903                                                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
904                                                         if (mono_jit_trace_calls != NULL)
905                                                                 g_print ("EXCEPTION: finally clause %d of %s handled at: %p using sp: %p\n", 
906                                                                 i, mono_method_full_name (ji->method, TRUE),
907                                                                 ei->handler_start,
908                                                                 MONO_CONTEXT_GET_BP(ctx));
909                                                         call_filter (ctx, ei->handler_start, NULL);
910                                                 }
911                                                 
912                                         }
913                                 }
914                         }
915                 }
916
917                 g_free (trace);
918                         
919                 *ctx = new_ctx;
920
921                 if ((ji == (gpointer)-1) || 
922                     (MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack)) {
923                         if (!test_only) {
924                                 jit_tls->lmf = lmf;
925                                 jit_tls->abort_func (obj);
926                                 g_assert_not_reached ();
927                         } else {
928                                 if (mono_ex) {
929                                         trace_ips = g_list_reverse (trace_ips);
930                                         mono_ex->trace_ips = glist_to_array (trace_ips);
931                                 }
932                                 g_list_free (trace_ips);
933                                 if (traceStr)
934                                         g_string_free (traceStr, TRUE);
935                                 return FALSE;
936                         }
937                 }
938         }
939
940         g_assert_not_reached ();
941 }
942
943 /*========================= End of Function ========================*/
944
945 /*------------------------------------------------------------------*/
946 /*                                                                  */
947 /* Name         - mono_arch_ip_from_context                         */
948 /*                                                                  */
949 /* Function     - Return the instruction pointer from the context.  */
950 /*                                                                  */
951 /* Parameters   - sigctx    - Saved processor state                 */
952 /*                                                                  */
953 /*------------------------------------------------------------------*/
954
955 gpointer
956 mono_arch_ip_from_context (void *sigctx)
957 {
958         return context_get_ip (sigctx);
959 }
960