Mon Apr 18 16:20:32 CEST 2005 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / exceptions-ppc.c
1 /*
2  * exceptions-ppc.c: exception support for PowerPC
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <ucontext.h>
16
17 #include <mono/arch/ppc/ppc-codegen.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/threads.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/metadata/exception.h>
23 #include <mono/metadata/mono-debug.h>
24
25 #include "mini.h"
26 #include "mini-ppc.h"
27
28 static gboolean arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only);
29
30 /*
31
32 struct sigcontext {
33     int      sc_onstack;     // sigstack state to restore 
34     int      sc_mask;        // signal mask to restore 
35     int      sc_ir;          // pc 
36     int      sc_psw;         // processor status word 
37     int      sc_sp;          // stack pointer if sc_regs == NULL 
38     void    *sc_regs;        // (kernel private) saved state 
39 };
40
41 struct ucontext {
42         int             uc_onstack;
43         sigset_t        uc_sigmask;     // signal mask used by this context 
44         stack_t         uc_stack;       // stack used by this context 
45         struct ucontext *uc_link;       // pointer to resuming context 
46         size_t          uc_mcsize;      // size of the machine context passed in 
47         mcontext_t      uc_mcontext;    // machine specific context 
48 };
49
50 typedef struct ppc_exception_state {
51         unsigned long dar;      // Fault registers for coredump 
52         unsigned long dsisr;
53         unsigned long exception;// number of powerpc exception taken 
54         unsigned long pad0;     // align to 16 bytes 
55
56         unsigned long pad1[4];  // space in PCB "just in case" 
57 } ppc_exception_state_t;
58
59 typedef struct ppc_vector_state {
60         unsigned long   save_vr[32][4];
61         unsigned long   save_vscr[4];
62         unsigned int    save_pad5[4];
63         unsigned int    save_vrvalid;                   // VRs that have been saved 
64         unsigned int    save_pad6[7];
65 } ppc_vector_state_t;
66
67 typedef struct ppc_float_state {
68         double  fpregs[32];
69
70         unsigned int fpscr_pad; // fpscr is 64 bits, 32 bits of rubbish 
71         unsigned int fpscr;     // floating point status register 
72 } ppc_float_state_t;
73
74 typedef struct ppc_thread_state {
75         unsigned int srr0;      // Instruction address register (PC) 
76         unsigned int srr1;      // Machine state register (supervisor) 
77         unsigned int r0;
78         unsigned int r1;
79         unsigned int r2;
80         ... 
81         unsigned int r31;
82         unsigned int cr;        // Condition register 
83         unsigned int xer;       // User's integer exception register 
84         unsigned int lr;        // Link register 
85         unsigned int ctr;       // Count register 
86         unsigned int mq;        // MQ register (601 only) 
87
88         unsigned int vrsave;    // Vector Save Register 
89 } ppc_thread_state_t;
90
91 struct mcontext {
92         ppc_exception_state_t   es;
93         ppc_thread_state_t      ss;
94         ppc_float_state_t       fs;
95         ppc_vector_state_t      vs;
96 };
97
98 typedef struct mcontext  * mcontext_t;
99
100 Linux/PPC instead has:
101 struct sigcontext {
102         unsigned long   _unused[4];
103         int             signal;
104         unsigned long   handler;
105         unsigned long   oldmask;
106         struct pt_regs  *regs;
107 };
108 struct pt_regs {
109         unsigned long gpr[32];
110         unsigned long nip;
111         unsigned long msr;
112         unsigned long orig_gpr3;        // Used for restarting system calls 
113         unsigned long ctr;
114         unsigned long link;
115         unsigned long xer;
116         unsigned long ccr;
117         unsigned long mq;               // 601 only (not used at present) 
118                                         // Used on APUS to hold IPL value. 
119         unsigned long trap;             // Reason for being here 
120         // N.B. for critical exceptions on 4xx, the dar and dsisr
121         // fields are overloaded to hold srr0 and srr1. 
122         unsigned long dar;              // Fault registers 
123         unsigned long dsisr;            // on 4xx/Book-E used for ESR 
124         unsigned long result;           // Result of a system call 
125 };
126 struct mcontext {
127         elf_gregset_t   mc_gregs;
128         elf_fpregset_t  mc_fregs;
129         unsigned long   mc_pad[2];
130         elf_vrregset_t  mc_vregs __attribute__((__aligned__(16)));
131 };
132
133 struct ucontext {
134         unsigned long    uc_flags;
135         struct ucontext *uc_link;
136         stack_t          uc_stack;
137         int              uc_pad[7];
138         struct mcontext *uc_regs;       // points to uc_mcontext field 
139         sigset_t         uc_sigmask;
140         // glibc has 1024-bit signal masks, ours are 64-bit 
141         int              uc_maskext[30];
142         int              uc_pad2[3];
143         struct mcontext  uc_mcontext;
144 };
145
146 #define ELF_NGREG       48      // includes nip, msr, lr, etc. 
147 #define ELF_NFPREG      33      // includes fpscr 
148
149 // General registers 
150 typedef unsigned long elf_greg_t;
151 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
152
153 // Floating point registers 
154 typedef double elf_fpreg_t;
155 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
156
157
158 */
159
160
161 #define restore_regs_from_context(ctx_reg,ip_reg,tmp_reg) do {  \
162                 int reg;        \
163                 ppc_lwz (code, ip_reg, G_STRUCT_OFFSET (MonoContext, sc_ir), ctx_reg);  \
164                 ppc_lmw (code, ppc_r13, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs));  \
165                 for (reg = 0; reg < MONO_SAVED_FREGS; ++reg) {  \
166                         ppc_lfd (code, (14 + reg), G_STRUCT_OFFSET(MonoLMF, fregs) + reg * sizeof (gdouble), ctx_reg);  \
167                 }       \
168         } while (0)
169
170 /* nothing to do */
171 #define setup_context(ctx)
172
173 /*
174  * arch_get_restore_context:
175  *
176  * Returns a pointer to a method which restores a previously saved sigcontext.
177  * The first argument in r3 is the pointer to the context.
178  */
179 static gpointer
180 arch_get_restore_context (void)
181 {
182         guint8 *code;
183         static guint8 start [128];
184         static int inited = 0;
185
186         if (inited)
187                 return start;
188         inited = 1;
189
190         code = start;
191         restore_regs_from_context (ppc_r3, ppc_r4, ppc_r5);
192         /* restore also the stack pointer */
193         ppc_lwz (code, ppc_sp, G_STRUCT_OFFSET (MonoContext, sc_sp), ppc_r3);
194         //ppc_break (code);
195         /* jump to the saved IP */
196         ppc_mtctr (code, ppc_r4);
197         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
198         /* never reached */
199         ppc_break (code);
200
201         g_assert ((code - start) < sizeof(start));
202         mono_arch_flush_icache (start, code - start);
203         return start;
204 }
205
206 /*
207  * arch_get_call_filter:
208  *
209  * Returns a pointer to a method which calls an exception filter. We
210  * also use this function to call finally handlers (we pass NULL as 
211  * @exc object in this case).
212  */
213 static gpointer
214 arch_get_call_filter (void)
215 {
216         static guint8 start [320];
217         static int inited = 0;
218         guint8 *code;
219         int alloc_size, pos, i;
220
221         if (inited)
222                 return start;
223
224         inited = 1;
225         /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
226         code = start;
227
228         /* save all the regs on the stack */
229         pos = 0;
230         for (i = 31; i >= 14; --i) {
231                 pos += sizeof (gdouble);
232                 ppc_stfd (code, i, -pos, ppc_sp);
233         }
234         pos += sizeof (gulong) * MONO_SAVED_GREGS;
235         ppc_stmw (code, ppc_r13, ppc_sp, -pos);
236
237         ppc_mflr (code, ppc_r0);
238         ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
239
240         alloc_size = PPC_MINIMAL_STACK_SIZE + pos + 64;
241         // align to PPC_STACK_ALIGNMENT bytes
242         alloc_size += PPC_STACK_ALIGNMENT - 1;
243         alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
244
245         g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
246         ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
247
248         /* restore all the regs from ctx (in r3), but not r1, the stack pointer */
249         restore_regs_from_context (ppc_r3, ppc_r6, ppc_r7);
250         /* call handler at eip (r4) and set the first arg with the exception (r5) */
251         ppc_mtctr (code, ppc_r4);
252         ppc_mr (code, ppc_r3, ppc_r5);
253         ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
254
255         /* epilog */
256         ppc_lwz (code, ppc_r0, alloc_size + PPC_RET_ADDR_OFFSET, ppc_sp);
257         ppc_mtlr (code, ppc_r0);
258         ppc_addic (code, ppc_sp, ppc_sp, alloc_size);
259         
260         /* restore all the regs from the stack */
261         pos = 0;
262         for (i = 31; i >= 14; --i) {
263                 pos += sizeof (double);
264                 ppc_lfd (code, i, -pos, ppc_sp);
265         }
266         pos += sizeof (gulong) * MONO_SAVED_GREGS;
267         ppc_lmw (code, ppc_r13, ppc_sp, -pos);
268
269         ppc_blr (code);
270
271         g_assert ((code - start) < sizeof(start));
272         mono_arch_flush_icache (start, code - start);
273         return start;
274 }
275
276 static void
277 throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs, gboolean rethrow)
278 {
279         static void (*restore_context) (MonoContext *);
280         MonoContext ctx;
281
282         if (!restore_context)
283                 restore_context = arch_get_restore_context ();
284
285         /* adjust eip so that it point into the call instruction */
286         eip -= 4;
287
288         setup_context (&ctx);
289
290         /*printf ("stack in throw: %p\n", esp);*/
291         MONO_CONTEXT_SET_BP (&ctx, esp);
292         MONO_CONTEXT_SET_IP (&ctx, eip);
293         memcpy (&ctx.regs, int_regs, sizeof (gulong) * MONO_SAVED_GREGS);
294         memcpy (&ctx.fregs, fp_regs, sizeof (double) * MONO_SAVED_FREGS);
295
296         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
297                 MonoException *mono_ex = (MonoException*)exc;
298                 if (!rethrow)
299                         mono_ex->stack_trace = NULL;
300         }
301         arch_handle_exception (&ctx, exc, FALSE);
302         restore_context (&ctx);
303
304         g_assert_not_reached ();
305 }
306
307 /**
308  * arch_get_throw_exception_generic:
309  *
310  * Returns a function pointer which can be used to raise 
311  * exceptions. The returned function has the following 
312  * signature: void (*func) (MonoException *exc); or
313  * void (*func) (char *exc_name);
314  *
315  */
316 static gpointer 
317 mono_arch_get_throw_exception_generic (guint8 *start, int size, int by_name, gboolean rethrow)
318 {
319         guint8 *code;
320         int alloc_size, pos, i;
321
322         code = start;
323
324         /* save all the regs on the stack */
325         pos = 0;
326         for (i = 31; i >= 14; --i) {
327                 pos += sizeof (gdouble);
328                 ppc_stfd (code, i, -pos, ppc_sp);
329         }
330         pos += sizeof (gulong) * MONO_SAVED_GREGS;
331         ppc_stmw (code, ppc_r13, ppc_sp, -pos);
332
333         ppc_mflr (code, ppc_r0);
334         ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
335
336         alloc_size = PPC_MINIMAL_STACK_SIZE + pos + 64;
337         // align to PPC_STACK_ALIGNMENT bytes
338         alloc_size += PPC_STACK_ALIGNMENT - 1;
339         alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
340
341         g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
342         ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
343
344         //ppc_break (code);
345         if (by_name) {
346                 ppc_mr (code, ppc_r5, ppc_r3);
347                 ppc_load (code, ppc_r3, mono_defaults.corlib);
348                 ppc_load (code, ppc_r4, "System");
349                 ppc_load (code, ppc_r0, mono_exception_from_name);
350                 ppc_mtctr (code, ppc_r0);
351                 ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
352         }
353
354         /* call throw_exception (exc, ip, sp, int_regs, fp_regs) */
355         /* caller sp */
356         ppc_lwz (code, ppc_r5, 0, ppc_sp); 
357         /* exc is already in place in r3 */
358         if (by_name)
359                 ppc_lwz (code, ppc_r4, PPC_RET_ADDR_OFFSET, ppc_r5); 
360         else
361                 ppc_mr (code, ppc_r4, ppc_r0); /* caller ip */
362         /* pointer to the saved fp regs */
363         pos = alloc_size - sizeof (double) * MONO_SAVED_FREGS;
364         ppc_addi (code, ppc_r7, ppc_sp, pos);
365         /* pointer to the saved int regs */
366         pos -= sizeof (gulong) * MONO_SAVED_GREGS;
367         ppc_addi (code, ppc_r6, ppc_sp, pos);
368         ppc_li (code, ppc_r8, rethrow);
369
370         ppc_load (code, ppc_r0, throw_exception);
371         ppc_mtctr (code, ppc_r0);
372         ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
373         /* we should never reach this breakpoint */
374         ppc_break (code);
375         g_assert ((code - start) < size);
376         mono_arch_flush_icache (start, code - start);
377         return start;
378 }
379
380 /**
381  * mono_arch_get_rethrow_exception:
382  *
383  * Returns a function pointer which can be used to rethrow 
384  * exceptions. The returned function has the following 
385  * signature: void (*func) (MonoException *exc); 
386  *
387  */
388 gpointer
389 mono_arch_get_rethrow_exception (void)
390 {
391         static guint8 start [132];
392         static int inited = 0;
393
394         if (inited)
395                 return start;
396         mono_arch_get_throw_exception_generic (start, sizeof (start), FALSE, TRUE);
397         inited = 1;
398         return start;
399 }
400 /**
401  * arch_get_throw_exception:
402  *
403  * Returns a function pointer which can be used to raise 
404  * exceptions. The returned function has the following 
405  * signature: void (*func) (MonoException *exc); 
406  * For example to raise an arithmetic exception you can use:
407  *
408  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
409  * x86_call_code (code, arch_get_throw_exception ()); 
410  *
411  */
412 gpointer 
413 mono_arch_get_throw_exception (void)
414 {
415         static guint8 start [132];
416         static int inited = 0;
417
418         if (inited)
419                 return start;
420         mono_arch_get_throw_exception_generic (start, sizeof (start), FALSE, FALSE);
421         inited = 1;
422         return start;
423 }
424
425 /**
426  * arch_get_throw_exception_by_name:
427  *
428  * Returns a function pointer which can be used to raise 
429  * corlib exceptions. The returned function has the following 
430  * signature: void (*func) (char *exc_name); 
431  * For example to raise an arithmetic exception you can use:
432  *
433  * x86_push_imm (code, "ArithmeticException"); 
434  * x86_call_code (code, arch_get_throw_exception_by_name ()); 
435  *
436  */
437 gpointer 
438 mono_arch_get_throw_exception_by_name (void)
439 {
440         static guint8 start [168];
441         static int inited = 0;
442
443         if (inited)
444                 return start;
445         mono_arch_get_throw_exception_generic (start, sizeof (start), TRUE, FALSE);
446         inited = 1;
447         return start;
448 }       
449
450 static MonoArray *
451 glist_to_array (GList *list, MonoClass *eclass) 
452 {
453         MonoDomain *domain = mono_domain_get ();
454         MonoArray *res;
455         int len, i;
456
457         if (!list)
458                 return NULL;
459
460         len = g_list_length (list);
461         res = mono_array_new (domain, eclass, len);
462
463         for (i = 0; list; list = list->next, i++)
464                 mono_array_set (res, gpointer, i, list->data);
465
466         return res;
467 }
468
469 /* mono_arch_find_jit_info:
470  *
471  * This function is used to gather information from @ctx. It return the 
472  * MonoJitInfo of the corresponding function, unwinds one stack frame and
473  * stores the resulting context into @new_ctx. It also stores a string 
474  * describing the stack location into @trace (if not NULL), and modifies
475  * the @lmf if necessary. @native_offset return the IP offset from the 
476  * start of the function or -1 if that info is not available.
477  */
478 MonoJitInfo *
479 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji,
480                          MonoContext *ctx, 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         MonoPPCStackFrame *sframe;
488
489         /* Avoid costly table lookup during stack overflow */
490         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
491                 ji = prev_ji;
492         else
493                 ji = mono_jit_info_table_find (domain, ip);
494
495         if (trace)
496                 *trace = NULL;
497
498         if (native_offset)
499                 *native_offset = -1;
500
501         if (managed)
502                 *managed = FALSE;
503
504         if (ji != NULL) {
505                 char *source_location, *tmpaddr, *fname;
506                 gint32 address, iloffset;
507                 int offset, i;
508                 gulong *ctx_regs;
509
510                 *new_ctx = *ctx;
511                 setup_context (new_ctx);
512
513                 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
514                         /* remove any unused lmf */
515                         *lmf = (*lmf)->previous_lmf;
516                 }
517
518                 address = (char *)ip - (char *)ji->code_start;
519
520                 if (native_offset)
521                         *native_offset = address;
522
523                 if (managed)
524                         if (!ji->method->wrapper_type)
525                                 *managed = TRUE;
526
527                 if (trace) {
528                         source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
529                         iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
530
531                         if (iloffset < 0)
532                                 tmpaddr = g_strdup_printf ("<0x%05x>", address);
533                         else
534                                 tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
535                 
536                         fname = mono_method_full_name (ji->method, TRUE);
537
538                         if (source_location)
539                                 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
540                         else
541                                 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
542
543                         g_free (fname);
544                         g_free (source_location);
545                         g_free (tmpaddr);
546                 }
547                 sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_BP (ctx);
548                 MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
549                 if (ji->method->save_lmf) {
550                         memcpy (&new_ctx->fregs, (char*)sframe->sp - sizeof (double) * MONO_SAVED_FREGS, sizeof (double) * MONO_SAVED_FREGS);
551                         memcpy (&new_ctx->regs, (char*)sframe->sp - sizeof (double) * MONO_SAVED_FREGS - sizeof (gulong) * MONO_SAVED_GREGS, sizeof (gulong) * MONO_SAVED_GREGS);
552                 } else if (ji->used_regs) {
553                         /* keep updated with emit_prolog in mini-ppc.c */
554                         offset = 0;
555                         /* FIXME handle floating point args 
556                         for (i = 31; i >= 14; --i) {
557                                 if (ji->used_fregs & (1 << i)) {
558                                         offset += sizeof (double);
559                                         new_ctx->fregs [i - 14] = *(gulong*)((char*)sframe->sp - offset);
560                                 }
561                         }*/
562                         for (i = 31; i >= 13; --i) {
563                                 if (ji->used_regs & (1 << i)) {
564                                         offset += sizeof (gulong);
565                                         new_ctx->regs [i - 13] = *(gulong*)((char*)sframe->sp - offset);
566                                 }
567                         }
568                 }
569                 /* the calling IP is in the parent frame */
570                 sframe = (MonoPPCStackFrame*)sframe->sp;
571                 /* we substract 4, so that the IP points into the call instruction */
572                 MONO_CONTEXT_SET_IP (new_ctx, sframe->lr - 4);
573
574                 return ji;
575         } else if (*lmf) {
576                 
577                 *new_ctx = *ctx;
578                 setup_context (new_ctx);
579
580                 if (!(*lmf)->method)
581                         return (gpointer)-1;
582
583                 if (trace) {
584                         char *fname = mono_method_full_name ((*lmf)->method, TRUE);
585                         *trace = g_strdup_printf ("in (unmanaged) %s", fname);
586                         g_free (fname);
587                 }
588                 
589                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
590                 } else {
591                         memset (res, 0, sizeof (MonoJitInfo));
592                         res->method = (*lmf)->method;
593                 }
594
595                 /*sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_BP (ctx);
596                 MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
597                 MONO_CONTEXT_SET_IP (new_ctx, sframe->lr);*/
598                 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
599                 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
600                 memcpy (&new_ctx->regs, (*lmf)->iregs, sizeof (gulong) * MONO_SAVED_GREGS);
601                 memcpy (&new_ctx->fregs, (*lmf)->fregs, sizeof (double) * MONO_SAVED_FREGS);
602                 *lmf = (*lmf)->previous_lmf;
603
604                 return ji ? ji : res;
605         }
606
607         return NULL;
608 }
609
610 void
611 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data) {
612         MonoDomain *domain = mono_domain_get ();
613         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
614         MonoLMF *lmf = jit_tls->lmf;
615         MonoJitInfo *ji, rji;
616         gint native_offset, il_offset;
617         gboolean managed;
618         MonoPPCStackFrame *sframe;
619
620         MonoContext ctx, new_ctx;
621
622         setup_context (&ctx);
623         setup_context (&new_ctx);
624
625 #ifdef __APPLE__
626         __asm__ volatile("lwz   %0,0(r1)" : "=r" (sframe));
627 #else
628         __asm__ volatile("lwz   %0,0(1)" : "=r" (sframe));
629 #endif
630         //MONO_CONTEXT_SET_IP (&ctx, sframe->lr);
631         MONO_CONTEXT_SET_BP (&ctx, sframe->sp);
632         sframe = (MonoPPCStackFrame*)sframe->sp;
633         MONO_CONTEXT_SET_IP (&ctx, sframe->lr);
634
635         while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
636                 
637                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
638                 g_assert (ji);
639
640                 if (ji == (gpointer)-1)
641                         return;
642
643                 il_offset = do_il_offset ? mono_debug_il_offset_from_address (ji->method, native_offset, domain): -1;
644
645                 if (func (ji->method, native_offset, il_offset, managed, user_data))
646                         return;
647                 
648                 ctx = new_ctx;
649                 setup_context (&ctx);
650         }
651 }
652
653 MonoBoolean
654 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
655                           MonoReflectionMethod **method, 
656                           gint32 *iloffset, gint32 *native_offset,
657                           MonoString **file, gint32 *line, gint32 *column)
658 {
659         MonoDomain *domain = mono_domain_get ();
660         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
661         MonoLMF *lmf = jit_tls->lmf;
662         MonoJitInfo *ji, rji;
663         MonoContext ctx, new_ctx;
664         MonoPPCStackFrame *sframe;
665
666 #ifdef __APPLE__
667         __asm__ volatile("lwz   %0,0(r1)" : "=r" (sframe));
668 #else
669         __asm__ volatile("lwz   %0,0(1)" : "=r" (sframe));
670 #endif
671         MONO_CONTEXT_SET_BP (&ctx, sframe->sp);
672         sframe = (MonoPPCStackFrame*)sframe->sp;
673         MONO_CONTEXT_SET_IP (&ctx, sframe->lr);
674         /*MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
675         MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));*/
676
677         skip++;
678
679         do {
680                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
681
682                 ctx = new_ctx;
683                 
684                 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
685                         return FALSE;
686
687                 /* skip all wrappers ??*/
688                 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
689                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
690                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
691                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
692                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
693                         continue;
694
695                 skip--;
696
697         } while (skip >= 0);
698
699         *method = mono_method_get_object (domain, ji->method, NULL);
700         *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset, domain);
701
702         if (need_file_info) {
703                 gchar *filename;
704
705                 filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
706
707                 *file = filename? mono_string_new (domain, filename): NULL;
708                 *column = 0;
709
710                 g_free (filename);
711         }
712
713         return TRUE;
714 }
715
716 /*
717  * This is the function called from the signal handler
718  */
719 #ifdef __APPLE__
720 gboolean
721 mono_arch_handle_exception (void *ctx, gpointer obj, gboolean test_only)
722 {
723         struct ucontext *uc = ctx;
724         MonoContext mctx;
725         gboolean result;
726         
727         mctx.sc_ir = uc->uc_mcontext->ss.srr0;
728         mctx.sc_sp = uc->uc_mcontext->ss.r1;
729         memcpy (&mctx.regs, &uc->uc_mcontext->ss.r13, sizeof (gulong) * MONO_SAVED_GREGS);
730         memcpy (&mctx.fregs, &uc->uc_mcontext->fs.fpregs [14], sizeof (double) * MONO_SAVED_FREGS);
731
732         result = arch_handle_exception (&mctx, obj, test_only);
733         /* restore the context so that returning from the signal handler will invoke
734          * the catch clause 
735          */
736         uc->uc_mcontext->ss.srr0 = mctx.sc_ir;
737         uc->uc_mcontext->ss.r1 = mctx.sc_sp;
738         memcpy (&uc->uc_mcontext->ss.r13, &mctx.regs, sizeof (gulong) * MONO_SAVED_GREGS);
739         memcpy (&uc->uc_mcontext->fs.fpregs [14], &mctx.fregs, sizeof (double) * MONO_SAVED_FREGS);
740         return result;
741 }
742
743 gpointer
744 mono_arch_ip_from_context (void *sigctx)
745 {
746         struct ucontext *uc = sigctx;
747         return (gpointer)uc->uc_mcontext->ss.srr0;
748 }
749
750 #else
751 /* Linux */
752 gboolean
753 mono_arch_handle_exception (void *ctx, gpointer obj, gboolean test_only)
754 {
755         struct ucontext *uc = ctx;
756         MonoContext mctx;
757         gboolean result;
758         
759         mctx.sc_ir = uc->uc_mcontext.uc_regs->gregs [PT_NIP];
760         mctx.sc_sp = uc->uc_mcontext.uc_regs->gregs [PT_R1];
761         memcpy (&mctx.regs, &uc->uc_mcontext.uc_regs->gregs [PT_R13], sizeof (gulong) * MONO_SAVED_GREGS);
762         memcpy (&mctx.fregs, &uc->uc_mcontext.uc_regs->fpregs.fpregs [14], sizeof (double) * MONO_SAVED_FREGS);
763
764         result = arch_handle_exception (&mctx, obj, test_only);
765         /* restore the context so that returning from the signal handler will invoke
766          * the catch clause 
767          */
768         uc->uc_mcontext.uc_regs->gregs [PT_NIP] = mctx.sc_ir;
769         uc->uc_mcontext.uc_regs->gregs [PT_R1] = mctx.sc_sp;
770         memcpy (&uc->uc_mcontext.uc_regs->gregs [PT_R13], &mctx.regs, sizeof (gulong) * MONO_SAVED_GREGS);
771         memcpy (&uc->uc_mcontext.uc_regs->fpregs.fpregs [14], &mctx.fregs, sizeof (double) * MONO_SAVED_FREGS);
772         return result;
773 }
774
775 gpointer
776 mono_arch_ip_from_context (void *sigctx)
777 {
778         struct ucontext *uc = sigctx;
779         return (gpointer)uc->uc_mcontext.uc_regs->gregs [PT_NIP];
780 }
781
782 #endif
783
784 /**
785  * arch_handle_exception:
786  * @ctx: saved processor state
787  * @obj: the exception object
788  * @test_only: only test if the exception is caught, but dont call handlers
789  *
790  *
791  */
792 static gboolean
793 arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
794 {
795         MonoDomain *domain = mono_domain_get ();
796         MonoJitInfo *ji, rji;
797         static int (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
798         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
799         MonoLMF *lmf = jit_tls->lmf;            
800         GList *trace_ips = NULL;
801         MonoException *mono_ex;
802         MonoArray *initial_trace_ips = NULL;
803         int frame_count = 0;
804         gboolean has_dynamic_methods = FALSE;
805
806         g_assert (ctx != NULL);
807         if (!obj) {
808                 MonoException *ex = mono_get_exception_null_reference ();
809                 ex->message = mono_string_new (domain, 
810                         "Object reference not set to an instance of an object");
811                 obj = (MonoObject *)ex;
812         } 
813
814         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
815                 mono_ex = (MonoException*)obj;
816                 initial_trace_ips = mono_ex->trace_ips;
817         } else {
818                 mono_ex = NULL;
819         }
820
821
822         if (!call_filter)
823                 call_filter = arch_get_call_filter ();
824
825         g_assert (jit_tls->end_of_stack);
826         g_assert (jit_tls->abort_func);
827
828         if (!test_only) {
829                 MonoContext ctx_cp = *ctx;
830                 setup_context (&ctx_cp);
831                 if (mono_jit_trace_calls != NULL)
832                         g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
833                 if (!arch_handle_exception (&ctx_cp, obj, TRUE)) {
834                         if (mono_break_on_exc)
835                                 G_BREAKPOINT ();
836                         mono_unhandled_exception (obj);
837                 }
838         }
839
840         memset (&rji, 0, sizeof (rji));
841
842         while (1) {
843                 MonoContext new_ctx;
844
845                 setup_context (&new_ctx);
846                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx, 
847                                               NULL, &lmf, NULL, NULL);
848                 if (!ji) {
849                         g_warning ("Exception inside function without unwind info");
850                         g_assert_not_reached ();
851                 }
852
853                 if (ji != (gpointer)-1) {
854                         frame_count ++;
855                         
856                         if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
857                                 /* 
858                                  * Avoid overwriting the stack trace if the exception is
859                                  * rethrown. Also avoid giant stack traces during a stack
860                                  * overflow.
861                                  */
862                                 if (!initial_trace_ips && (frame_count < 1000)) {
863                                         trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
864
865                                 }
866                         }
867
868                         if (ji->method->dynamic)
869                                 has_dynamic_methods = TRUE;
870
871                         if (ji->num_clauses) {
872                                 int i;
873                                 
874                                 g_assert (ji->clauses);
875                         
876                                 for (i = 0; i < ji->num_clauses; i++) {
877                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
878                                         gboolean filtered = FALSE;
879
880                                         if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
881                                             MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
882                                                 /* catch block */
883
884                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
885                                                         /* store the exception object int cfg->excvar */
886                                                         g_assert (ei->exvar_offset);
887                                                         /* need to use the frame pointer (ppc_r31), not r1 (regs start from register r13): methods with clauses always have r31 */
888                                                         *((gpointer *)((char *)(ctx->regs [ppc_r31-13]) + ei->exvar_offset)) = obj;
889                                                 }
890
891                                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
892                                                         filtered = call_filter (ctx, ei->data.filter, mono_ex);
893
894                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
895                                                      mono_object_isinst (obj, ei->data.catch_class)) || filtered) {
896                                                         if (test_only) {
897                                                                 if (mono_ex && !initial_trace_ips) {
898                                                                         trace_ips = g_list_reverse (trace_ips);
899                                                                         mono_ex->trace_ips = glist_to_array (trace_ips, mono_defaults.int_class);
900                                                                         if (has_dynamic_methods)
901                                                                                 /* These methods could go away anytime, so compute the stack trace now */
902                                                                                 mono_ex->stack_trace = ves_icall_System_Exception_get_trace (mono_ex);
903                                                                 }
904                                                                 g_list_free (trace_ips);
905                                                                 return TRUE;
906                                                         }
907                                                         if (mono_jit_trace_calls != NULL)
908                                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
909                                                         /*printf ("stack for catch: %p\n", MONO_CONTEXT_GET_BP (ctx));*/
910                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
911                                                         jit_tls->lmf = lmf;
912                                                         return 0;
913                                                 }
914                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
915                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
916                                                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
917                                                         if (mono_jit_trace_calls != NULL)
918                                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
919                                                         call_filter (ctx, ei->handler_start, NULL);
920                                                 }
921                                                 
922                                         }
923                                 }
924                         }
925                 }
926
927                 *ctx = new_ctx;
928                 setup_context (ctx);
929
930                 if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
931                         if (!test_only) {
932                                 jit_tls->lmf = lmf;
933                                 jit_tls->abort_func (obj);
934                                 g_assert_not_reached ();
935                         } else {
936                                 if (mono_ex && !initial_trace_ips) {
937                                         trace_ips = g_list_reverse (trace_ips);
938                                         mono_ex->trace_ips = glist_to_array (trace_ips, mono_defaults.int_class);
939                                         if (has_dynamic_methods)
940                                                 /* These methods could go away anytime, so compute the stack trace now */
941                                                 mono_ex->stack_trace = ves_icall_System_Exception_get_trace (mono_ex);
942                                 }
943                                 g_list_free (trace_ips);
944                                 return FALSE;
945                         }
946                 }
947         }
948
949         g_assert_not_reached ();
950 }
951
952 gboolean
953 mono_arch_has_unwind_info (gconstpointer addr)
954 {
955         return FALSE;
956 }
957