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