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