Wed Apr 21 16:38:28 CEST 2004 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
16 #include <mono/arch/ppc/ppc-codegen.h>
17 #include <mono/metadata/appdomain.h>
18 #include <mono/metadata/tabledefs.h>
19 #include <mono/metadata/threads.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/mono-debug.h>
23
24 #include "mini.h"
25 #include "mini-ppc.h"
26
27 #ifdef __APPLE__
28 typedef struct sigcontext MonoContext;
29 #else
30 typedef struct ucontext MonoContext;
31 #endif
32
33 /*
34
35 struct sigcontext {
36     int      sc_onstack;     // sigstack state to restore 
37     int      sc_mask;        // signal mask to restore 
38     int      sc_ir;          // pc 
39     int      sc_psw;         // processor status word 
40     int      sc_sp;          // stack pointer if sc_regs == NULL 
41     void    *sc_regs;        // (kernel private) saved state 
42 };
43
44 struct ucontext {
45         int             uc_onstack;
46         sigset_t        uc_sigmask;     // signal mask used by this context 
47         stack_t         uc_stack;       // stack used by this context 
48         struct ucontext *uc_link;       // pointer to resuming context 
49         size_t          uc_mcsize;      // size of the machine context passed in 
50         mcontext_t      uc_mcontext;    // machine specific context 
51 };
52
53 typedef struct ppc_exception_state {
54         unsigned long dar;      // Fault registers for coredump 
55         unsigned long dsisr;
56         unsigned long exception;// number of powerpc exception taken 
57         unsigned long pad0;     // align to 16 bytes 
58
59         unsigned long pad1[4];  // space in PCB "just in case" 
60 } ppc_exception_state_t;
61
62 typedef struct ppc_vector_state {
63         unsigned long   save_vr[32][4];
64         unsigned long   save_vscr[4];
65         unsigned int    save_pad5[4];
66         unsigned int    save_vrvalid;                   // VRs that have been saved 
67         unsigned int    save_pad6[7];
68 } ppc_vector_state_t;
69
70 typedef struct ppc_float_state {
71         double  fpregs[32];
72
73         unsigned int fpscr_pad; // fpscr is 64 bits, 32 bits of rubbish 
74         unsigned int fpscr;     // floating point status register 
75 } ppc_float_state_t;
76
77 typedef struct ppc_thread_state {
78         unsigned int srr0;      // Instruction address register (PC) 
79         unsigned int srr1;      // Machine state register (supervisor) 
80         unsigned int r0;
81         unsigned int r1;
82         unsigned int r2;
83         ... 
84         unsigned int r31;
85         unsigned int cr;        // Condition register 
86         unsigned int xer;       // User's integer exception register 
87         unsigned int lr;        // Link register 
88         unsigned int ctr;       // Count register 
89         unsigned int mq;        // MQ register (601 only) 
90
91         unsigned int vrsave;    // Vector Save Register 
92 } ppc_thread_state_t;
93
94 struct mcontext {
95         ppc_exception_state_t   es;
96         ppc_thread_state_t      ss;
97         ppc_float_state_t       fs;
98         ppc_vector_state_t      vs;
99 };
100
101 typedef struct mcontext  * mcontext_t;
102
103 Linux/PPC instead has:
104 struct sigcontext {
105         unsigned long   _unused[4];
106         int             signal;
107         unsigned long   handler;
108         unsigned long   oldmask;
109         struct pt_regs  *regs;
110 };
111 struct pt_regs {
112         unsigned long gpr[32];
113         unsigned long nip;
114         unsigned long msr;
115         unsigned long orig_gpr3;        // Used for restarting system calls 
116         unsigned long ctr;
117         unsigned long link;
118         unsigned long xer;
119         unsigned long ccr;
120         unsigned long mq;               // 601 only (not used at present) 
121                                         // Used on APUS to hold IPL value. 
122         unsigned long trap;             // Reason for being here 
123         // N.B. for critical exceptions on 4xx, the dar and dsisr
124         // fields are overloaded to hold srr0 and srr1. 
125         unsigned long dar;              // Fault registers 
126         unsigned long dsisr;            // on 4xx/Book-E used for ESR 
127         unsigned long result;           // Result of a system call 
128 };
129 struct mcontext {
130         elf_gregset_t   mc_gregs;
131         elf_fpregset_t  mc_fregs;
132         unsigned long   mc_pad[2];
133         elf_vrregset_t  mc_vregs __attribute__((__aligned__(16)));
134 };
135
136 struct ucontext {
137         unsigned long    uc_flags;
138         struct ucontext *uc_link;
139         stack_t          uc_stack;
140         int              uc_pad[7];
141         struct mcontext *uc_regs;       // points to uc_mcontext field 
142         sigset_t         uc_sigmask;
143         // glibc has 1024-bit signal masks, ours are 64-bit 
144         int              uc_maskext[30];
145         int              uc_pad2[3];
146         struct mcontext  uc_mcontext;
147 };
148
149 #define ELF_NGREG       48      // includes nip, msr, lr, etc. 
150 #define ELF_NFPREG      33      // includes fpscr 
151
152 // General registers 
153 typedef unsigned long elf_greg_t;
154 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
155
156 // Floating point registers 
157 typedef double elf_fpreg_t;
158 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
159
160
161 */
162
163 #ifdef __APPLE__
164
165 /* we have the stack pointer, not the base pointer in sigcontext */
166 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->sc_ir = (int)ip; } while (0); 
167 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->sc_sp = (int)bp; } while (0); 
168
169 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->sc_ir))
170 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->sc_sp))
171
172 typedef struct {
173         unsigned long sp;
174         unsigned long unused1;
175         unsigned long lr;
176 } MonoPPCStackFrame;
177
178 #else /* on linux/ppc we use ucontext. See /usr/include/asm/ptrace.h. */
179
180 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->uc_mcontext.uc_regs->gregs [PT_NIP] = (unsigned long)ip; } while (0); 
181 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->uc_mcontext.uc_regs->gregs [PT_R1] = (unsigned long)bp; } while (0); 
182
183 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->uc_mcontext.uc_regs->gregs [PT_NIP]))
184 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->uc_mcontext.uc_regs->gregs [PT_R1]))
185
186 typedef struct {
187         unsigned long sp;
188         unsigned long lr;
189 } MonoPPCStackFrame;
190
191 #endif
192
193 /* disbale this for now */
194 #undef MONO_USE_EXC_TABLES
195
196 #ifdef MONO_USE_EXC_TABLES
197
198 /*************************************/
199 /*    STACK UNWINDING STUFF          */
200 /*************************************/
201
202 /* These definitions are from unwind-dw2.c in glibc 2.2.5 */
203
204 /* For x86 */
205 #define DWARF_FRAME_REGISTERS 17
206
207 typedef struct frame_state
208 {
209   void *cfa;
210   void *eh_ptr;
211   long cfa_offset;
212   long args_size;
213   long reg_or_offset[DWARF_FRAME_REGISTERS+1];
214   unsigned short cfa_reg;
215   unsigned short retaddr_column;
216   char saved[DWARF_FRAME_REGISTERS+1];
217 } frame_state;
218
219 #if 0
220
221 static long
222 get_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum)
223 {
224         switch (dwarf_regnum) {
225         case X86_EAX:
226                 return ctx->SC_EAX;
227         case X86_EBX:
228                 return ctx->SC_EBX;
229         case X86_ECX:
230                 return ctx->SC_ECX;
231         case X86_EDX:
232                 return ctx->SC_EDX;
233         case X86_ESI:
234                 return ctx->SC_ESI;
235         case X86_EDI:
236                 return ctx->SC_EDI;
237         case X86_EBP:
238                 return ctx->SC_EBP;
239         case X86_ESP:
240                 return ctx->SC_ESP;
241         default:
242                 g_assert_not_reached ();
243         }
244
245         return 0;
246 }
247
248 static void
249 set_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum, long value)
250 {
251         switch (dwarf_regnum) {
252         case X86_EAX:
253                 ctx->SC_EAX = value;
254                 break;
255         case X86_EBX:
256                 ctx->SC_EBX = value;
257                 break;
258         case X86_ECX:
259                 ctx->SC_ECX = value;
260                 break;
261         case X86_EDX:
262                 ctx->SC_EDX = value;
263                 break;
264         case X86_ESI:
265                 ctx->SC_ESI = value;
266                 break;
267         case X86_EDI:
268                 ctx->SC_EDI = value;
269                 break;
270         case X86_EBP:
271                 ctx->SC_EBP = value;
272                 break;
273         case X86_ESP:
274                 ctx->SC_ESP = value;
275                 break;
276         case 8:
277                 ctx->SC_EIP = value;
278                 break;
279         default:
280                 g_assert_not_reached ();
281         }
282 }
283
284 typedef struct frame_state * (*framesf) (void *, struct frame_state *);
285
286 static framesf frame_state_for = NULL;
287
288 static gboolean inited = FALSE;
289
290 typedef char ** (*get_backtrace_symbols_type) (void *__const *__array, int __size);
291
292 static get_backtrace_symbols_type get_backtrace_symbols = NULL;
293
294 static void
295 init_frame_state_for (void)
296 {
297         GModule *module;
298
299         /*
300          * There are two versions of __frame_state_for: one in libgcc.a and the
301          * other in glibc.so. We need the version from glibc.
302          * For more info, see this:
303          * http://gcc.gnu.org/ml/gcc/2002-08/msg00192.html
304          */
305         if ((module = g_module_open ("libc.so.6", G_MODULE_BIND_LAZY))) {
306         
307                 if (!g_module_symbol (module, "__frame_state_for", (gpointer*)&frame_state_for))
308                         frame_state_for = NULL;
309
310                 if (!g_module_symbol (module, "backtrace_symbols", (gpointer*)&get_backtrace_symbols)) {
311                         get_backtrace_symbols = NULL;
312                         frame_state_for = NULL;
313                 }
314
315                 g_module_close (module);
316         }
317
318         inited = TRUE;
319 }
320
321 #endif
322
323 gboolean  mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only);
324
325 /* mono_arch_has_unwind_info:
326  *
327  * Tests if a function has an DWARF exception table able to restore
328  * all caller saved registers. 
329  */
330 gboolean
331 mono_arch_has_unwind_info (MonoMethod *method)
332 {
333 #if 0
334         struct frame_state state_in;
335         struct frame_state *res;
336
337         if (!inited) 
338                 init_frame_state_for ();
339         
340         if (!frame_state_for)
341                 return FALSE;
342
343         g_assert (method->addr);
344
345         memset (&state_in, 0, sizeof (state_in));
346
347         /* offset 10 is just a guess, but it works for all methods tested */
348         if ((res = frame_state_for ((char *)method->addr + 10, &state_in))) {
349
350                 if (res->saved [X86_EBX] != 1 ||
351                     res->saved [X86_EDI] != 1 ||
352                     res->saved [X86_EBP] != 1 ||
353                     res->saved [X86_ESI] != 1) {
354                         return FALSE;
355                 }
356                 return TRUE;
357         } else {
358                 return FALSE;
359         }
360 #else
361         return FALSE;
362 #endif
363 }
364
365 struct stack_frame
366 {
367   void *next;
368   void *return_address;
369 };
370
371 static MonoJitInfo *
372 ppc_unwind_native_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *ctx, 
373                          MonoContext *new_ctx, MonoLMF *lmf, char **trace)
374 {
375 #if 0
376         struct stack_frame *frame;
377         gpointer max_stack;
378         MonoJitInfo *ji;
379         struct frame_state state_in;
380         struct frame_state *res;
381
382         if (trace)
383                 *trace = NULL;
384
385         if (!inited) 
386                 init_frame_state_for ();
387
388         if (!frame_state_for)
389                 return FALSE;
390
391         frame = MONO_CONTEXT_GET_BP (ctx);
392
393         max_stack = lmf && lmf->method ? lmf : jit_tls->end_of_stack;
394
395         *new_ctx = *ctx;
396
397         memset (&state_in, 0, sizeof (state_in));
398
399         while ((gpointer)frame->next < (gpointer)max_stack) {
400                 gpointer ip, addr = frame->return_address;
401                 void *cfa;
402                 char *tmp, **symbols;
403
404                 if (trace) {
405                         ip = MONO_CONTEXT_GET_IP (new_ctx);
406                         symbols = get_backtrace_symbols (&ip, 1);
407                         if (*trace)
408                                 tmp = g_strdup_printf ("%s\nin (unmanaged) %s", *trace, symbols [0]);
409                         else
410                                 tmp = g_strdup_printf ("in (unmanaged) %s", symbols [0]);
411
412                         free (symbols);
413                         g_free (*trace);
414                         *trace = tmp;
415                 }
416
417                 if ((res = frame_state_for (addr, &state_in))) {        
418                         int i;
419
420                         cfa = (gint8*) (get_sigcontext_reg (new_ctx, res->cfa_reg) + res->cfa_offset);
421                         frame = (struct stack_frame *)((gint8*)cfa - 8);
422                         for (i = 0; i < DWARF_FRAME_REGISTERS + 1; i++) {
423                                 int how = res->saved[i];
424                                 long val;
425                                 g_assert ((how == 0) || (how == 1));
426                         
427                                 if (how == 1) {
428                                         val = * (long*) ((gint8*)cfa + res->reg_or_offset[i]);
429                                         set_sigcontext_reg (new_ctx, i, val);
430                                 }
431                         }
432                         new_ctx->SC_ESP = (long)cfa;
433
434                         if (res->saved [X86_EBX] == 1 &&
435                             res->saved [X86_EDI] == 1 &&
436                             res->saved [X86_EBP] == 1 &&
437                             res->saved [X86_ESI] == 1 &&
438                             (ji = mono_jit_info_table_find (domain, frame->return_address))) {
439                                 //printf ("FRAME CFA %s\n", mono_method_full_name (ji->method, TRUE));
440                                 return ji;
441                         }
442
443                 } else {
444                         //printf ("FRAME %p %p %p\n", frame, MONO_CONTEXT_GET_IP (new_ctx), mono_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (new_ctx)));
445
446                         MONO_CONTEXT_SET_IP (new_ctx, frame->return_address);
447                         frame = frame->next;
448                         MONO_CONTEXT_SET_BP (new_ctx, frame);
449
450                         /* stop if !frame or when we detect an unexpected managed frame */
451                         if (!frame || mono_jit_info_table_find (domain, frame->return_address)) {
452                                 if (trace) {
453                                         g_free (*trace);
454                                         *trace = NULL;
455                                 }
456                                 return NULL;
457                         }
458                 }
459         }
460
461         //if (!lmf)
462         //g_assert_not_reached ();
463
464         if (trace) {
465                 g_free (*trace);
466                 *trace = NULL;
467         }
468 #endif
469         return NULL;
470 }
471
472 #endif
473
474 #ifdef __APPLE__
475         /* FIXME: restore the rest of the registers */
476 #define restore_regs_from_context(ctx_reg,ip_reg,tmp_reg) do {  \
477                 ppc_lwz (code, ip_reg, G_STRUCT_OFFSET (struct sigcontext, sc_ir), ctx_reg);    \
478                 ppc_lwz (code, ppc_sp, G_STRUCT_OFFSET (struct sigcontext, sc_sp), ctx_reg);    \
479         } while (0)
480
481 /* nothing to do */
482 #define setup_context(ctx)
483
484 #else
485 /* 
486  * The registers can be at different offsets in the ucontext,
487  * so we need to reference them from uctx->uc_mcontext.uc_regs 
488  */
489 /* return the offset within uc_regs of register regnum (PT_*) */
490 #define regoffset(regnum) (G_STRUCT_OFFSET (mcontext_t, gregs) + (regnum) * sizeof (unsigned long))
491
492         /* FIXME: restore the rest of the registers */
493 #define restore_regs_from_context(ctx_reg,ip_reg,tmp_reg) do {  \
494                 ppc_lwz (code, tmp_reg, G_STRUCT_OFFSET (struct ucontext, uc_mcontext.uc_regs), ctx_reg);       \
495                 ppc_lwz (code, ip_reg, regoffset (PT_NIP), tmp_reg);    \
496                 ppc_lwz (code, ppc_sp, regoffset (PT_R1), tmp_reg);     \
497                 ppc_lmw (code, ppc_r13, tmp_reg, regoffset (PT_R13));   \
498         } while (0)
499
500 /* yes, very ugly, but we need to setup the pointer, since
501  * the mcontext could be at different offsets in the ucontext
502  * generated by the kernel.
503  */
504 #define setup_context(ctx) do { \
505                 (ctx)->uc_mcontext.uc_regs = (mcontext_t*)&(ctx)->uc_reg_space; \
506         } while (0)
507 #endif
508
509 /*
510  * arch_get_restore_context:
511  *
512  * Returns a pointer to a method which restores a previously saved sigcontext.
513  * The first argument in r3 is the pointer to the context.
514  */
515 static gpointer
516 arch_get_restore_context (void)
517 {
518         guint8 *code;
519         static guint8 start [64];
520         static int inited = 0;
521
522         if (inited)
523                 return start;
524         inited = 1;
525
526         code = start;
527         restore_regs_from_context (ppc_r3, ppc_r4, ppc_r5);
528         //ppc_break (code);
529         /* jump to the saved IP */
530         ppc_mtctr (code, ppc_r4);
531         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
532         /* never reached */
533         ppc_break (code);
534
535         g_assert ((code - start) < sizeof(start));
536         return start;
537 }
538
539 /*
540  * arch_get_call_filter:
541  *
542  * Returns a pointer to a method which calls an exception filter. We
543  * also use this function to call finally handlers (we pass NULL as 
544  * @exc object in this case).
545  */
546 static gpointer
547 arch_get_call_filter (void)
548 {
549         static guint8 start [256];
550         static int inited = 0;
551         guint8 *code;
552         int alloc_size, pos, i;
553
554         if (inited)
555                 return start;
556
557         inited = 1;
558         /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
559         code = start;
560
561         ppc_mflr (code, ppc_r0);
562         ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
563         alloc_size = 32 + PPC_MINIMAL_STACK_SIZE + (sizeof (gulong) * 19 + sizeof (gdouble) * 18);
564         // align to PPC_STACK_ALIGNMENT bytes
565         if (alloc_size & (PPC_STACK_ALIGNMENT - 1))
566                 alloc_size += PPC_STACK_ALIGNMENT - (alloc_size & (PPC_STACK_ALIGNMENT - 1));
567         g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
568         ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
569         /* save all the regs on the stack */
570         pos = 32 + PPC_MINIMAL_STACK_SIZE;
571         ppc_stmw (code, ppc_r13, ppc_sp, pos);
572         pos += sizeof (gulong) * 19;
573         for (i = 14; i < 32; ++i) {
574                 ppc_stfd (code, i, pos, ppc_sp);
575                 pos += sizeof (gdouble);
576         }
577         /* restore all the regs from ctx (in r3) */
578         /* FIXME: calling the filter code must not restore the stack pointer */
579         restore_regs_from_context (ppc_r3, ppc_r6, ppc_r7);
580         /* call handler at eip (r4) and set the first arg with the exception (r5) */
581         ppc_mtctr (code, ppc_r4);
582         ppc_mr (code, ppc_r3, ppc_r5);
583         ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
584         /* restore all the regs from the stack */
585         pos = 32 + PPC_MINIMAL_STACK_SIZE;
586         ppc_lmw (code, ppc_r13, ppc_sp, pos);
587         pos += sizeof (gulong) * 19;
588         for (i = 14; i < 32; ++i) {
589                 ppc_lfd (code, i, pos, ppc_sp);
590                 pos += sizeof (gdouble);
591         }
592         ppc_lwz (code, ppc_r0, alloc_size + PPC_RET_ADDR_OFFSET, ppc_sp);
593         ppc_mtlr (code, ppc_r0);
594         ppc_addic (code, ppc_sp, ppc_sp, alloc_size);
595
596         g_assert ((code - start) < sizeof(start));
597         return start;
598 }
599
600 static void
601 throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs)
602 {
603         static void (*restore_context) (MonoContext *);
604         MonoContext ctx;
605
606         if (!restore_context)
607                 restore_context = arch_get_restore_context ();
608
609         /* adjust eip so that it point into the call instruction */
610         eip -= 4;
611
612         setup_context (&ctx);
613
614         /*printf ("stack in throw: %p\n", esp);*/
615         MONO_CONTEXT_SET_BP (&ctx, esp);
616         MONO_CONTEXT_SET_IP (&ctx, eip);
617 #ifdef __APPLE__
618         /* FIXME */
619 #else
620         memcpy (((char*)ctx.uc_mcontext.uc_regs) + regoffset (PT_R13), int_regs, sizeof (gulong) * 19);
621 #endif
622
623         mono_arch_handle_exception (&ctx, exc, FALSE);
624         restore_context (&ctx);
625
626         g_assert_not_reached ();
627 }
628
629 /**
630  * arch_get_throw_exception_generic:
631  *
632  * Returns a function pointer which can be used to raise 
633  * exceptions. The returned function has the following 
634  * signature: void (*func) (MonoException *exc); or
635  * void (*func) (char *exc_name);
636  *
637  */
638 static gpointer 
639 mono_arch_get_throw_exception_generic (guint8 *start, int size, int by_name)
640 {
641         guint8 *code;
642         int alloc_size, pos, i;
643
644         code = start;
645
646         ppc_mflr (code, ppc_r0);
647         ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
648         alloc_size = 32 + PPC_MINIMAL_STACK_SIZE + (sizeof (gulong) * 19 + sizeof (gdouble) * 18);
649         // align to PPC_STACK_ALIGNMENT bytes
650         if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
651                 alloc_size += PPC_STACK_ALIGNMENT - 1;
652                 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
653         }
654         /*g_print ("alloc size = %d\n", alloc_size);*/
655         g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
656         ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
657         //ppc_break (code);
658         if (by_name) {
659                 ppc_mr (code, ppc_r5, ppc_r3);
660                 ppc_load (code, ppc_r3, mono_defaults.corlib);
661                 ppc_load (code, ppc_r4, "System");
662                 ppc_bl (code, 0);
663                 ppc_patch (code - 4, mono_exception_from_name);
664         }
665         /* save all the regs on the stack */
666         pos = 32 + PPC_MINIMAL_STACK_SIZE;
667         ppc_stmw (code, ppc_r13, ppc_sp, pos);
668         pos += sizeof (gulong) * 19;
669         /* align for doubles */
670         pos += 7;
671         pos &= ~7;
672         for (i = 14; i < 32; ++i) {
673                 ppc_stfd (code, i, pos, ppc_sp);
674                 pos += sizeof (gdouble);
675         }
676         /* call throw_exception (exc, ip, sp, int_regs, fp_regs) */
677         /* caller sp */
678         ppc_lwz (code, ppc_r5, 0, ppc_sp); 
679         /* exc is already in place in r3 */
680         if (by_name)
681                 ppc_lwz (code, ppc_r4, PPC_RET_ADDR_OFFSET, ppc_r5); 
682         else
683                 ppc_mr (code, ppc_r4, ppc_r0); /* caller ip */
684         /* pointer to the saved int regs */
685         pos = 32 + PPC_MINIMAL_STACK_SIZE;
686         ppc_addi (code, ppc_r6, ppc_sp, pos);
687         /* pointer to the saved fp regs */
688         pos += sizeof (gulong) * 19;
689         ppc_addi (code, ppc_r7, ppc_sp, pos);
690         ppc_bl (code, 0);
691         ppc_patch (code - 4, throw_exception);
692         /* we should never reach this breakpoint */
693         ppc_break (code);
694         g_assert ((code - start) < size);
695         return start;
696 }
697
698 /**
699  * arch_get_throw_exception:
700  *
701  * Returns a function pointer which can be used to raise 
702  * exceptions. The returned function has the following 
703  * signature: void (*func) (MonoException *exc); 
704  * For example to raise an arithmetic exception you can use:
705  *
706  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
707  * x86_call_code (code, arch_get_throw_exception ()); 
708  *
709  */
710 gpointer 
711 mono_arch_get_throw_exception (void)
712 {
713         static guint8 start [128];
714         static int inited = 0;
715
716         if (inited)
717                 return start;
718         mono_arch_get_throw_exception_generic (start, sizeof (start), FALSE);
719         inited = 1;
720         return start;
721 }
722
723 /**
724  * arch_get_throw_exception_by_name:
725  *
726  * Returns a function pointer which can be used to raise 
727  * corlib exceptions. The returned function has the following 
728  * signature: void (*func) (char *exc_name); 
729  * For example to raise an arithmetic exception you can use:
730  *
731  * x86_push_imm (code, "ArithmeticException"); 
732  * x86_call_code (code, arch_get_throw_exception_by_name ()); 
733  *
734  */
735 gpointer 
736 mono_arch_get_throw_exception_by_name (void)
737 {
738         static guint8 start [160];
739         static int inited = 0;
740
741         if (inited)
742                 return start;
743         mono_arch_get_throw_exception_generic (start, sizeof (start), TRUE);
744         inited = 1;
745         return start;
746 }       
747
748 static MonoArray *
749 glist_to_array (GList *list) 
750 {
751         MonoDomain *domain = mono_domain_get ();
752         MonoArray *res;
753         int len, i;
754
755         if (!list)
756                 return NULL;
757
758         len = g_list_length (list);
759         res = mono_array_new (domain, mono_defaults.int_class, len);
760
761         for (i = 0; list; list = list->next, i++)
762                 mono_array_set (res, gpointer, i, list->data);
763
764         return res;
765 }
766
767 /* mono_arch_find_jit_info:
768  *
769  * This function is used to gather information from @ctx. It return the 
770  * MonoJitInfo of the corresponding function, unwinds one stack frame and
771  * stores the resulting context into @new_ctx. It also stores a string 
772  * describing the stack location into @trace (if not NULL), and modifies
773  * the @lmf if necessary. @native_offset return the IP offset from the 
774  * start of the function or -1 if that info is not available.
775  */
776 static MonoJitInfo *
777 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoContext *ctx, 
778                          MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
779                          gboolean *managed)
780 {
781         MonoJitInfo *ji;
782         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
783         unsigned long *ptr;
784         char *p;
785         MonoPPCStackFrame *sframe;
786
787         ji = mono_jit_info_table_find (domain, ip);
788
789         if (trace)
790                 *trace = NULL;
791
792         if (native_offset)
793                 *native_offset = -1;
794
795         if (managed)
796                 *managed = FALSE;
797
798         if (ji != NULL) {
799                 char *source_location, *tmpaddr, *fname;
800                 gint32 address, iloffset;
801                 int offset, i;
802                 gulong *ctx_regs;
803
804                 *new_ctx = *ctx;
805                 setup_context (new_ctx);
806
807                 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
808                         /* remove any unused lmf */
809                         *lmf = (*lmf)->previous_lmf;
810                 }
811
812                 address = (char *)ip - (char *)ji->code_start;
813
814                 if (native_offset)
815                         *native_offset = address;
816
817                 if (managed)
818                         if (!ji->method->wrapper_type)
819                                 *managed = TRUE;
820
821                 if (trace) {
822                         source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
823                         iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
824
825                         if (iloffset < 0)
826                                 tmpaddr = g_strdup_printf ("<0x%05x>", address);
827                         else
828                                 tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
829                 
830                         fname = mono_method_full_name (ji->method, TRUE);
831
832                         if (source_location)
833                                 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
834                         else
835                                 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
836
837                         g_free (fname);
838                         g_free (source_location);
839                         g_free (tmpaddr);
840                 }
841 #if 0                           
842                 offset = -1;
843                 /* restore caller saved registers */
844                 if (ji->used_regs & X86_EBX_MASK) {
845                         new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
846                         offset--;
847                 }
848                 if (ji->used_regs & X86_EDI_MASK) {
849                         new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
850                         offset--;
851                 }
852                 if (ji->used_regs & X86_ESI_MASK) {
853                         new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
854                 }
855
856                 new_ctx->SC_ESP = ctx->SC_EBP;
857                 /* we substract 1, so that the IP points into the call instruction */
858                 new_ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 1;
859                 new_ctx->SC_EBP = *((int *)ctx->SC_EBP);
860 #endif
861                 sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_BP (ctx);
862                 MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
863                 if (ji->used_regs) {
864                         /* keep updated with emit_prolog in mini-ppc.c */
865                         offset = 0;
866                         for (i = 13; i < 32; ++i) {
867                                 if (ji->used_regs & (1 << i)) {
868                                         offset += sizeof (gulong);
869 #ifdef __APPLE__
870                                         /* FIXME */
871 #else
872                                         *(gulong*)(((char*)new_ctx->uc_mcontext.uc_regs) + regoffset (PT_R0 + i)) = *(gulong*)((char*)sframe->sp - offset);
873 #endif
874                                 }
875                         }
876                 }
877                 /* the calling IP is in the parent frame */
878                 sframe = (MonoPPCStackFrame*)sframe->sp;
879                 /* we substract 4, so that the IP points into the call instruction */
880                 MONO_CONTEXT_SET_IP (new_ctx, sframe->lr - 4);
881                 *res = *ji;
882                 return res;
883 #ifdef MONO_USE_EXC_TABLES
884         } else if ((ji = ppc_unwind_native_frame (domain, jit_tls, ctx, new_ctx, *lmf, trace))) {
885                 *res = *ji;
886                 return res;
887 #endif
888         } else if (*lmf) {
889                 
890                 *new_ctx = *ctx;
891                 setup_context (new_ctx);
892
893                 if (!(*lmf)->method)
894                         return (gpointer)-1;
895
896                 if (trace)
897                         *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
898                 
899                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
900                         *res = *ji;
901                 } else {
902                         memset (res, 0, sizeof (MonoJitInfo));
903                         res->method = (*lmf)->method;
904                 }
905
906 #if 0
907                 new_ctx->SC_ESI = (*lmf)->esi;
908                 new_ctx->SC_EDI = (*lmf)->edi;
909                 new_ctx->SC_EBX = (*lmf)->ebx;
910                 new_ctx->SC_EBP = (*lmf)->ebp;
911                 new_ctx->SC_EIP = (*lmf)->eip;
912                 /* the lmf is always stored on the stack, so the following
913                  * expression points to a stack location which can be used as ESP */
914                 new_ctx->SC_ESP = (unsigned long)&((*lmf)->eip);
915 #endif
916                 /*sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_BP (ctx);
917                 MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
918                 MONO_CONTEXT_SET_IP (new_ctx, sframe->lr);*/
919                 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
920                 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
921 #ifdef __APPLE__
922         /* FIXME */
923 #else
924                 memcpy (((char*)new_ctx->uc_mcontext.uc_regs) + regoffset (PT_R13), (*lmf)->iregs, sizeof (gulong) * 19);
925 #endif
926                 *lmf = (*lmf)->previous_lmf;
927
928                 return res;
929                 
930         }
931
932         return NULL;
933 }
934
935 MonoArray *
936 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
937 {
938         MonoDomain *domain = mono_domain_get ();
939         MonoArray *res;
940         MonoArray *ta = exc->trace_ips;
941         int i, len;
942         
943         len = mono_array_length (ta);
944
945         res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
946
947         for (i = skip; i < len; i++) {
948                 MonoJitInfo *ji;
949                 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
950                 gpointer ip = mono_array_get (ta, gpointer, i);
951
952                 ji = mono_jit_info_table_find (domain, ip);
953                 g_assert (ji != NULL);
954
955                 sf->method = mono_method_get_object (domain, ji->method, NULL);
956                 sf->native_offset = (char *)ip - (char *)ji->code_start;
957
958                 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
959
960                 if (need_file_info) {
961                         gchar *filename;
962                         
963                         filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
964
965                         sf->filename = filename? mono_string_new (domain, filename): NULL;
966                         sf->column = 0;
967
968                         g_free (filename);
969                 }
970
971                 mono_array_set (res, gpointer, i, sf);
972         }
973
974         return res;
975 }
976
977 void
978 mono_jit_walk_stack (MonoStackWalk func, gpointer user_data) {
979         MonoDomain *domain = mono_domain_get ();
980         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
981         MonoLMF *lmf = jit_tls->lmf;
982         MonoJitInfo *ji, rji;
983         gint native_offset, il_offset;
984         gboolean managed;
985         MonoPPCStackFrame *sframe;
986
987         MonoContext ctx, new_ctx;
988
989         setup_context (&ctx);
990         setup_context (&new_ctx);
991
992 #ifdef __APPLE__
993         __asm__ volatile("lwz   %0,0(r1)" : "=r" (sframe));
994 #else
995         __asm__ volatile("lwz   %0,0(1)" : "=r" (sframe));
996 #endif
997         MONO_CONTEXT_SET_IP (&ctx, sframe->lr);
998         MONO_CONTEXT_SET_BP (&ctx, sframe->sp);
999
1000         while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
1001                 
1002                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
1003                 g_assert (ji);
1004
1005                 if (ji == (gpointer)-1)
1006                         return;
1007
1008                 il_offset = mono_debug_il_offset_from_address (ji->method, native_offset, domain);
1009
1010                 if (func (ji->method, native_offset, il_offset, managed, user_data))
1011                         return;
1012                 
1013                 ctx = new_ctx;
1014                 setup_context (&ctx);
1015         }
1016 }
1017
1018 MonoBoolean
1019 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
1020                           MonoReflectionMethod **method, 
1021                           gint32 *iloffset, gint32 *native_offset,
1022                           MonoString **file, gint32 *line, gint32 *column)
1023 {
1024         MonoDomain *domain = mono_domain_get ();
1025         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1026         MonoLMF *lmf = jit_tls->lmf;
1027         MonoJitInfo *ji, rji;
1028         MonoContext ctx, new_ctx;
1029
1030         MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
1031         MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
1032
1033         skip++;
1034
1035         do {
1036                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
1037
1038                 ctx = new_ctx;
1039                 
1040                 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
1041                         return FALSE;
1042
1043                 /* skip all wrappers ??*/
1044                 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
1045                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
1046                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
1047                         continue;
1048
1049                 skip--;
1050
1051         } while (skip >= 0);
1052
1053         *method = mono_method_get_object (domain, ji->method, NULL);
1054         *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset, domain);
1055
1056         if (need_file_info) {
1057                 gchar *filename;
1058
1059                 filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
1060
1061                 *file = filename? mono_string_new (domain, filename): NULL;
1062                 *column = 0;
1063
1064                 g_free (filename);
1065         }
1066
1067         return TRUE;
1068 }
1069
1070 /**
1071  * arch_handle_exception:
1072  * @ctx: saved processor state
1073  * @obj: the exception object
1074  * @test_only: only test if the exception is caught, but dont call handlers
1075  *
1076  *
1077  */
1078 gboolean
1079 mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
1080 {
1081         MonoDomain *domain = mono_domain_get ();
1082         MonoJitInfo *ji, rji;
1083         static int (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
1084         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1085         MonoLMF *lmf = jit_tls->lmf;            
1086         GList *trace_ips = NULL;
1087         MonoException *mono_ex;
1088         MonoString *initial_stack_trace;
1089
1090         g_assert (ctx != NULL);
1091         if (!obj) {
1092                 MonoException *ex = mono_get_exception_null_reference ();
1093                 ex->message = mono_string_new (domain, 
1094                         "Object reference not set to an instance of an object");
1095                 obj = (MonoObject *)ex;
1096         } 
1097
1098         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1099                 mono_ex = (MonoException*)obj;
1100                 initial_stack_trace = mono_ex->stack_trace;
1101         } else {
1102                 mono_ex = NULL;
1103         }
1104
1105
1106         if (!call_filter)
1107                 call_filter = arch_get_call_filter ();
1108
1109         g_assert (jit_tls->end_of_stack);
1110         g_assert (jit_tls->abort_func);
1111
1112         if (!test_only) {
1113                 MonoContext ctx_cp = *ctx;
1114                 setup_context (&ctx_cp);
1115                 if (mono_jit_trace_calls != NULL)
1116                         g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
1117                 if (!mono_arch_handle_exception (&ctx_cp, obj, TRUE)) {
1118                         if (mono_break_on_exc)
1119                                 G_BREAKPOINT ();
1120                         mono_unhandled_exception (obj);
1121                 }
1122         }
1123
1124         while (1) {
1125                 MonoContext new_ctx;
1126                 char *trace = NULL;
1127                 
1128                 setup_context (&new_ctx);
1129                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, ctx, &new_ctx, 
1130                                               test_only ? &trace : NULL, &lmf, NULL, NULL);
1131                 if (!ji) {
1132                         g_warning ("Exception inside function without unwind info");
1133                         g_assert_not_reached ();
1134                 }
1135
1136                 if (ji != (gpointer)-1) {
1137                         
1138                         if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1139                                 char *tmp, *strace;
1140
1141                                 if (!initial_stack_trace) {
1142                                         trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1143
1144                                         if (!mono_ex->stack_trace)
1145                                                 strace = g_strdup ("");
1146                                         else
1147                                                 strace = mono_string_to_utf8 (mono_ex->stack_trace);
1148                         
1149                                         tmp = g_strdup_printf ("%s%s\n", strace, trace);
1150                                         g_free (strace);
1151
1152                                         mono_ex->stack_trace = mono_string_new (domain, tmp);
1153
1154                                         g_free (tmp);
1155                                 }
1156                         }
1157
1158                         if (ji->num_clauses) {
1159                                 int i;
1160                                 
1161                                 g_assert (ji->clauses);
1162                         
1163                                 for (i = 0; i < ji->num_clauses; i++) {
1164                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
1165
1166                                         if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
1167                                             MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
1168                                                 /* catch block */
1169                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
1170                                                      mono_object_isinst (obj, mono_class_get (ji->method->klass->image, ei->data.token))) ||
1171                                                     ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
1172                                                       call_filter (ctx, ei->data.filter, obj)))) {
1173                                                         if (test_only) {
1174                                                                 if (mono_ex)
1175                                                                         mono_ex->trace_ips = glist_to_array (trace_ips);
1176                                                                 g_list_free (trace_ips);
1177                                                                 g_free (trace);
1178                                                                 return TRUE;
1179                                                         }
1180                                                         if (mono_jit_trace_calls != NULL)
1181                                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1182                                                         /*printf ("stack for catch: %p\n", MONO_CONTEXT_GET_BP (ctx));*/
1183                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1184                                                         *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
1185                                                         jit_tls->lmf = lmf;
1186                                                         g_free (trace);
1187                                                         return 0;
1188                                                 }
1189                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
1190                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
1191                                                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1192                                                         if (mono_jit_trace_calls != NULL)
1193                                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1194                                                         call_filter (ctx, ei->handler_start, NULL);
1195                                                 }
1196                                                 
1197                                         }
1198                                 }
1199                         }
1200                 }
1201
1202                 g_free (trace);
1203                         
1204                 *ctx = new_ctx;
1205                 setup_context (ctx);
1206
1207                 if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
1208                         if (!test_only) {
1209                                 jit_tls->lmf = lmf;
1210                                 jit_tls->abort_func (obj);
1211                                 g_assert_not_reached ();
1212                         } else {
1213                                 if (mono_ex)
1214                                         mono_ex->trace_ips = glist_to_array (trace_ips);
1215                                 g_list_free (trace_ips);
1216                                 return FALSE;
1217                         }
1218                 }
1219         }
1220
1221         g_assert_not_reached ();
1222 }
1223
1224 gboolean
1225 mono_arch_has_unwind_info (gconstpointer addr)
1226 {
1227         return FALSE;
1228 }
1229