eb3af5f63f69b5c01ea88e2b4f1a2a28c1ec131b
[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  *   Andreas Faerber <andreas.faerber@web.de>
8  *
9  * (C) 2001 Ximian, Inc.
10  * (C) 2007-2008 Andreas Faerber
11  */
12
13 #include <config.h>
14 #include <glib.h>
15 #include <signal.h>
16 #include <string.h>
17 #include <stddef.h>
18 #include <ucontext.h>
19
20 #include <mono/arch/ppc/ppc-codegen.h>
21 #include <mono/metadata/appdomain.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/threads.h>
24 #include <mono/metadata/debug-helpers.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/mono-debug.h>
27
28 #include "mini.h"
29 #include "mini-ppc.h"
30
31 /*
32
33 struct sigcontext {
34     int      sc_onstack;     // sigstack state to restore 
35     int      sc_mask;        // signal mask to restore 
36     int      sc_ir;          // pc 
37     int      sc_psw;         // processor status word 
38     int      sc_sp;          // stack pointer if sc_regs == NULL 
39     void    *sc_regs;        // (kernel private) saved state 
40 };
41
42 struct ucontext {
43         int             uc_onstack;
44         sigset_t        uc_sigmask;     // signal mask used by this context 
45         stack_t         uc_stack;       // stack used by this context 
46         struct ucontext *uc_link;       // pointer to resuming context 
47         size_t          uc_mcsize;      // size of the machine context passed in 
48         mcontext_t      uc_mcontext;    // machine specific context 
49 };
50
51 typedef struct ppc_exception_state {
52         unsigned long dar;      // Fault registers for coredump 
53         unsigned long dsisr;
54         unsigned long exception;// number of powerpc exception taken 
55         unsigned long pad0;     // align to 16 bytes 
56
57         unsigned long pad1[4];  // space in PCB "just in case" 
58 } ppc_exception_state_t;
59
60 typedef struct ppc_vector_state {
61         unsigned long   save_vr[32][4];
62         unsigned long   save_vscr[4];
63         unsigned int    save_pad5[4];
64         unsigned int    save_vrvalid;                   // VRs that have been saved 
65         unsigned int    save_pad6[7];
66 } ppc_vector_state_t;
67
68 typedef struct ppc_float_state {
69         double  fpregs[32];
70
71         unsigned int fpscr_pad; // fpscr is 64 bits, 32 bits of rubbish 
72         unsigned int fpscr;     // floating point status register 
73 } ppc_float_state_t;
74
75 typedef struct ppc_thread_state {
76         unsigned int srr0;      // Instruction address register (PC) 
77         unsigned int srr1;      // Machine state register (supervisor) 
78         unsigned int r0;
79         unsigned int r1;
80         unsigned int r2;
81         ... 
82         unsigned int r31;
83         unsigned int cr;        // Condition register 
84         unsigned int xer;       // User's integer exception register 
85         unsigned int lr;        // Link register 
86         unsigned int ctr;       // Count register 
87         unsigned int mq;        // MQ register (601 only) 
88
89         unsigned int vrsave;    // Vector Save Register 
90 } ppc_thread_state_t;
91
92 struct mcontext {
93         ppc_exception_state_t   es;
94         ppc_thread_state_t      ss;
95         ppc_float_state_t       fs;
96         ppc_vector_state_t      vs;
97 };
98
99 typedef struct mcontext  * mcontext_t;
100
101 Linux/PPC instead has:
102 struct sigcontext {
103         unsigned long   _unused[4];
104         int             signal;
105         unsigned long   handler;
106         unsigned long   oldmask;
107         struct pt_regs  *regs;
108 };
109 struct pt_regs {
110         unsigned long gpr[32];
111         unsigned long nip;
112         unsigned long msr;
113         unsigned long orig_gpr3;        // Used for restarting system calls 
114         unsigned long ctr;
115         unsigned long link;
116         unsigned long xer;
117         unsigned long ccr;
118         unsigned long mq;               // 601 only (not used at present) 
119                                         // Used on APUS to hold IPL value. 
120         unsigned long trap;             // Reason for being here 
121         // N.B. for critical exceptions on 4xx, the dar and dsisr
122         // fields are overloaded to hold srr0 and srr1. 
123         unsigned long dar;              // Fault registers 
124         unsigned long dsisr;            // on 4xx/Book-E used for ESR 
125         unsigned long result;           // Result of a system call 
126 };
127 struct mcontext {
128         elf_gregset_t   mc_gregs;
129         elf_fpregset_t  mc_fregs;
130         unsigned long   mc_pad[2];
131         elf_vrregset_t  mc_vregs __attribute__((__aligned__(16)));
132 };
133
134 struct ucontext {
135         unsigned long    uc_flags;
136         struct ucontext *uc_link;
137         stack_t          uc_stack;
138         int              uc_pad[7];
139         struct mcontext *uc_regs;       // points to uc_mcontext field 
140         sigset_t         uc_sigmask;
141         // glibc has 1024-bit signal masks, ours are 64-bit 
142         int              uc_maskext[30];
143         int              uc_pad2[3];
144         struct mcontext  uc_mcontext;
145 };
146
147 #define ELF_NGREG       48      // includes nip, msr, lr, etc. 
148 #define ELF_NFPREG      33      // includes fpscr 
149
150 // General registers 
151 typedef unsigned long elf_greg_t;
152 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
153
154 // Floating point registers 
155 typedef double elf_fpreg_t;
156 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
157
158
159 */
160
161
162 #define restore_regs_from_context(ctx_reg,ip_reg,tmp_reg) do {  \
163                 int reg;        \
164                 ppc_load_reg (code, ip_reg, G_STRUCT_OFFSET (MonoContext, sc_ir), ctx_reg);     \
165                 ppc_load_multiple_regs (code, ppc_r13, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs));   \
166                 for (reg = 0; reg < MONO_SAVED_FREGS; ++reg) {  \
167                         ppc_lfd (code, (14 + reg),      \
168                                 G_STRUCT_OFFSET(MonoContext, fregs) + reg * sizeof (gdouble), ctx_reg); \
169                 }       \
170         } while (0)
171
172 /* nothing to do */
173 #define setup_context(ctx)
174
175 #ifdef __mono_ppc64__
176 static gpointer
177 ppc_create_ftnptr (gpointer addr)
178 {
179         gpointer *desc;
180
181         desc = mono_global_codeman_reserve (3 * sizeof (gpointer));
182
183         desc [0] = addr;
184         desc [1] = NULL;
185         desc [2] = NULL;
186
187         return desc;
188 }
189 #else
190 #define ppc_create_ftnptr(a)    a
191 #endif
192
193 /*
194  * arch_get_restore_context:
195  *
196  * Returns a pointer to a method which restores a previously saved sigcontext.
197  * The first argument in r3 is the pointer to the context.
198  */
199 gpointer
200 mono_arch_get_restore_context (void)
201 {
202         static guint8 *ftnptr = NULL;
203
204         guint8 *code;
205         guint8 *start;
206         int size = MONO_PPC_32_64_CASE (128, 172);
207
208         if (ftnptr)
209                 return ftnptr;
210
211         code = start = mono_global_codeman_reserve (size);
212         restore_regs_from_context (ppc_r3, ppc_r4, ppc_r5);
213         /* restore also the stack pointer */
214         ppc_load_reg (code, ppc_sp, G_STRUCT_OFFSET (MonoContext, sc_sp), ppc_r3);
215         //ppc_break (code);
216         /* jump to the saved IP */
217         ppc_mtctr (code, ppc_r4);
218         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
219         /* never reached */
220         ppc_break (code);
221
222         g_assert ((code - start) < size);
223         mono_arch_flush_icache (start, code - start);
224         ftnptr = ppc_create_ftnptr (start);
225         return ftnptr;
226 }
227
228 /*
229  * mono_arch_get_call_filter:
230  *
231  * Returns a pointer to a method which calls an exception filter. We
232  * also use this function to call finally handlers (we pass NULL as 
233  * @exc object in this case).
234  */
235 gpointer
236 mono_arch_get_call_filter (void)
237 {
238         static guint8 *ftnptr = NULL;
239
240         guint8 *start;
241         guint8 *code;
242         int alloc_size, pos, i;
243         int size = MONO_PPC_32_64_CASE (320, 500);
244
245         if (ftnptr)
246                 return ftnptr;
247
248         /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
249         code = start = mono_global_codeman_reserve (size);
250
251         /* save all the regs on the stack */
252         pos = 0;
253         for (i = 31; i >= 14; --i) {
254                 pos += sizeof (gdouble);
255                 ppc_stfd (code, i, -pos, ppc_sp);
256         }
257         pos += sizeof (gulong) * MONO_SAVED_GREGS;
258         ppc_store_multiple_regs (code, ppc_r13, ppc_sp, -pos);
259
260         ppc_mflr (code, ppc_r0);
261         ppc_store_reg (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
262
263         alloc_size = PPC_MINIMAL_STACK_SIZE + pos + 64;
264         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
265         alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
266         alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
267
268         /* allocate stack frame and set link from sp in ctx */
269         g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
270         ppc_load_reg (code, ppc_r0, G_STRUCT_OFFSET (MonoContext, sc_sp), ppc_r3);
271         ppc_load_reg_indexed (code, ppc_r0, ppc_r0, ppc_r0);
272         ppc_store_reg_update (code, ppc_r0, -alloc_size, ppc_sp);
273
274         /* restore all the regs from ctx (in r3), but not r1, the stack pointer */
275         restore_regs_from_context (ppc_r3, ppc_r6, ppc_r7);
276         /* call handler at eip (r4) and set the first arg with the exception (r5) */
277         ppc_mtctr (code, ppc_r4);
278         ppc_mr (code, ppc_r3, ppc_r5);
279         ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
280
281         /* epilog */
282         ppc_load_reg (code, ppc_r0, alloc_size + PPC_RET_ADDR_OFFSET, ppc_sp);
283         ppc_mtlr (code, ppc_r0);
284         ppc_addic (code, ppc_sp, ppc_sp, alloc_size);
285         
286         /* restore all the regs from the stack */
287         pos = 0;
288         for (i = 31; i >= 14; --i) {
289                 pos += sizeof (double);
290                 ppc_lfd (code, i, -pos, ppc_sp);
291         }
292         pos += sizeof (gulong) * MONO_SAVED_GREGS;
293         ppc_load_multiple_regs (code, ppc_r13, ppc_sp, -pos);
294
295         ppc_blr (code);
296
297         g_assert ((code - start) < size);
298         mono_arch_flush_icache (start, code - start);
299         ftnptr = ppc_create_ftnptr (start);
300         return ftnptr;
301 }
302
303 static void
304 throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs, gboolean rethrow)
305 {
306         static void (*restore_context) (MonoContext *);
307         MonoContext ctx;
308
309         if (!restore_context)
310                 restore_context = mono_arch_get_restore_context ();
311
312         /* adjust eip so that it point into the call instruction */
313         eip -= 4;
314
315         setup_context (&ctx);
316
317         /*printf ("stack in throw: %p\n", esp);*/
318         MONO_CONTEXT_SET_BP (&ctx, esp);
319         MONO_CONTEXT_SET_IP (&ctx, eip);
320         memcpy (&ctx.regs, int_regs, sizeof (gulong) * MONO_SAVED_GREGS);
321         memcpy (&ctx.fregs, fp_regs, sizeof (double) * MONO_SAVED_FREGS);
322
323         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
324                 MonoException *mono_ex = (MonoException*)exc;
325                 if (!rethrow)
326                         mono_ex->stack_trace = NULL;
327         }
328         mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE);
329         restore_context (&ctx);
330
331         g_assert_not_reached ();
332 }
333
334 /**
335  * arch_get_throw_exception_generic:
336  *
337  * Returns a function pointer which can be used to raise 
338  * exceptions. The returned function has the following 
339  * signature: void (*func) (MonoException *exc); or
340  * void (*func) (char *exc_name);
341  *
342  */
343 static gpointer 
344 mono_arch_get_throw_exception_generic (guint8 *start, int size, int by_name, gboolean rethrow)
345 {
346         guint8 *code;
347         int alloc_size, pos, i;
348
349         code = start;
350
351         /* save all the regs on the stack */
352         pos = 0;
353         for (i = 31; i >= 14; --i) {
354                 pos += sizeof (gdouble);
355                 ppc_stfd (code, i, -pos, ppc_sp);
356         }
357         pos += sizeof (gulong) * MONO_SAVED_GREGS;
358         ppc_store_multiple_regs (code, ppc_r13, ppc_sp, -pos);
359
360         ppc_mflr (code, ppc_r0);
361         ppc_store_reg (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
362
363         /* The 64 bytes here are for outgoing arguments and a bit of
364            spare.  We don't use it all, but it doesn't hurt. */
365         alloc_size = PPC_MINIMAL_STACK_SIZE + pos + 64;
366         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
367         alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
368         alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
369
370         g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
371         ppc_store_reg_update (code, ppc_sp, -alloc_size, ppc_sp);
372
373         //ppc_break (code);
374         if (by_name) {
375                 ppc_mr (code, ppc_r5, ppc_r3);
376                 ppc_load (code, ppc_r3, (gulong)mono_defaults.corlib);
377                 ppc_load (code, ppc_r4, "System");
378                 ppc_load_func (code, ppc_r0, mono_exception_from_name);
379                 ppc_mtctr (code, ppc_r0);
380                 ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
381         }
382
383         /* call throw_exception (exc, ip, sp, int_regs, fp_regs) */
384         /* caller sp */
385         ppc_load_reg (code, ppc_r5, 0, ppc_sp);
386         /* exc is already in place in r3 */
387         if (by_name)
388                 ppc_load_reg (code, ppc_r4, PPC_RET_ADDR_OFFSET, ppc_r5);
389         else
390                 ppc_mr (code, ppc_r4, ppc_r0); /* caller ip */
391         /* pointer to the saved fp regs */
392         pos = alloc_size - sizeof (double) * MONO_SAVED_FREGS;
393         ppc_addi (code, ppc_r7, ppc_sp, pos);
394         /* pointer to the saved int regs */
395         pos -= sizeof (gulong) * MONO_SAVED_GREGS;
396         ppc_addi (code, ppc_r6, ppc_sp, pos);
397         ppc_li (code, ppc_r8, rethrow);
398
399         ppc_load_func (code, ppc_r0, throw_exception);
400         ppc_mtctr (code, ppc_r0);
401         ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
402         /* we should never reach this breakpoint */
403         ppc_break (code);
404         g_assert ((code - start) < size);
405         mono_arch_flush_icache (start, code - start);
406         return ppc_create_ftnptr (start);
407 }
408
409 /**
410  * mono_arch_get_rethrow_exception:
411  *
412  * Returns a function pointer which can be used to rethrow 
413  * exceptions. The returned function has the following 
414  * signature: void (*func) (MonoException *exc); 
415  *
416  */
417 gpointer
418 mono_arch_get_rethrow_exception (void)
419 {
420         static guint8 *start = NULL;
421         static int inited = 0;
422
423         guint8 *code;
424         int size = MONO_PPC_32_64_CASE (132, 224);
425
426         if (inited)
427                 return start;
428         code = mono_global_codeman_reserve (size);
429         start = mono_arch_get_throw_exception_generic (code, size, FALSE, TRUE);
430         inited = 1;
431         return start;
432 }
433 /**
434  * arch_get_throw_exception:
435  *
436  * Returns a function pointer which can be used to raise 
437  * exceptions. The returned function has the following 
438  * signature: void (*func) (MonoException *exc); 
439  * For example to raise an arithmetic exception you can use:
440  *
441  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
442  * x86_call_code (code, arch_get_throw_exception ()); 
443  *
444  */
445 gpointer 
446 mono_arch_get_throw_exception (void)
447 {
448         static guint8 *start = NULL;
449         static int inited = 0;
450
451         guint8 *code;
452         int size = MONO_PPC_32_64_CASE (132, 224);
453
454         if (inited)
455                 return start;
456         code = mono_global_codeman_reserve (size);
457         start = mono_arch_get_throw_exception_generic (code, size, FALSE, FALSE);
458         inited = 1;
459         return start;
460 }
461
462 /**
463  * arch_get_throw_exception_by_name:
464  *
465  * Returns a function pointer which can be used to raise 
466  * corlib exceptions. The returned function has the following 
467  * signature: void (*func) (char *exc_name); 
468  * For example to raise an arithmetic exception you can use:
469  *
470  * x86_push_imm (code, "ArithmeticException"); 
471  * x86_call_code (code, arch_get_throw_exception_by_name ()); 
472  *
473  */
474 gpointer 
475 mono_arch_get_throw_exception_by_name (void)
476 {
477         static guint8 *start = NULL;
478         static int inited = 0;
479
480         guint8 *code;
481         int size = MONO_PPC_32_64_CASE (168, 292);
482
483         if (inited)
484                 return start;
485         code = mono_global_codeman_reserve (size);
486         start = mono_arch_get_throw_exception_generic (code, size, TRUE, FALSE);
487         inited = 1;
488         return start;
489 }
490
491 /* mono_arch_find_jit_info:
492  *
493  * This function is used to gather information from @ctx. It return the 
494  * MonoJitInfo of the corresponding function, unwinds one stack frame and
495  * stores the resulting context into @new_ctx. It also stores a string 
496  * describing the stack location into @trace (if not NULL), and modifies
497  * the @lmf if necessary. @native_offset return the IP offset from the 
498  * start of the function or -1 if that info is not available.
499  */
500 MonoJitInfo *
501 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
502                                                  MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
503 {
504         MonoJitInfo *ji;
505         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
506         MonoPPCStackFrame *sframe;
507
508         /* Avoid costly table lookup during stack overflow */
509         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
510                 ji = prev_ji;
511         else
512                 ji = mono_jit_info_table_find (domain, ip);
513
514         if (managed)
515                 *managed = FALSE;
516
517         if (ji != NULL) {
518                 gint32 address;
519                 int offset, i;
520
521                 *new_ctx = *ctx;
522                 setup_context (new_ctx);
523
524                 if (*lmf && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->ebp)) {
525                         /* remove any unused lmf */
526                         *lmf = (*lmf)->previous_lmf;
527                 }
528
529                 address = (char *)ip - (char *)ji->code_start;
530
531                 if (managed)
532                         if (!ji->method->wrapper_type)
533                                 *managed = TRUE;
534
535                 sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx);
536                 MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
537                 if (ji->method->save_lmf) {
538                         memcpy (&new_ctx->fregs, (char*)sframe->sp - sizeof (double) * MONO_SAVED_FREGS, sizeof (double) * MONO_SAVED_FREGS);
539                         memcpy (&new_ctx->regs, (char*)sframe->sp - sizeof (double) * MONO_SAVED_FREGS - sizeof (gulong) * MONO_SAVED_GREGS, sizeof (gulong) * MONO_SAVED_GREGS);
540                 } else if (ji->used_regs) {
541                         /* keep updated with emit_prolog in mini-ppc.c */
542                         offset = 0;
543                         /* FIXME handle floating point args 
544                         for (i = 31; i >= 14; --i) {
545                                 if (ji->used_fregs & (1 << i)) {
546                                         offset += sizeof (double);
547                                         new_ctx->fregs [i - 14] = *(gulong*)((char*)sframe->sp - offset);
548                                 }
549                         }*/
550                         for (i = 31; i >= 13; --i) {
551                                 if (ji->used_regs & (1 << i)) {
552                                         offset += sizeof (gulong);
553                                         new_ctx->regs [i - 13] = *(gulong*)((char*)sframe->sp - offset);
554                                 }
555                         }
556                 }
557                 /* the calling IP is in the parent frame */
558                 sframe = (MonoPPCStackFrame*)sframe->sp;
559                 /* we substract 4, so that the IP points into the call instruction */
560                 MONO_CONTEXT_SET_IP (new_ctx, sframe->lr - 4);
561
562                 return ji;
563         } else if (*lmf) {
564                 
565                 *new_ctx = *ctx;
566                 setup_context (new_ctx);
567
568                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
569                 } else {
570                         if (!(*lmf)->method)
571                                 return (gpointer)-1;
572
573                         memset (res, 0, sizeof (MonoJitInfo));
574                         res->method = (*lmf)->method;
575                 }
576
577                 /*sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx);
578                 MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
579                 MONO_CONTEXT_SET_IP (new_ctx, sframe->lr);*/
580                 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
581                 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
582                 memcpy (&new_ctx->regs, (*lmf)->iregs, sizeof (gulong) * MONO_SAVED_GREGS);
583                 memcpy (&new_ctx->fregs, (*lmf)->fregs, sizeof (double) * MONO_SAVED_FREGS);
584
585                 /* FIXME: what about trampoline LMF frames?  see exceptions-x86.c */
586
587                 *lmf = (*lmf)->previous_lmf;
588
589                 return ji ? ji : res;
590         }
591
592         return NULL;
593 }
594
595 /*
596  * This is the function called from the signal handler
597  */
598 void
599 mono_arch_sigctx_to_monoctx (void *ctx, MonoContext *mctx)
600 {
601         os_ucontext *uc = ctx;
602
603         mctx->sc_ir = UCONTEXT_REG_NIP(uc);
604         mctx->sc_sp = UCONTEXT_REG_Rn(uc, 1);
605         memcpy (&mctx->regs, &UCONTEXT_REG_Rn(uc, 13), sizeof (gulong) * MONO_SAVED_GREGS);
606         memcpy (&mctx->fregs, &UCONTEXT_REG_FPRn(uc, 14), sizeof (double) * MONO_SAVED_FREGS);
607 }
608
609 void
610 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *ctx)
611 {
612         os_ucontext *uc = ctx;
613
614         UCONTEXT_REG_NIP(uc) = mctx->sc_ir;
615         UCONTEXT_REG_Rn(uc, 1) = mctx->sc_sp;
616         memcpy (&UCONTEXT_REG_Rn(uc, 13), &mctx->regs, sizeof (gulong) * MONO_SAVED_GREGS);
617         memcpy (&UCONTEXT_REG_FPRn(uc, 14), &mctx->fregs, sizeof (double) * MONO_SAVED_FREGS);
618 }
619
620 gpointer
621 mono_arch_ip_from_context (void *sigctx)
622 {
623         os_ucontext *uc = sigctx;
624         return (gpointer)UCONTEXT_REG_NIP(uc);
625 }
626
627 static void
628 altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean test_only)
629 {
630         void (*restore_context) (MonoContext *);
631         MonoContext mctx;
632
633         restore_context = mono_arch_get_restore_context ();
634         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
635         mono_handle_exception (&mctx, obj, (gpointer)mctx.sc_ir, test_only);
636         restore_context (&mctx);
637 }
638
639 void
640 mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean stack_ovf)
641 {
642 #ifdef MONO_ARCH_USE_SIGACTION
643         os_ucontext *uc = (ucontext_t*)sigctx;
644         os_ucontext *uc_copy;
645         MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (sigctx));
646         gpointer *sp;
647         int frame_size;
648
649         if (stack_ovf) {
650                 const char *method;
651                 /* we don't do much now, but we can warn the user with a useful message */
652                 fprintf (stderr, "Stack overflow: IP: %p, SP: %p\n", mono_arch_ip_from_context (sigctx), (gpointer)UCONTEXT_REG_Rn(uc, 1));
653                 if (ji && ji->method)
654                         method = mono_method_full_name (ji->method, TRUE);
655                 else
656                         method = "Unmanaged";
657                 fprintf (stderr, "At %s\n", method);
658                 abort ();
659         }
660         if (!ji)
661                 mono_handle_native_sigsegv (SIGSEGV, sigctx);
662         /* setup a call frame on the real stack so that control is returned there
663          * and exception handling can continue.
664          * The frame looks like:
665          *   ucontext struct
666          *   ...
667          * 224 is the size of the red zone
668          */
669         frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 16 + 224;
670         frame_size += 15;
671         frame_size &= ~15;
672         sp = (gpointer)(UCONTEXT_REG_Rn(uc, 1) & ~15);
673         sp = (gpointer)((char*)sp - frame_size);
674         /* may need to adjust pointers in the new struct copy, depending on the OS */
675         uc_copy = (ucontext_t*)(sp + 16);
676         memcpy (uc_copy, uc, sizeof (os_ucontext));
677 #if defined(__linux__) && !defined(__mono_ppc64__)
678         uc_copy->uc_mcontext.uc_regs = (gpointer)((char*)uc_copy + ((char*)uc->uc_mcontext.uc_regs - (char*)uc));
679 #endif
680         g_assert (mono_arch_ip_from_context (uc) == mono_arch_ip_from_context (uc_copy));
681         /* at the return form the signal handler execution starts in altstack_handle_and_restore() */
682         UCONTEXT_REG_LNK(uc) = UCONTEXT_REG_NIP(uc);
683 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
684         {
685                 MonoPPCFunctionDescriptor *handler_ftnptr = (MonoPPCFunctionDescriptor*)altstack_handle_and_restore;
686
687                 UCONTEXT_REG_NIP(uc) = (gulong)handler_ftnptr->code;
688                 UCONTEXT_REG_Rn(uc, 2) = (gulong)handler_ftnptr->toc;
689         }
690 #else
691         UCONTEXT_REG_NIP(uc) = (unsigned long)altstack_handle_and_restore;
692 #endif
693         UCONTEXT_REG_Rn(uc, 1) = (unsigned long)sp;
694         UCONTEXT_REG_Rn(uc, PPC_FIRST_ARG_REG) = (unsigned long)(sp + 16);
695         UCONTEXT_REG_Rn(uc, PPC_FIRST_ARG_REG + 1) = 0;
696         UCONTEXT_REG_Rn(uc, PPC_FIRST_ARG_REG + 2) = 0;
697 #endif
698 }
699
700 gboolean
701 mono_arch_handle_exception (void *ctx, gpointer obj, gboolean test_only)
702 {
703         MonoContext mctx;
704         gboolean result;
705
706         mono_arch_sigctx_to_monoctx (ctx, &mctx);
707
708         result = mono_handle_exception (&mctx, obj, (gpointer)mctx.sc_ir, test_only);
709         /* restore the context so that returning from the signal handler will invoke
710          * the catch clause 
711          */
712         mono_arch_monoctx_to_sigctx (&mctx, ctx);
713         return result;
714 }
715
716 gboolean
717 mono_arch_has_unwind_info (gconstpointer addr)
718 {
719         return FALSE;
720 }
721