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