2008-12-12 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / exceptions-ppc.c
1 /*
2  * exceptions-ppc.c: exception support for PowerPC
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *   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 PPC_USES_FUNCTION_DESCRIPTOR
176 guint8*
177 mono_ppc_create_pre_code_ftnptr (guint8 *code)
178 {
179         MonoPPCFunctionDescriptor *ftnptr = (MonoPPCFunctionDescriptor*)code;
180
181         code += sizeof (MonoPPCFunctionDescriptor);
182         ftnptr->code = code;
183         ftnptr->toc = NULL;
184         ftnptr->env = NULL;
185
186         return code;
187 }
188 #endif
189
190 /*
191  * arch_get_restore_context:
192  *
193  * Returns a pointer to a method which restores a previously saved sigcontext.
194  * The first argument in r3 is the pointer to the context.
195  */
196 gpointer
197 mono_arch_get_restore_context (void)
198 {
199         static guint8 *start = NULL;
200
201         guint8 *code;
202         int size = MONO_PPC_32_64_CASE (128, 172) + PPC_FTNPTR_SIZE;
203
204         if (start)
205                 return start;
206
207         code = start = mono_global_codeman_reserve (size);
208         code = mono_ppc_create_pre_code_ftnptr (code);
209         restore_regs_from_context (ppc_r3, ppc_r4, ppc_r5);
210         /* restore also the stack pointer */
211         ppc_load_reg (code, ppc_sp, G_STRUCT_OFFSET (MonoContext, sc_sp), ppc_r3);
212         //ppc_break (code);
213         /* jump to the saved IP */
214         ppc_mtctr (code, ppc_r4);
215         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
216         /* never reached */
217         ppc_break (code);
218
219         g_assert ((code - start) < size);
220         mono_arch_flush_icache (start, code - start);
221         return start;
222 }
223
224 /*
225  * mono_arch_get_call_filter:
226  *
227  * Returns a pointer to a method which calls an exception filter. We
228  * also use this function to call finally handlers (we pass NULL as 
229  * @exc object in this case).
230  */
231 gpointer
232 mono_arch_get_call_filter (void)
233 {
234         static guint8 *start = NULL;
235
236         guint8 *code;
237         int alloc_size, pos, i;
238         int size = MONO_PPC_32_64_CASE (320, 500) + PPC_FTNPTR_SIZE;
239
240         if (start)
241                 return start;
242
243         /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
244         code = start = mono_global_codeman_reserve (size);
245         code = mono_ppc_create_pre_code_ftnptr (code);
246
247         /* save all the regs on the stack */
248         pos = 0;
249         for (i = 31; i >= 14; --i) {
250                 pos += sizeof (gdouble);
251                 ppc_stfd (code, i, -pos, ppc_sp);
252         }
253         pos += sizeof (gulong) * MONO_SAVED_GREGS;
254         ppc_store_multiple_regs (code, ppc_r13, ppc_sp, -pos);
255
256         ppc_mflr (code, ppc_r0);
257         ppc_store_reg (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
258
259         alloc_size = PPC_MINIMAL_STACK_SIZE + pos + 64;
260         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
261         alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
262         alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
263
264         /* allocate stack frame and set link from sp in ctx */
265         g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
266         ppc_load_reg (code, ppc_r0, G_STRUCT_OFFSET (MonoContext, sc_sp), ppc_r3);
267         ppc_load_reg_indexed (code, ppc_r0, ppc_r0, ppc_r0);
268         ppc_store_reg_update (code, ppc_r0, -alloc_size, ppc_sp);
269
270         /* restore all the regs from ctx (in r3), but not r1, the stack pointer */
271         restore_regs_from_context (ppc_r3, ppc_r6, ppc_r7);
272         /* call handler at eip (r4) and set the first arg with the exception (r5) */
273         ppc_mtctr (code, ppc_r4);
274         ppc_mr (code, ppc_r3, ppc_r5);
275         ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
276
277         /* epilog */
278         ppc_load_reg (code, ppc_r0, alloc_size + PPC_RET_ADDR_OFFSET, ppc_sp);
279         ppc_mtlr (code, ppc_r0);
280         ppc_addic (code, ppc_sp, ppc_sp, alloc_size);
281         
282         /* restore all the regs from the stack */
283         pos = 0;
284         for (i = 31; i >= 14; --i) {
285                 pos += sizeof (double);
286                 ppc_lfd (code, i, -pos, ppc_sp);
287         }
288         pos += sizeof (gulong) * MONO_SAVED_GREGS;
289         ppc_load_multiple_regs (code, ppc_r13, ppc_sp, -pos);
290
291         ppc_blr (code);
292
293         g_assert ((code - start) < size);
294         mono_arch_flush_icache (start, code - start);
295         return start;
296 }
297
298 static void
299 throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs, gboolean rethrow)
300 {
301         static void (*restore_context) (MonoContext *);
302         MonoContext ctx;
303
304         if (!restore_context)
305                 restore_context = mono_arch_get_restore_context ();
306
307         /* adjust eip so that it point into the call instruction */
308         eip -= 4;
309
310         setup_context (&ctx);
311
312         /*printf ("stack in throw: %p\n", esp);*/
313         MONO_CONTEXT_SET_BP (&ctx, esp);
314         MONO_CONTEXT_SET_IP (&ctx, eip);
315         memcpy (&ctx.regs, int_regs, sizeof (gulong) * MONO_SAVED_GREGS);
316         memcpy (&ctx.fregs, fp_regs, sizeof (double) * MONO_SAVED_FREGS);
317
318         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
319                 MonoException *mono_ex = (MonoException*)exc;
320                 if (!rethrow)
321                         mono_ex->stack_trace = NULL;
322         }
323         mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE);
324         restore_context (&ctx);
325
326         g_assert_not_reached ();
327 }
328
329 /**
330  * arch_get_throw_exception_generic:
331  *
332  * Returns a function pointer which can be used to raise 
333  * exceptions. The returned function has the following 
334  * signature: void (*func) (MonoException *exc); or
335  * void (*func) (char *exc_name);
336  *
337  */
338 static gpointer 
339 mono_arch_get_throw_exception_generic (guint8 *start, int size, int by_name, gboolean rethrow)
340 {
341         guint8 *code;
342         int alloc_size, pos, i;
343
344         code = mono_ppc_create_pre_code_ftnptr (start);
345
346         /* save all the regs on the stack */
347         pos = 0;
348         for (i = 31; i >= 14; --i) {
349                 pos += sizeof (gdouble);
350                 ppc_stfd (code, i, -pos, ppc_sp);
351         }
352         pos += sizeof (gulong) * MONO_SAVED_GREGS;
353         ppc_store_multiple_regs (code, ppc_r13, ppc_sp, -pos);
354
355         ppc_mflr (code, ppc_r0);
356         ppc_store_reg (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
357
358         /* The 64 bytes here are for outgoing arguments and a bit of
359            spare.  We don't use it all, but it doesn't hurt. */
360         alloc_size = PPC_MINIMAL_STACK_SIZE + pos + 64;
361         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
362         alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
363         alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
364
365         g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
366         ppc_store_reg_update (code, ppc_sp, -alloc_size, ppc_sp);
367
368         //ppc_break (code);
369         if (by_name) {
370                 ppc_mr (code, ppc_r5, ppc_r3);
371                 ppc_load (code, ppc_r3, (gulong)mono_defaults.corlib);
372                 ppc_load (code, ppc_r4, "System");
373                 ppc_load_func (code, ppc_r0, mono_exception_from_name);
374                 ppc_mtctr (code, ppc_r0);
375                 ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
376         }
377
378         /* call throw_exception (exc, ip, sp, int_regs, fp_regs) */
379         /* caller sp */
380         ppc_load_reg (code, ppc_r5, 0, ppc_sp);
381         /* exc is already in place in r3 */
382         if (by_name)
383                 ppc_load_reg (code, ppc_r4, PPC_RET_ADDR_OFFSET, ppc_r5);
384         else
385                 ppc_mr (code, ppc_r4, ppc_r0); /* caller ip */
386         /* pointer to the saved fp regs */
387         pos = alloc_size - sizeof (double) * MONO_SAVED_FREGS;
388         ppc_addi (code, ppc_r7, ppc_sp, pos);
389         /* pointer to the saved int regs */
390         pos -= sizeof (gulong) * MONO_SAVED_GREGS;
391         ppc_addi (code, ppc_r6, ppc_sp, pos);
392         ppc_li (code, ppc_r8, rethrow);
393
394         ppc_load_func (code, ppc_r0, throw_exception);
395         ppc_mtctr (code, ppc_r0);
396         ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
397         /* we should never reach this breakpoint */
398         ppc_break (code);
399         g_assert ((code - start) < size);
400         mono_arch_flush_icache (start, code - start);
401         return start;
402 }
403
404 /**
405  * mono_arch_get_rethrow_exception:
406  *
407  * Returns a function pointer which can be used to rethrow 
408  * exceptions. The returned function has the following 
409  * signature: void (*func) (MonoException *exc); 
410  *
411  */
412 gpointer
413 mono_arch_get_rethrow_exception (void)
414 {
415         static guint8 *start = NULL;
416         static int inited = 0;
417
418         guint8 *code;
419         int size = MONO_PPC_32_64_CASE (132, 224) + PPC_FTNPTR_SIZE;
420
421         if (inited)
422                 return start;
423         code = mono_global_codeman_reserve (size);
424         start = mono_arch_get_throw_exception_generic (code, size, FALSE, TRUE);
425         inited = 1;
426         return start;
427 }
428 /**
429  * arch_get_throw_exception:
430  *
431  * Returns a function pointer which can be used to raise 
432  * exceptions. The returned function has the following 
433  * signature: void (*func) (MonoException *exc); 
434  * For example to raise an arithmetic exception you can use:
435  *
436  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
437  * x86_call_code (code, arch_get_throw_exception ()); 
438  *
439  */
440 gpointer 
441 mono_arch_get_throw_exception (void)
442 {
443         static guint8 *start = NULL;
444         static int inited = 0;
445
446         guint8 *code;
447         int size = MONO_PPC_32_64_CASE (132, 224) + PPC_FTNPTR_SIZE;
448
449         if (inited)
450                 return start;
451         code = mono_global_codeman_reserve (size);
452         start = mono_arch_get_throw_exception_generic (code, size, FALSE, FALSE);
453         inited = 1;
454         return start;
455 }
456
457 /**
458  * arch_get_throw_exception_by_name:
459  *
460  * Returns a function pointer which can be used to raise 
461  * corlib exceptions. The returned function has the following 
462  * signature: void (*func) (char *exc_name); 
463  * For example to raise an arithmetic exception you can use:
464  *
465  * x86_push_imm (code, "ArithmeticException"); 
466  * x86_call_code (code, arch_get_throw_exception_by_name ()); 
467  *
468  */
469 gpointer 
470 mono_arch_get_throw_exception_by_name (void)
471 {
472         static guint8 *start = NULL;
473         static int inited = 0;
474
475         guint8 *code;
476         int size = MONO_PPC_32_64_CASE (168, 292) + PPC_FTNPTR_SIZE;
477
478         if (inited)
479                 return start;
480         code = mono_global_codeman_reserve (size);
481         start = mono_arch_get_throw_exception_generic (code, size, TRUE, FALSE);
482         inited = 1;
483         return start;
484 }
485
486 /* mono_arch_find_jit_info:
487  *
488  * This function is used to gather information from @ctx. It return the 
489  * MonoJitInfo of the corresponding function, unwinds one stack frame and
490  * stores the resulting context into @new_ctx. It also stores a string 
491  * describing the stack location into @trace (if not NULL), and modifies
492  * the @lmf if necessary. @native_offset return the IP offset from the 
493  * start of the function or -1 if that info is not available.
494  */
495 MonoJitInfo *
496 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
497                                                  MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
498 {
499         MonoJitInfo *ji;
500         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
501         MonoPPCStackFrame *sframe;
502
503         /* Avoid costly table lookup during stack overflow */
504         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
505                 ji = prev_ji;
506         else
507                 ji = mono_jit_info_table_find (domain, ip);
508
509         if (managed)
510                 *managed = FALSE;
511
512         if (ji != NULL) {
513                 gint32 address;
514                 int offset, i;
515
516                 *new_ctx = *ctx;
517                 setup_context (new_ctx);
518
519                 if (*lmf && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->ebp)) {
520                         /* remove any unused lmf */
521                         *lmf = (*lmf)->previous_lmf;
522                 }
523
524                 address = (char *)ip - (char *)ji->code_start;
525
526                 if (managed)
527                         if (!ji->method->wrapper_type)
528                                 *managed = TRUE;
529
530                 sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx);
531                 MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
532                 if (ji->method->save_lmf) {
533                         memcpy (&new_ctx->fregs, (char*)sframe->sp - sizeof (double) * MONO_SAVED_FREGS, sizeof (double) * MONO_SAVED_FREGS);
534                         memcpy (&new_ctx->regs, (char*)sframe->sp - sizeof (double) * MONO_SAVED_FREGS - sizeof (gulong) * MONO_SAVED_GREGS, sizeof (gulong) * MONO_SAVED_GREGS);
535                 } else if (ji->used_regs) {
536                         /* keep updated with emit_prolog in mini-ppc.c */
537                         offset = 0;
538                         /* FIXME handle floating point args 
539                         for (i = 31; i >= 14; --i) {
540                                 if (ji->used_fregs & (1 << i)) {
541                                         offset += sizeof (double);
542                                         new_ctx->fregs [i - 14] = *(gulong*)((char*)sframe->sp - offset);
543                                 }
544                         }*/
545                         for (i = 31; i >= 13; --i) {
546                                 if (ji->used_regs & (1 << i)) {
547                                         offset += sizeof (gulong);
548                                         new_ctx->regs [i - 13] = *(gulong*)((char*)sframe->sp - offset);
549                                 }
550                         }
551                 }
552                 /* the calling IP is in the parent frame */
553                 sframe = (MonoPPCStackFrame*)sframe->sp;
554                 /* we substract 4, so that the IP points into the call instruction */
555                 MONO_CONTEXT_SET_IP (new_ctx, sframe->lr - 4);
556
557                 return ji;
558         } else if (*lmf) {
559                 
560                 *new_ctx = *ctx;
561                 setup_context (new_ctx);
562
563                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
564                 } else {
565                         if (!(*lmf)->method)
566                                 return (gpointer)-1;
567
568                         memset (res, 0, sizeof (MonoJitInfo));
569                         res->method = (*lmf)->method;
570                 }
571
572                 /*sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx);
573                 MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
574                 MONO_CONTEXT_SET_IP (new_ctx, sframe->lr);*/
575                 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
576                 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
577                 memcpy (&new_ctx->regs, (*lmf)->iregs, sizeof (gulong) * MONO_SAVED_GREGS);
578                 memcpy (&new_ctx->fregs, (*lmf)->fregs, sizeof (double) * MONO_SAVED_FREGS);
579
580                 /* FIXME: what about trampoline LMF frames?  see exceptions-x86.c */
581
582                 *lmf = (*lmf)->previous_lmf;
583
584                 return ji ? ji : res;
585         }
586
587         return NULL;
588 }
589
590 /*
591  * This is the function called from the signal handler
592  */
593 void
594 mono_arch_sigctx_to_monoctx (void *ctx, MonoContext *mctx)
595 {
596         os_ucontext *uc = ctx;
597
598         mctx->sc_ir = UCONTEXT_REG_NIP(uc);
599         mctx->sc_sp = UCONTEXT_REG_Rn(uc, 1);
600         memcpy (&mctx->regs, &UCONTEXT_REG_Rn(uc, 13), sizeof (gulong) * MONO_SAVED_GREGS);
601         memcpy (&mctx->fregs, &UCONTEXT_REG_FPRn(uc, 14), sizeof (double) * MONO_SAVED_FREGS);
602 }
603
604 void
605 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *ctx)
606 {
607         os_ucontext *uc = ctx;
608
609         UCONTEXT_REG_NIP(uc) = mctx->sc_ir;
610         UCONTEXT_REG_Rn(uc, 1) = mctx->sc_sp;
611         memcpy (&UCONTEXT_REG_Rn(uc, 13), &mctx->regs, sizeof (gulong) * MONO_SAVED_GREGS);
612         memcpy (&UCONTEXT_REG_FPRn(uc, 14), &mctx->fregs, sizeof (double) * MONO_SAVED_FREGS);
613 }
614
615 gpointer
616 mono_arch_ip_from_context (void *sigctx)
617 {
618         os_ucontext *uc = sigctx;
619         return (gpointer)UCONTEXT_REG_NIP(uc);
620 }
621
622 static void
623 altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean test_only)
624 {
625         void (*restore_context) (MonoContext *);
626         MonoContext mctx;
627
628         restore_context = mono_arch_get_restore_context ();
629         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
630         mono_handle_exception (&mctx, obj, (gpointer)mctx.sc_ir, test_only);
631         restore_context (&mctx);
632 }
633
634 void
635 mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean stack_ovf)
636 {
637 #ifdef MONO_ARCH_USE_SIGACTION
638         os_ucontext *uc = (ucontext_t*)sigctx;
639         os_ucontext *uc_copy;
640         MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (sigctx));
641         gpointer *sp;
642         int frame_size;
643
644         if (stack_ovf) {
645                 const char *method;
646                 /* we don't do much now, but we can warn the user with a useful message */
647                 fprintf (stderr, "Stack overflow: IP: %p, SP: %p\n", mono_arch_ip_from_context (sigctx), (gpointer)UCONTEXT_REG_Rn(uc, 1));
648                 if (ji && ji->method)
649                         method = mono_method_full_name (ji->method, TRUE);
650                 else
651                         method = "Unmanaged";
652                 fprintf (stderr, "At %s\n", method);
653                 abort ();
654         }
655         if (!ji)
656                 mono_handle_native_sigsegv (SIGSEGV, sigctx);
657         /* setup a call frame on the real stack so that control is returned there
658          * and exception handling can continue.
659          * The frame looks like:
660          *   ucontext struct
661          *   ...
662          * 224 is the size of the red zone
663          */
664         frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 16 + 224;
665         frame_size += 15;
666         frame_size &= ~15;
667         sp = (gpointer)(UCONTEXT_REG_Rn(uc, 1) & ~15);
668         sp = (gpointer)((char*)sp - frame_size);
669         /* may need to adjust pointers in the new struct copy, depending on the OS */
670         uc_copy = (ucontext_t*)(sp + 16);
671         memcpy (uc_copy, uc, sizeof (os_ucontext));
672 #if defined(__linux__) && !defined(__mono_ppc64__)
673         uc_copy->uc_mcontext.uc_regs = (gpointer)((char*)uc_copy + ((char*)uc->uc_mcontext.uc_regs - (char*)uc));
674 #endif
675         g_assert (mono_arch_ip_from_context (uc) == mono_arch_ip_from_context (uc_copy));
676         /* at the return form the signal handler execution starts in altstack_handle_and_restore() */
677         UCONTEXT_REG_LNK(uc) = UCONTEXT_REG_NIP(uc);
678 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
679         {
680                 MonoPPCFunctionDescriptor *handler_ftnptr = (MonoPPCFunctionDescriptor*)altstack_handle_and_restore;
681
682                 UCONTEXT_REG_NIP(uc) = (gulong)handler_ftnptr->code;
683                 UCONTEXT_REG_Rn(uc, 2) = (gulong)handler_ftnptr->toc;
684         }
685 #else
686         UCONTEXT_REG_NIP(uc) = (unsigned long)altstack_handle_and_restore;
687 #endif
688         UCONTEXT_REG_Rn(uc, 1) = (unsigned long)sp;
689         UCONTEXT_REG_Rn(uc, PPC_FIRST_ARG_REG) = (unsigned long)(sp + 16);
690         UCONTEXT_REG_Rn(uc, PPC_FIRST_ARG_REG + 1) = 0;
691         UCONTEXT_REG_Rn(uc, PPC_FIRST_ARG_REG + 2) = 0;
692 #endif
693 }
694
695 gboolean
696 mono_arch_handle_exception (void *ctx, gpointer obj, gboolean test_only)
697 {
698         MonoContext mctx;
699         gboolean result;
700
701         mono_arch_sigctx_to_monoctx (ctx, &mctx);
702
703         result = mono_handle_exception (&mctx, obj, (gpointer)mctx.sc_ir, test_only);
704         /* restore the context so that returning from the signal handler will invoke
705          * the catch clause 
706          */
707         mono_arch_monoctx_to_sigctx (&mctx, ctx);
708         return result;
709 }
710
711 gboolean
712 mono_arch_has_unwind_info (gconstpointer addr)
713 {
714         return FALSE;
715 }
716