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