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