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