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