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