1 /*------------------------------------------------------------------*/
3 /* Name - exceptions-s390.c */
5 /* Function - Exception support for S/390. */
7 /* Name - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
9 /* Date - January, 2004 */
11 /* Derivation - From exceptions-x86 & exceptions-ppc */
12 /* Paolo Molaro (lupus@ximian.com) */
13 /* Dietmar Maurer (dietmar@ximian.com) */
15 /* Copyright - 2001 Ximian, Inc. */
17 /*------------------------------------------------------------------*/
19 /*------------------------------------------------------------------*/
21 /*------------------------------------------------------------------*/
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)))
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)))
36 #define S390_REG_SAVE_R13 (S390_REG_SAVE_OFFSET+(7*sizeof(gulong)))
40 #define setup_context(ctx)
42 /*========================= End of Defines =========================*/
44 /*------------------------------------------------------------------*/
46 /*------------------------------------------------------------------*/
54 #include <mono/arch/s390x/s390x-codegen.h>
55 #include <mono/metadata/appdomain.h>
56 #include <mono/metadata/tabledefs.h>
57 #include <mono/metadata/threads.h>
58 #include <mono/metadata/debug-helpers.h>
59 #include <mono/metadata/exception.h>
60 #include <mono/metadata/mono-debug.h>
63 #include "mini-s390x.h"
65 /*========================= End of Includes ========================*/
67 /*------------------------------------------------------------------*/
68 /* P r o t o t y p e s */
69 /*------------------------------------------------------------------*/
71 gboolean
mono_arch_handle_exception (void *ctx
,
74 /*========================= End of Prototypes ======================*/
76 /*------------------------------------------------------------------*/
77 /* G l o b a l V a r i a b l e s */
78 /*------------------------------------------------------------------*/
85 /*====================== End of Global Variables ===================*/
87 /*------------------------------------------------------------------*/
89 /* Name - mono_arch_get_call_filter */
91 /* Function - Return a pointer to a method which calls an */
92 /* exception filter. We also use this function to */
93 /* call finally handlers (we pass NULL as @exc */
94 /* object in this case). */
96 /*------------------------------------------------------------------*/
99 mono_arch_get_call_filter (MonoTrampInfo
**info
, gboolean aot
)
101 static guint8
*start
;
102 static int inited
= 0;
104 int alloc_size
, pos
, i
;
105 GSList
*unwind_ops
= NULL
;
106 MonoJumpInfo
*ji
= NULL
;
114 /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
115 code
= start
= mono_global_codeman_reserve (512);
117 s390_stmg (code
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
118 s390_lgr (code
, s390_r14
, STK_BASE
);
119 alloc_size
= S390_ALIGN(S390_CALLFILTER_SIZE
, S390_STACK_ALIGNMENT
);
120 s390_aghi (code
, STK_BASE
, -alloc_size
);
121 s390_stg (code
, s390_r14
, 0, STK_BASE
, 0);
123 /*------------------------------------------------------*/
124 /* save general registers on stack */
125 /*------------------------------------------------------*/
126 s390_stmg (code
, s390_r0
, STK_BASE
, STK_BASE
, S390_CALLFILTER_INTREGS
);
128 /*------------------------------------------------------*/
129 /* save floating point registers on stack */
130 /*------------------------------------------------------*/
131 pos
= S390_CALLFILTER_FLTREGS
;
132 for (i
= 0; i
< 16; ++i
) {
133 s390_std (code
, i
, 0, STK_BASE
, pos
);
134 pos
+= sizeof (gdouble
);
137 /*------------------------------------------------------*/
138 /* save access registers on stack */
139 /*------------------------------------------------------*/
140 s390_stam (code
, s390_a0
, s390_a15
, STK_BASE
, S390_CALLFILTER_ACCREGS
);
142 /*------------------------------------------------------*/
144 /*------------------------------------------------------*/
145 s390_lgr (code
, s390_r13
, s390_r2
);
147 /*------------------------------------------------------*/
148 /* Get A(Handler Entry Point) */
149 /*------------------------------------------------------*/
150 s390_lgr (code
, s390_r0
, s390_r3
);
152 /*------------------------------------------------------*/
153 /* Set parameter register with Exception */
154 /*------------------------------------------------------*/
155 s390_lgr (code
, s390_r2
, s390_r4
);
157 /*------------------------------------------------------*/
158 /* Load all registers with values from the context */
159 /*------------------------------------------------------*/
160 s390_lmg (code
, s390_r3
, s390_r12
, s390_r13
,
161 G_STRUCT_OFFSET(MonoContext
, uc_mcontext
.gregs
[3]));
162 pos
= G_STRUCT_OFFSET(MonoContext
, uc_mcontext
.fpregs
.fprs
[0]);
163 for (i
= 0; i
< 16; ++i
) {
164 s390_ld (code
, i
, 0, s390_r13
, pos
);
165 pos
+= sizeof(gdouble
);
169 /*------------------------------------------------------*/
170 /* We need to preserve current SP before calling filter */
171 /* with SP from the context */
172 /*------------------------------------------------------*/
173 s390_lgr (code
, s390_r14
, STK_BASE
);
174 s390_lg (code
, STK_BASE
, 0, s390_r13
,
175 G_STRUCT_OFFSET(MonoContext
, uc_mcontext
.gregs
[15]));
176 s390_lgr (code
, s390_r13
, s390_r14
);
179 /*------------------------------------------------------*/
181 /*------------------------------------------------------*/
182 s390_lgr (code
, s390_r1
, s390_r0
);
183 s390_basr (code
, s390_r14
, s390_r1
);
185 /*------------------------------------------------------*/
186 /* Save return value */
187 /*------------------------------------------------------*/
188 s390_lgr (code
, s390_r14
, s390_r2
);
191 /*------------------------------------------------------*/
192 /* Reload our stack register with value saved in context*/
193 /*------------------------------------------------------*/
194 s390_lgr (code
, STK_BASE
, s390_r13
);
197 /*------------------------------------------------------*/
198 /* Restore all the regs from the stack */
199 /*------------------------------------------------------*/
200 s390_lmg (code
, s390_r0
, s390_r13
, STK_BASE
, S390_CALLFILTER_INTREGS
);
201 pos
= S390_CALLFILTER_FLTREGS
;
202 for (i
= 0; i
< 16; ++i
) {
203 s390_ld (code
, i
, 0, STK_BASE
, pos
);
204 pos
+= sizeof (gdouble
);
207 s390_lgr (code
, s390_r2
, s390_r14
);
208 s390_lam (code
, s390_a0
, s390_a15
, STK_BASE
, S390_CALLFILTER_ACCREGS
);
209 s390_aghi (code
, s390_r15
, alloc_size
);
210 s390_lmg (code
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
211 s390_br (code
, s390_r14
);
213 g_assert ((code
- start
) < SZ_THROW
);
216 *info
= mono_tramp_info_create (g_strdup_printf("call_filter"),
217 start
, code
- start
, ji
,
223 /*========================= End of Function ========================*/
225 /*------------------------------------------------------------------*/
227 /* Name - throw_exception. */
229 /* Function - Raise an exception based on the parameters passed.*/
231 /*------------------------------------------------------------------*/
234 throw_exception (MonoObject
*exc
, unsigned long ip
, unsigned long sp
,
235 gulong
*int_regs
, gdouble
*fp_regs
, gint32
*acc_regs
,
236 guint fpc
, gboolean rethrow
)
240 static void (*restore_context
) (MonoContext
*);
242 if (!restore_context
)
243 restore_context
= mono_get_restore_context();
245 memset(&ctx
, 0, sizeof(ctx
));
249 /* adjust eip so that it point into the call instruction */
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
];
258 ctx
.uc_mcontext
.fpregs
.fpc
= fpc
;
260 MONO_CONTEXT_SET_BP (&ctx
, sp
);
261 MONO_CONTEXT_SET_IP (&ctx
, ip
);
263 if (mono_object_isinst (exc
, mono_defaults
.exception_class
)) {
264 MonoException
*mono_ex
= (MonoException
*)exc
;
266 mono_ex
->stack_trace
= NULL
;
268 // mono_arch_handle_exception (&ctx, exc, FALSE);
269 mono_handle_exception (&ctx
, exc
);
270 restore_context(&ctx
);
272 g_assert_not_reached ();
275 /*========================= End of Function ========================*/
277 /*------------------------------------------------------------------*/
279 /* Name - get_throw_exception_generic */
281 /* Function - Return a function pointer which can be used to */
282 /* raise exceptions. The returned function has the */
283 /* following signature: */
284 /* void (*func) (MonoException *exc); or, */
285 /* void (*func) (char *exc_name); */
287 /*------------------------------------------------------------------*/
290 mono_arch_get_throw_exception_generic (int size
, MonoTrampInfo
**info
,
291 int corlib
, gboolean rethrow
, gboolean aot
)
293 guint8
*code
, *start
;
294 int alloc_size
, pos
, i
;
295 MonoJumpInfo
*ji
= NULL
;
296 GSList
*unwind_ops
= NULL
;
298 code
= start
= mono_global_codeman_reserve(size
);
300 s390_stmg (code
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
301 alloc_size
= S390_ALIGN(S390_THROWSTACK_SIZE
, S390_STACK_ALIGNMENT
);
302 s390_lgr (code
, s390_r14
, STK_BASE
);
303 s390_aghi (code
, STK_BASE
, -alloc_size
);
304 s390_stg (code
, s390_r14
, 0, STK_BASE
, 0);
305 s390_lgr (code
, s390_r3
, s390_r2
);
307 s390_basr (code
, s390_r13
, 0);
309 s390_llong(code
, mono_defaults
.exception_class
->image
);
310 s390_llong(code
, mono_exception_from_token
);
311 s390_lg (code
, s390_r2
, 0, s390_r13
, 4);
312 s390_lg (code
, s390_r1
, 0, s390_r13
, 12);
313 s390_basr (code
, s390_r14
, s390_r1
);
316 /*------------------------------------------------------*/
317 /* save the general registers on the stack */
318 /*------------------------------------------------------*/
319 s390_stmg (code
, s390_r0
, s390_r13
, STK_BASE
, S390_THROWSTACK_INTREGS
);
321 s390_lgr (code
, s390_r1
, STK_BASE
);
322 s390_aghi (code
, s390_r1
, alloc_size
);
323 /*------------------------------------------------------*/
324 /* save the return address in the parameter register */
325 /*------------------------------------------------------*/
326 s390_lg (code
, s390_r3
, 0, s390_r1
, S390_RET_ADDR_OFFSET
);
328 /*------------------------------------------------------*/
329 /* save the floating point registers */
330 /*------------------------------------------------------*/
331 pos
= S390_THROWSTACK_FLTREGS
;
332 for (i
= 0; i
< 16; ++i
) {
333 s390_std (code
, i
, 0, STK_BASE
, pos
);
334 pos
+= sizeof (gdouble
);
336 /*------------------------------------------------------*/
337 /* save the access registers */
338 /*------------------------------------------------------*/
339 s390_stam (code
, s390_r0
, s390_r15
, STK_BASE
, S390_THROWSTACK_ACCREGS
);
341 /*------------------------------------------------------*/
342 /* call throw_exception (tkn, ip, sp, gr, fr, ar, re) */
343 /* - r2 already contains *exc */
344 /*------------------------------------------------------*/
345 s390_lgr (code
, s390_r4
, s390_r1
); /* caller sp */
347 /*------------------------------------------------------*/
348 /* pointer to the saved int regs */
349 /*------------------------------------------------------*/
350 s390_la (code
, s390_r5
, 0, STK_BASE
, S390_THROWSTACK_INTREGS
);
351 s390_la (code
, s390_r6
, 0, STK_BASE
, S390_THROWSTACK_FLTREGS
);
352 s390_la (code
, s390_r7
, 0, STK_BASE
, S390_THROWSTACK_ACCREGS
);
353 s390_stg (code
, s390_r7
, 0, STK_BASE
, S390_THROWSTACK_ACCPRM
);
354 s390_stfpc(code
, STK_BASE
, S390_THROWSTACK_FPCPRM
+4);
355 s390_lghi (code
, s390_r7
, rethrow
);
356 s390_stg (code
, s390_r7
, 0, STK_BASE
, S390_THROWSTACK_RETHROW
);
357 s390_basr (code
, s390_r13
, 0);
359 s390_llong(code
, throw_exception
);
360 s390_lg (code
, s390_r1
, 0, s390_r13
, 4);
361 s390_basr (code
, s390_r14
, s390_r1
);
362 /* we should never reach this breakpoint */
364 g_assert ((code
- start
) < size
);
367 *info
= mono_tramp_info_create (g_strdup_printf(corlib
? "throw_corlib_exception"
368 : (rethrow
? "rethrow_exception"
369 : "throw_exception")),
370 start
, code
- start
, ji
, unwind_ops
);
375 /*========================= End of Function ========================*/
377 /*------------------------------------------------------------------*/
379 /* Name - arch_get_throw_exception */
381 /* Function - Return a function pointer which can be used to */
382 /* raise exceptions. The returned function has the */
383 /* following signature: */
384 /* void (*func) (MonoException *exc); */
386 /*------------------------------------------------------------------*/
389 mono_arch_get_throw_exception (MonoTrampInfo
**info
, gboolean aot
)
396 return (mono_arch_get_throw_exception_generic (SZ_THROW
, info
, FALSE
, FALSE
, aot
));
399 /*========================= End of Function ========================*/
401 /*------------------------------------------------------------------*/
403 /* Name - arch_get_rethrow_exception */
405 /* Function - Return a function pointer which can be used to */
406 /* raise exceptions. The returned function has the */
407 /* following signature: */
408 /* void (*func) (MonoException *exc); */
410 /*------------------------------------------------------------------*/
413 mono_arch_get_rethrow_exception (MonoTrampInfo
**info
, gboolean aot
)
419 return (mono_arch_get_throw_exception_generic (SZ_THROW
, info
, FALSE
, FALSE
, aot
));
422 /*========================= End of Function ========================*/
424 /*------------------------------------------------------------------*/
426 /* Name - arch_get_corlib_exception */
428 /* Function - Return a function pointer which can be used to */
429 /* raise corlib exceptions. The return function has */
430 /* the following signature: */
431 /* void (*func) (guint32 token, guint32 offset) */
433 /*------------------------------------------------------------------*/
436 mono_arch_get_throw_corlib_exception (MonoTrampInfo
**info
, gboolean aot
)
442 return (mono_arch_get_throw_exception_generic (SZ_THROW
, info
, TRUE
, FALSE
, aot
));
445 /*========================= End of Function ========================*/
447 /*------------------------------------------------------------------*/
449 /* Name - mono_arch_find_jit_info */
451 /* Function - See exceptions-amd64.c for docs. */
453 /*------------------------------------------------------------------*/
456 mono_arch_find_jit_info (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
457 MonoJitInfo
*ji
, MonoContext
*ctx
,
458 MonoContext
*new_ctx
, MonoLMF
**lmf
,
459 mgreg_t
**save_locations
,
460 StackFrameInfo
*frame
)
462 gpointer ip
= (gpointer
) MONO_CONTEXT_GET_IP (ctx
);
463 MonoS390StackFrame
*sframe
;
465 memset (frame
, 0, sizeof (StackFrameInfo
));
473 guint32 unwind_info_len
;
477 frame
->type
= FRAME_TYPE_MANAGED
;
480 unwind_info
= mono_aot_get_unwind_info(ji
, &unwind_info_len
);
482 unwind_info
= mono_get_cached_unwind_info(ji
->used_regs
, &unwind_info_len
);
484 if (*lmf
&& ((*lmf
) != jit_tls
->first_lmf
) &&
485 (MONO_CONTEXT_GET_SP (ctx
) >= (gpointer
)(*lmf
)->ebp
)) {
486 /* remove any unused lmf */
487 *lmf
= (*lmf
)->previous_lmf
;
490 address
= (char *)ip
- (char *)ji
->code_start
;
492 memcpy(®s
, &ctx
->uc_mcontext
.gregs
, sizeof(regs
));
493 mono_unwind_frame (unwind_info
, unwind_info_len
, ji
->code_start
,
494 (guint8
*) ji
->code_start
+ ji
->code_size
,
495 ip
, regs
, 16, save_locations
,
496 MONO_MAX_IREGS
, &cfa
);
497 memcpy (&new_ctx
->uc_mcontext
.gregs
, ®s
, sizeof(regs
));
498 MONO_CONTEXT_SET_IP(new_ctx
, regs
[14] - 2);
499 MONO_CONTEXT_SET_BP(new_ctx
, cfa
);
501 if (*lmf
&& (MONO_CONTEXT_GET_SP (ctx
) >= (gpointer
)(*lmf
)->ebp
)) {
502 /* remove any unused lmf */
503 *lmf
= (*lmf
)->previous_lmf
;
508 ji
= mini_jit_info_table_find (domain
, (gpointer
)(*lmf
)->eip
, NULL
);
513 frame
->method
= (*lmf
)->method
;
517 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
519 memcpy(new_ctx
->uc_mcontext
.gregs
, (*lmf
)->gregs
, sizeof((*lmf
)->gregs
));
520 memcpy(new_ctx
->uc_mcontext
.fpregs
.fprs
, (*lmf
)->fregs
, sizeof((*lmf
)->fregs
));
521 MONO_CONTEXT_SET_BP (new_ctx
, (*lmf
)->ebp
);
522 MONO_CONTEXT_SET_IP (new_ctx
, (*lmf
)->eip
- 2);
523 *lmf
= (*lmf
)->previous_lmf
;
531 /*========================= End of Function ========================*/
533 /*------------------------------------------------------------------*/
535 /* Name - mono_arch_handle_exception */
537 /* Function - Handle an exception raised by the JIT code. */
539 /* Parameters - ctx - Saved processor state */
540 /* obj - The exception object */
542 /*------------------------------------------------------------------*/
545 mono_arch_handle_exception (void *uc
, gpointer obj
)
547 return mono_handle_exception (uc
, obj
);
550 /*========================= End of Function ========================*/
552 /*------------------------------------------------------------------*/
554 /* Name - mono_arch_sigctx_to_monoctx. */
556 /* Function - Called from the signal handler to convert signal */
557 /* context to MonoContext. */
559 /*------------------------------------------------------------------*/
562 mono_arch_sigctx_to_monoctx (void *ctx
, MonoContext
*mctx
)
564 mono_sigctx_to_monoctx(ctx
, mctx
);
567 /*========================= End of Function ========================*/
569 /*------------------------------------------------------------------*/
571 /* Name - mono_arch_monoctx_to_sigctx. */
573 /* Function - Convert MonoContext structure to signal context. */
575 /*------------------------------------------------------------------*/
578 mono_arch_monoctx_to_sigctx (MonoContext
*mctx
, void *ctx
)
580 mono_monoctx_to_sigctx(mctx
, ctx
);
583 /*========================= End of Function ========================*/
585 /*------------------------------------------------------------------*/
587 /* Name - mono_arch_ip_from_context */
589 /* Function - Return the instruction pointer from the context. */
591 /* Parameters - sigctx - Saved processor state */
593 /*------------------------------------------------------------------*/
596 mono_arch_ip_from_context (void *sigctx
)
598 return ((gpointer
) MONO_CONTEXT_GET_IP(((MonoContext
*) sigctx
)));
602 /*========================= End of Function ========================*/
604 /*------------------------------------------------------------------*/
606 /* Name - mono_arch_get_restore_context */
608 /* Function - Return the address of the routine that will rest- */
609 /* ore the context. */
611 /*------------------------------------------------------------------*/
614 mono_arch_get_restore_context (MonoTrampInfo
**info
, gboolean aot
)
623 /*========================= End of Function ========================*/
625 /*------------------------------------------------------------------*/
627 /* Name - mono_arch_is_int_overflow */
629 /* Function - Inspect the code that raised the SIGFPE signal */
630 /* to see if the DivideByZero or Arithmetic exception*/
631 /* should be raised. */
633 /*------------------------------------------------------------------*/
636 mono_arch_is_int_overflow (void *uc
, void *info
)
641 gboolean arithExc
= TRUE
;
646 ctx
= (MonoContext
*) uc
;
647 code
= (guint8
*) ((siginfo_t
*)info
)->si_addr
;
648 /*----------------------------------------------------------*/
649 /* Divide operations are the only ones that will give the */
650 /* divide by zero exception so just check for these ops. */
651 /*----------------------------------------------------------*/
653 case 0x1d : /* Divide Register */
654 regNo
= code
[1] & 0x0f;
655 if (ctx
->uc_mcontext
.gregs
[regNo
] == 0)
658 case 0x5d : /* Divide */
659 regNo
= (code
[2] & 0xf0 >> 8);
660 idxNo
= (code
[1] & 0x0f);
661 offset
= *((guint16
*) code
+2) & 0x0fff;
662 operand
= (guint64
*)(ctx
->uc_mcontext
.gregs
[regNo
] + offset
);
664 operand
+= ctx
->uc_mcontext
.gregs
[idxNo
];
668 case 0xb9 : /* DL[GR] or DS[GR] */
669 if ((code
[1] == 0x97) || (code
[1] == 0x87) ||
670 (code
[1] == 0x0d) || (code
[1] == 0x1d)) {
671 regNo
= (code
[3] & 0x0f);
672 if (ctx
->uc_mcontext
.gregs
[regNo
] == 0)
676 case 0xe3 : /* DL[G] | DS[G] */
677 if ((code
[5] == 0x97) || (code
[5] == 0x87) ||
678 (code
[5] == 0x0d) || (code
[5] == 0x1d)) {
679 regNo
= (code
[2] & 0xf0 >> 8);
680 idxNo
= (code
[1] & 0x0f);
681 offset
= (code
[2] & 0x0f << 8) +
682 code
[3] + (code
[4] << 12);
683 operand
= (guint64
*)(ctx
->uc_mcontext
.gregs
[regNo
] + offset
);
685 operand
+= ctx
->uc_mcontext
.gregs
[idxNo
];
693 ctx
->uc_mcontext
.psw
.addr
= (guint64
)code
;
697 /*========================= End of Function ========================*/