New tests.
[mono.git] / mono / mini / exceptions-s390x.c
1 /*------------------------------------------------------------------*/
2 /*                                                                  */
3 /* Name        - exceptions-s390.c                                  */
4 /*                                                                  */
5 /* Function    - Exception support for S/390.                       */
6 /*                                                                  */
7 /* Name        - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
8 /*                                                                  */
9 /* Date        - January, 2004                                      */
10 /*                                                                  */
11 /* Derivation  - From exceptions-x86 & exceptions-ppc               */
12 /*               Paolo Molaro (lupus@ximian.com)                    */
13 /*               Dietmar Maurer (dietmar@ximian.com)                */
14 /*                                                                  */
15 /* Copyright   - 2001 Ximian, Inc.                                  */
16 /*                                                                  */
17 /*------------------------------------------------------------------*/
18
19 /*------------------------------------------------------------------*/
20 /*                 D e f i n e s                                    */
21 /*------------------------------------------------------------------*/
22
23 #define S390_CALLFILTER_INTREGS         S390_MINIMAL_STACK_SIZE
24 #define S390_CALLFILTER_FLTREGS         (S390_CALLFILTER_INTREGS+(16*sizeof(gulong)))
25 #define S390_CALLFILTER_ACCREGS         (S390_CALLFILTER_FLTREGS+(16*sizeof(gdouble)))
26 #define S390_CALLFILTER_SIZE            (S390_CALLFILTER_ACCREGS+(16*sizeof(gint32)))
27
28 #define S390_THROWSTACK_ACCPRM          S390_MINIMAL_STACK_SIZE
29 #define S390_THROWSTACK_FPCPRM          (S390_THROWSTACK_ACCPRM+sizeof(gpointer))
30 #define S390_THROWSTACK_RETHROW         (S390_THROWSTACK_FPCPRM+sizeof(gulong))
31 #define S390_THROWSTACK_INTREGS         (S390_THROWSTACK_RETHROW+sizeof(gboolean))
32 #define S390_THROWSTACK_FLTREGS         (S390_THROWSTACK_INTREGS+(16*sizeof(gulong)))
33 #define S390_THROWSTACK_ACCREGS         (S390_THROWSTACK_FLTREGS+(16*sizeof(gdouble)))
34 #define S390_THROWSTACK_SIZE            (S390_THROWSTACK_ACCREGS+(16*sizeof(gint32)))
35
36 #define SZ_THROW        384
37
38 /*========================= End of Defines =========================*/
39
40 /*------------------------------------------------------------------*/
41 /*                 I n c l u d e s                                  */
42 /*------------------------------------------------------------------*/
43
44 #include <config.h>
45 #include <glib.h>
46 #include <signal.h>
47 #include <string.h>
48 #include <ucontext.h>
49
50 #include <mono/arch/s390x/s390x-codegen.h>
51 #include <mono/metadata/appdomain.h>
52 #include <mono/metadata/tabledefs.h>
53 #include <mono/metadata/threads.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/exception.h>
56 #include <mono/metadata/mono-debug.h>
57
58 #include "mini.h"
59 #include "mini-s390x.h"
60
61 /*========================= End of Includes ========================*/
62
63 /*------------------------------------------------------------------*/
64 /*                   P r o t o t y p e s                            */
65 /*------------------------------------------------------------------*/
66
67 gboolean mono_arch_handle_exception (void     *ctx,
68                                      gpointer obj, 
69                                      gboolean test_only);
70
71 /*========================= End of Prototypes ======================*/
72
73 /*------------------------------------------------------------------*/
74 /*                 G l o b a l   V a r i a b l e s                  */
75 /*------------------------------------------------------------------*/
76
77 typedef enum {
78         by_none,
79         by_name,
80         by_token
81 } throwType;
82
83 /*====================== End of Global Variables ===================*/
84
85 /*------------------------------------------------------------------*/
86 /*                                                                  */
87 /* Name         - mono_arch_has_unwind_info                         */
88 /*                                                                  */
89 /* Function     - Tests if a function has a DWARF exception table   */
90 /*                that is able to restore all caller saved registers*/
91 /*                                                                  */
92 /*------------------------------------------------------------------*/
93
94 gboolean
95 mono_arch_has_unwind_info (gconstpointer addr)
96 {
97         return FALSE;
98 }
99
100 /*========================= End of Function ========================*/
101
102 /*------------------------------------------------------------------*/
103 /*                                                                  */
104 /* Name         - mono_arch_get_call_filter                         */
105 /*                                                                  */
106 /* Function     - Return a pointer to a method which calls an       */
107 /*                exception filter. We also use this function to    */
108 /*                call finally handlers (we pass NULL as @exc       */
109 /*                object in this case).                             */
110 /*                                                                  */
111 /*------------------------------------------------------------------*/
112
113 gpointer
114 mono_arch_get_call_filter (void)
115 {
116         static guint8 *start;
117         static int inited = 0;
118         guint8 *code;
119         int alloc_size, pos, i;
120
121         if (inited)
122                 return start;
123
124         inited = 1;
125         /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
126         code = start = mono_global_codeman_reserve (512);
127
128         s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
129         s390_lgr  (code, s390_r14, STK_BASE);
130         alloc_size = S390_ALIGN(S390_CALLFILTER_SIZE, S390_STACK_ALIGNMENT);
131         s390_aghi (code, STK_BASE, -alloc_size);
132         s390_stg  (code, s390_r14, 0, STK_BASE, 0);
133
134         /*------------------------------------------------------*/
135         /* save general registers on stack                      */
136         /*------------------------------------------------------*/
137         s390_stmg (code, s390_r0, STK_BASE, STK_BASE, S390_CALLFILTER_INTREGS);
138
139         /*------------------------------------------------------*/
140         /* save floating point registers on stack               */
141         /*------------------------------------------------------*/
142         pos = S390_CALLFILTER_FLTREGS;
143         for (i = 0; i < 16; ++i) {
144                 s390_std (code, i, 0, STK_BASE, pos);
145                 pos += sizeof (gdouble);
146         }
147
148         /*------------------------------------------------------*/
149         /* save access registers on stack                       */
150         /*------------------------------------------------------*/
151         s390_stam (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
152
153         /*------------------------------------------------------*/
154         /* Get A(Context)                                       */
155         /*------------------------------------------------------*/
156         s390_lgr  (code, s390_r13, s390_r2);
157
158         /*------------------------------------------------------*/
159         /* Get A(Handler Entry Point)                           */
160         /*------------------------------------------------------*/
161         s390_lgr  (code, s390_r0, s390_r3);
162
163         /*------------------------------------------------------*/
164         /* Set parameter register with Exception                */
165         /*------------------------------------------------------*/
166         s390_lgr  (code, s390_r2, s390_r4);
167
168         /*------------------------------------------------------*/
169         /* Load all registers with values from the context      */
170         /*------------------------------------------------------*/
171         s390_lmg  (code, s390_r3, s390_r12, s390_r13, 
172                    G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs[3]));
173         pos = G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs[0]);
174         for (i = 0; i < 16; ++i) {
175                 s390_ld  (code, i, 0, s390_r13, pos);
176                 pos += sizeof(gdouble);
177         }
178         
179         /*------------------------------------------------------*/
180         /* Go call filter                                       */
181         /*------------------------------------------------------*/
182         s390_lgr  (code, s390_r1, s390_r0);
183         s390_basr (code, s390_r14, s390_r1);
184
185         /*------------------------------------------------------*/
186         /* Save return value                                    */
187         /*------------------------------------------------------*/
188         s390_lgr  (code, s390_r14, s390_r2);
189
190         /*------------------------------------------------------*/
191         /* Restore all the regs from the stack                  */
192         /*------------------------------------------------------*/
193         s390_lmg  (code, s390_r0, s390_r13, STK_BASE, S390_CALLFILTER_INTREGS);
194         pos = S390_CALLFILTER_FLTREGS;
195         for (i = 0; i < 16; ++i) {
196                 s390_ld (code, i, 0, STK_BASE, pos);
197                 pos += sizeof (gdouble);
198         }
199
200         s390_lgr  (code, s390_r2, s390_r14);
201         s390_lam  (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
202         s390_aghi (code, s390_r15, alloc_size);
203         s390_lmg  (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
204         s390_br   (code, s390_r14);
205
206         g_assert ((code - start) < SZ_THROW); 
207         return start;
208 }
209
210 /*========================= End of Function ========================*/
211
212 /*------------------------------------------------------------------*/
213 /*                                                                  */
214 /* Name         - throw_exception.                                  */
215 /*                                                                  */
216 /* Function     - Raise an exception based on the parameters passed.*/
217 /*                                                                  */
218 /*------------------------------------------------------------------*/
219
220 static void
221 throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp, 
222                  gulong *int_regs, gdouble *fp_regs, gint32 *acc_regs, 
223                  guint fpc, gboolean rethrow)
224 {
225         MonoContext ctx;
226         int iReg;
227         static void (*restore_context) (MonoContext *);
228
229         if (!restore_context)
230                 restore_context = mono_arch_get_restore_context();
231         
232         memset(&ctx, 0, sizeof(ctx));
233
234         getcontext(&ctx);
235
236         /* adjust eip so that it point into the call instruction */
237         ip -= 2;
238
239         for (iReg = 0; iReg < 16; iReg++) {
240                 ctx.uc_mcontext.gregs[iReg]         = int_regs[iReg];
241                 ctx.uc_mcontext.fpregs.fprs[iReg].d = fp_regs[iReg];
242                 ctx.uc_mcontext.aregs[iReg]         = acc_regs[iReg];
243         }
244
245         ctx.uc_mcontext.fpregs.fpc = fpc;
246
247         MONO_CONTEXT_SET_BP (&ctx, sp);
248         MONO_CONTEXT_SET_IP (&ctx, ip);
249         
250         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
251                 MonoException *mono_ex = (MonoException*)exc;
252                 if (!rethrow)
253                         mono_ex->stack_trace = NULL;
254         }
255         mono_arch_handle_exception (&ctx, exc, FALSE);
256         restore_context(&ctx);
257
258         g_assert_not_reached ();
259 }
260
261 /*========================= End of Function ========================*/
262
263 /*------------------------------------------------------------------*/
264 /*                                                                  */
265 /* Name         - get_throw_exception_generic                       */
266 /*                                                                  */
267 /* Function     - Return a function pointer which can be used to    */
268 /*                raise exceptions. The returned function has the   */
269 /*                following signature:                              */
270 /*                void (*func) (MonoException *exc); or,            */
271 /*                void (*func) (char *exc_name);                    */
272 /*                                                                  */
273 /*------------------------------------------------------------------*/
274
275 static gpointer 
276 get_throw_exception_generic (guint8 *start, int size, 
277                              throwType type, gboolean rethrow)
278 {
279         guint8 *code;
280         int alloc_size, pos, i;
281
282         code = start;
283
284         s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
285         alloc_size = S390_ALIGN(S390_THROWSTACK_SIZE, S390_STACK_ALIGNMENT);
286         s390_lgr  (code, s390_r14, STK_BASE);
287         s390_aghi (code, STK_BASE, -alloc_size);
288         s390_stg  (code, s390_r14, 0, STK_BASE, 0);
289         switch (type) {
290         case by_name : 
291                 s390_lgr  (code, s390_r4, s390_r2);
292                 s390_lg   (code, s390_r3, 0, s390_r2, G_STRUCT_OFFSET(MonoException, object));
293                 s390_basr (code, s390_r13, 0);
294                 s390_j    (code, 10);
295                 s390_llong(code, mono_defaults.corlib);
296                 s390_llong(code, mono_exception_from_name);
297                 s390_lg   (code, s390_r3, 0, s390_r3, G_STRUCT_OFFSET(MonoVTable, klass));
298                 s390_lg   (code, s390_r2, 0, s390_r13, 4);
299                 s390_lg   (code, s390_r1, 0, s390_r13, 12);
300                 s390_lg   (code, s390_r4, 0, s390_r3, G_STRUCT_OFFSET(MonoClass, name));
301                 s390_lg   (code, s390_r3, 0, s390_r3, G_STRUCT_OFFSET(MonoClass, name_space));
302                 s390_basr (code, s390_r14, s390_r1);
303                 break;
304         case by_token : 
305                 s390_lgr  (code, s390_r3, s390_r2);
306                 s390_basr (code, s390_r13, 0);
307                 s390_j    (code, 10);
308                 s390_llong(code, mono_defaults.exception_class->image);
309                 s390_llong(code, mono_exception_from_token);
310                 s390_lg   (code, s390_r2, 0, s390_r13, 4);
311                 s390_lg   (code, s390_r1, 0, s390_r13, 12);
312                 s390_basr (code, s390_r14, s390_r1);
313                 break;
314         case by_none :
315                 break;
316         }
317         /*------------------------------------------------------*/
318         /* save the general registers on the stack              */
319         /*------------------------------------------------------*/
320         s390_stmg (code, s390_r0, s390_r13, STK_BASE, S390_THROWSTACK_INTREGS);
321
322         s390_lgr  (code, s390_r1, STK_BASE);
323         s390_aghi (code, s390_r1, alloc_size);
324         /*------------------------------------------------------*/
325         /* save the return address in the parameter register    */
326         /*------------------------------------------------------*/
327         s390_lg   (code, s390_r3, 0, s390_r1, S390_RET_ADDR_OFFSET);
328
329         /*------------------------------------------------------*/
330         /* save the floating point registers                    */
331         /*------------------------------------------------------*/
332         pos = S390_THROWSTACK_FLTREGS;
333         for (i = 0; i < 16; ++i) {
334                 s390_std (code, i, 0, STK_BASE, pos);
335                 pos += sizeof (gdouble);
336         }
337         /*------------------------------------------------------*/
338         /* save the access registers                            */
339         /*------------------------------------------------------*/
340         s390_stam (code, s390_r0, s390_r15, STK_BASE, S390_THROWSTACK_ACCREGS);
341
342         /*------------------------------------------------------*/
343         /* call throw_exception (tkn, ip, sp, gr, fr, ar, re)   */
344         /* - r2 already contains *exc                           */
345         /*------------------------------------------------------*/
346         s390_lgr  (code, s390_r4, s390_r1);        /* caller sp */
347
348         /*------------------------------------------------------*/
349         /* pointer to the saved int regs                        */
350         /*------------------------------------------------------*/
351         s390_la   (code, s390_r5, 0, STK_BASE, S390_THROWSTACK_INTREGS);
352         s390_la   (code, s390_r6, 0, STK_BASE, S390_THROWSTACK_FLTREGS);
353         s390_la   (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCREGS);
354         s390_stg  (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCPRM);
355         s390_stfpc(code, STK_BASE, S390_THROWSTACK_FPCPRM+4);
356         s390_lghi (code, s390_r7, rethrow);
357         s390_stg  (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_RETHROW);
358         s390_basr (code, s390_r13, 0);
359         s390_j    (code, 6);
360         s390_llong(code, throw_exception);
361         s390_lg   (code, s390_r1, 0, s390_r13, 4);
362         s390_basr (code, s390_r14, s390_r1);
363         /* we should never reach this breakpoint */
364         s390_break (code);
365         g_assert ((code - start) < size);
366         return start;
367 }
368
369 /*========================= End of Function ========================*/
370
371 /*------------------------------------------------------------------*/
372 /*                                                                  */
373 /* Name         - arch_get_throw_exception                          */
374 /*                                                                  */
375 /* Function     - Return a function pointer which can be used to    */
376 /*                raise exceptions. The returned function has the   */
377 /*                following signature:                              */
378 /*                void (*func) (MonoException *exc);                */
379 /*                                                                  */
380 /*------------------------------------------------------------------*/
381
382 gpointer 
383 mono_arch_get_throw_exception (void)
384 {
385         static guint8 *start;
386         static int inited = 0;
387
388         if (inited)
389                 return start;
390         start = mono_global_codeman_reserve (SZ_THROW);
391         get_throw_exception_generic (start, SZ_THROW, by_none, FALSE);
392         inited = 1;
393         return start;
394 }
395
396 /*========================= End of Function ========================*/
397
398 /*------------------------------------------------------------------*/
399 /*                                                                  */
400 /* Name         - arch_get_rethrow_exception                        */
401 /*                                                                  */
402 /* Function     - Return a function pointer which can be used to    */
403 /*                raise exceptions. The returned function has the   */
404 /*                following signature:                              */
405 /*                void (*func) (MonoException *exc);                */
406 /*                                                                  */
407 /*------------------------------------------------------------------*/
408
409 gpointer 
410 mono_arch_get_rethrow_exception (void)
411 {
412         static guint8 *start;
413         static int inited = 0;
414
415         if (inited)
416                 return start;
417         start = mono_global_codeman_reserve (SZ_THROW);
418         get_throw_exception_generic (start, SZ_THROW, FALSE, TRUE);
419         inited = 1;
420         return start;
421 }
422
423 /*========================= End of Function ========================*/
424
425 /*------------------------------------------------------------------*/
426 /*                                                                  */
427 /* Name         - arch_get_corlib_exception                         */
428 /*                                                                  */
429 /* Function     - Return a function pointer which can be used to    */
430 /*                raise corlib exceptions. The return function has  */
431 /*                the following signature:                          */
432 /*                void (*func) (guint32 token, guint32 offset)      */
433 /*                                                                  */
434 /*------------------------------------------------------------------*/
435
436 gpointer 
437 mono_arch_get_throw_corlib_exception(void)
438 {
439         static guint8 *start;
440         static int inited = 0;
441
442         if (inited)
443                 return start;
444         start = mono_global_codeman_reserve (SZ_THROW);
445         get_throw_exception_generic (start, SZ_THROW, by_token, FALSE);
446         inited = 1;
447         return start;
448 }       
449
450 /*========================= End of Function ========================*/
451
452 /*------------------------------------------------------------------*/
453 /*                                                                  */
454 /* Name         - arch_get_throw_exception_by_name                  */
455 /*                                                                  */
456 /* Function     - Return a function pointer which can be used to    */
457 /*                raise corlib exceptions. The return function has  */
458 /*                the following signature:                          */
459 /*                void (*func) (char *exc_name);                    */
460 /*                                                                  */
461 /*------------------------------------------------------------------*/
462
463 gpointer 
464 mono_arch_get_throw_exception_by_name (void)
465 {
466         static guint8 *start;
467         static int inited = 0;
468
469         if (inited)
470                 return start;
471         start = mono_global_codeman_reserve (SZ_THROW);
472         get_throw_exception_generic (start, SZ_THROW, by_name, FALSE);
473         inited = 1;
474         return start;
475 }       
476
477 /*========================= End of Function ========================*/
478
479 /*------------------------------------------------------------------*/
480 /*                                                                  */
481 /* Name         - mono_arch_find_jit_info                           */
482 /*                                                                  */
483 /* Function     - This function is used to gather information from  */
484 /*                @ctx. It returns the MonoJitInfo of the corres-   */
485 /*                ponding function, unwinds one stack frame and     */
486 /*                stores the resulting context into @new_ctx. It    */
487 /*                also stores a string describing the stack location*/
488 /*                into @trace (if not NULL), and modifies the @lmf  */
489 /*                if necessary. @native_offset returns the IP off-  */
490 /*                set from the start of the function or -1 if that  */
491 /*                information is not available.                     */
492 /*                                                                  */
493 /*------------------------------------------------------------------*/
494
495 MonoJitInfo *
496 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
497                          MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
498                          MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
499 {
500         MonoJitInfo *ji;
501         gpointer ip = (gpointer) MONO_CONTEXT_GET_IP (ctx);
502         MonoS390StackFrame *sframe;
503
504         if (prev_ji && 
505             (ip >= prev_ji->code_start && 
506             ((guint8 *) ip <= ((guint8 *) prev_ji->code_start) + prev_ji->code_size)))
507                 ji = prev_ji;
508         else
509                 ji = mini_jit_info_table_find (domain, ip, NULL);
510
511         if (managed)
512                 *managed = FALSE;
513
514         if (ji != NULL) {
515                 gint64 address;
516
517                 *new_ctx = *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 = (MonoS390StackFrame *) MONO_CONTEXT_GET_SP (ctx);
531                 MONO_CONTEXT_SET_BP (new_ctx, sframe->prev);
532                 sframe = (MonoS390StackFrame *) sframe->prev;
533                 MONO_CONTEXT_SET_IP (new_ctx, sframe->return_address);
534                 memcpy (&new_ctx->uc_mcontext.gregs[6], sframe->regs, (8*sizeof(gint64)));
535                 return ji;
536
537         } else if (*lmf) {
538                 
539                 *new_ctx = *ctx;
540
541                 if (!(*lmf)->method)
542                         return (gpointer)-1;
543
544                 if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) {
545                 } else {
546                         memset (res, 0, MONO_SIZEOF_JIT_INFO);
547                         res->method = (*lmf)->method;
548                 }
549
550                 memcpy(new_ctx->uc_mcontext.gregs, (*lmf)->gregs, sizeof((*lmf)->gregs));
551                 memcpy(new_ctx->uc_mcontext.fpregs.fprs, (*lmf)->fregs, sizeof((*lmf)->fregs));
552
553                 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
554                 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
555                 *lmf = (*lmf)->previous_lmf;
556
557                 return ji ? ji : res;
558         }
559
560         return NULL;
561 }
562
563 /*========================= End of Function ========================*/
564
565 /*------------------------------------------------------------------*/
566 /*                                                                  */
567 /* Name         - mono_arch_handle_exception                        */
568 /*                                                                  */
569 /* Function     - Handle an exception raised by the JIT code.       */
570 /*                                                                  */
571 /* Parameters   - ctx       - Saved processor state                 */
572 /*                obj       - The exception object                  */
573 /*                test_only - Only test if the exception is caught, */
574 /*                            but don't call handlers               */
575 /*                                                                  */
576 /*------------------------------------------------------------------*/
577
578 gboolean
579 mono_arch_handle_exception (void *uc, gpointer obj, gboolean test_only)
580 {
581         return mono_handle_exception (uc, obj, mono_arch_ip_from_context(uc), test_only);
582 }
583
584 /*========================= End of Function ========================*/
585
586 /*------------------------------------------------------------------*/
587 /*                                                                  */
588 /* Name         - mono_arch_ip_from_context                         */
589 /*                                                                  */
590 /* Function     - Return the instruction pointer from the context.  */
591 /*                                                                  */
592 /* Parameters   - sigctx    - Saved processor state                 */
593 /*                                                                  */
594 /*------------------------------------------------------------------*/
595
596 gpointer
597 mono_arch_ip_from_context (void *sigctx)
598 {
599         return ((gpointer) MONO_CONTEXT_GET_IP(((MonoContext *) sigctx)));
600 }
601
602
603 /*========================= End of Function ========================*/
604
605 /*------------------------------------------------------------------*/
606 /*                                                                  */
607 /* Name         - mono_arch_get_restore_context                     */
608 /*                                                                  */
609 /* Function     - Return the address of the routine that will rest- */
610 /*                ore the context.                                  */
611 /*                                                                  */
612 /*------------------------------------------------------------------*/
613
614 gpointer
615 mono_arch_get_restore_context ()
616 {
617         return setcontext;
618 }
619
620
621 /*========================= End of Function ========================*/
622
623 /*------------------------------------------------------------------*/
624 /*                                                                  */
625 /* Name         - mono_arch_is_int_overflow                         */
626 /*                                                                  */
627 /* Function     - Inspect the code that raised the SIGFPE signal    */
628 /*                to see if the DivideByZero or Arithmetic exception*/
629 /*                should be raised.                                 */
630 /*                                                                  */
631 /*------------------------------------------------------------------*/
632
633 gboolean
634 mono_arch_is_int_overflow (void *uc, void *info)
635 {
636         MonoContext *ctx;
637         guint8      *code;
638         guint64     *operand;
639         gboolean    arithExc = TRUE;
640         gint        regNo,
641                     idxNo,
642                     offset;
643
644         ctx  = (MonoContext *) uc;
645         code =  (guint8 *) ((siginfo_t *)info)->si_addr;
646         /*----------------------------------------------------------*/
647         /* Divide operations are the only ones that will give the   */
648         /* divide by zero exception so just check for these ops.    */
649         /*----------------------------------------------------------*/
650         switch (code[0]) {
651                 case 0x1d :             /* Divide Register          */
652                         regNo = code[1] & 0x0f; 
653                         if (ctx->uc_mcontext.gregs[regNo] == 0)
654                                 arithExc = FALSE;
655                 break;
656                 case 0x5d :             /* Divide                   */
657                         regNo   = (code[2] & 0xf0 >> 8);        
658                         idxNo   = (code[1] & 0x0f);
659                         offset  = *((guint16 *) code+2) & 0x0fff;
660                         operand = (guint64*)(ctx->uc_mcontext.gregs[regNo] + offset);
661                         if (idxNo != 0)
662                                 operand += ctx->uc_mcontext.gregs[idxNo];
663                         if (*operand == 0)
664                                 arithExc = FALSE; 
665                 break;
666                 case 0xb9 :             /* DL[GR] or DS[GR]         */
667                         if ((code[1] == 0x97) || (code[1] == 0x87) ||
668                             (code[1] == 0x0d) || (code[1] == 0x1d)) {
669                                 regNo = (code[3] & 0x0f);
670                                 if (ctx->uc_mcontext.gregs[regNo] == 0)
671                                         arithExc = FALSE;
672                         }
673                 break;
674                 case 0xe3 :             /* DL[G] | DS[G]            */
675                         if ((code[5] == 0x97) || (code[5] == 0x87) ||
676                             (code[5] == 0x0d) || (code[5] == 0x1d)) {
677                                 regNo   = (code[2] & 0xf0 >> 8);        
678                                 idxNo   = (code[1] & 0x0f);
679                                 offset  = (code[2] & 0x0f << 8) + 
680                                           code[3] + (code[4] << 12);
681                                 operand = (guint64*)(ctx->uc_mcontext.gregs[regNo] + offset);
682                                 if (idxNo != 0)
683                                         operand += ctx->uc_mcontext.gregs[idxNo];
684                                 if (*operand == 0)
685                                         arithExc = FALSE; 
686                         }
687                 break;
688                 default:
689                         arithExc = TRUE;
690         }
691         ctx->uc_mcontext.psw.addr = (guint64)code;
692         return (arithExc);
693 }
694
695 /*========================= End of Function ========================*/