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)))
38 /*========================= End of Defines =========================*/
40 /*------------------------------------------------------------------*/
42 /*------------------------------------------------------------------*/
50 #include <mono/arch/s390x/s390x-codegen.h>
51 #include <mono/metadata/appdomain.h>
52 #include <mono/metadata/tabledefs.h>
53 #include <mono/metadata/threads.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/exception.h>
56 #include <mono/metadata/mono-debug.h>
59 #include "mini-s390x.h"
61 /*========================= End of Includes ========================*/
63 /*------------------------------------------------------------------*/
64 /* P r o t o t y p e s */
65 /*------------------------------------------------------------------*/
67 gboolean mono_arch_handle_exception (void *ctx,
71 /*========================= End of Prototypes ======================*/
73 /*------------------------------------------------------------------*/
74 /* G l o b a l V a r i a b l e s */
75 /*------------------------------------------------------------------*/
83 /*====================== End of Global Variables ===================*/
85 /*------------------------------------------------------------------*/
87 /* Name - mono_arch_has_unwind_info */
89 /* Function - Tests if a function has a DWARF exception table */
90 /* that is able to restore all caller saved registers*/
92 /*------------------------------------------------------------------*/
95 mono_arch_has_unwind_info (gconstpointer addr)
100 /*========================= End of Function ========================*/
102 /*------------------------------------------------------------------*/
104 /* Name - mono_arch_get_call_filter */
106 /* Function - Return a pointer to a method which calls an */
107 /* exception filter. We also use this function to */
108 /* call finally handlers (we pass NULL as @exc */
109 /* object in this case). */
111 /*------------------------------------------------------------------*/
114 mono_arch_get_call_filter (void)
116 static guint8 *start;
117 static int inited = 0;
119 int alloc_size, pos, i;
125 /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
126 code = start = mono_global_codeman_reserve (512);
128 s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
129 s390_lgr (code, s390_r14, STK_BASE);
130 alloc_size = S390_ALIGN(S390_CALLFILTER_SIZE, S390_STACK_ALIGNMENT);
131 s390_aghi (code, STK_BASE, -alloc_size);
132 s390_stg (code, s390_r14, 0, STK_BASE, 0);
134 /*------------------------------------------------------*/
135 /* save general registers on stack */
136 /*------------------------------------------------------*/
137 s390_stmg (code, s390_r0, STK_BASE, STK_BASE, S390_CALLFILTER_INTREGS);
139 /*------------------------------------------------------*/
140 /* save floating point registers on stack */
141 /*------------------------------------------------------*/
142 pos = S390_CALLFILTER_FLTREGS;
143 for (i = 0; i < 16; ++i) {
144 s390_std (code, i, 0, STK_BASE, pos);
145 pos += sizeof (gdouble);
148 /*------------------------------------------------------*/
149 /* save access registers on stack */
150 /*------------------------------------------------------*/
151 s390_stam (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
153 /*------------------------------------------------------*/
155 /*------------------------------------------------------*/
156 s390_lgr (code, s390_r13, s390_r2);
158 /*------------------------------------------------------*/
159 /* Get A(Handler Entry Point) */
160 /*------------------------------------------------------*/
161 s390_lgr (code, s390_r0, s390_r3);
163 /*------------------------------------------------------*/
164 /* Set parameter register with Exception */
165 /*------------------------------------------------------*/
166 s390_lgr (code, s390_r2, s390_r4);
168 /*------------------------------------------------------*/
169 /* Load all registers with values from the context */
170 /*------------------------------------------------------*/
171 s390_lmg (code, s390_r3, s390_r12, s390_r13,
172 G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs[3]));
173 pos = G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs[0]);
174 for (i = 0; i < 16; ++i) {
175 s390_ld (code, i, 0, s390_r13, pos);
176 pos += sizeof(gdouble);
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);
190 /*------------------------------------------------------*/
191 /* Restore all the regs from the stack */
192 /*------------------------------------------------------*/
193 s390_lmg (code, s390_r0, s390_r13, STK_BASE, S390_CALLFILTER_INTREGS);
194 pos = S390_CALLFILTER_FLTREGS;
195 for (i = 0; i < 16; ++i) {
196 s390_ld (code, i, 0, STK_BASE, pos);
197 pos += sizeof (gdouble);
200 s390_lgr (code, s390_r2, s390_r14);
201 s390_lam (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
202 s390_aghi (code, s390_r15, alloc_size);
203 s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
204 s390_br (code, s390_r14);
206 g_assert ((code - start) < SZ_THROW);
210 /*========================= End of Function ========================*/
212 /*------------------------------------------------------------------*/
214 /* Name - throw_exception. */
216 /* Function - Raise an exception based on the parameters passed.*/
218 /*------------------------------------------------------------------*/
221 throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp,
222 gulong *int_regs, gdouble *fp_regs, gint32 *acc_regs,
223 guint fpc, gboolean rethrow)
227 static void (*restore_context) (MonoContext *);
229 if (!restore_context)
230 restore_context = mono_arch_get_restore_context();
232 memset(&ctx, 0, sizeof(ctx));
236 /* adjust eip so that it point into the call instruction */
239 for (iReg = 0; iReg < 16; iReg++) {
240 ctx.uc_mcontext.gregs[iReg] = int_regs[iReg];
241 ctx.uc_mcontext.fpregs.fprs[iReg].d = fp_regs[iReg];
242 ctx.uc_mcontext.aregs[iReg] = acc_regs[iReg];
245 ctx.uc_mcontext.fpregs.fpc = fpc;
247 MONO_CONTEXT_SET_BP (&ctx, sp);
248 MONO_CONTEXT_SET_IP (&ctx, ip);
250 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
251 MonoException *mono_ex = (MonoException*)exc;
253 mono_ex->stack_trace = NULL;
255 mono_arch_handle_exception (&ctx, exc, FALSE);
256 restore_context(&ctx);
258 g_assert_not_reached ();
261 /*========================= End of Function ========================*/
263 /*------------------------------------------------------------------*/
265 /* Name - get_throw_exception_generic */
267 /* Function - Return a function pointer which can be used to */
268 /* raise exceptions. The returned function has the */
269 /* following signature: */
270 /* void (*func) (MonoException *exc); or, */
271 /* void (*func) (char *exc_name); */
273 /*------------------------------------------------------------------*/
276 get_throw_exception_generic (guint8 *start, int size,
277 throwType type, gboolean rethrow)
280 int alloc_size, pos, i;
284 s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
285 alloc_size = S390_ALIGN(S390_THROWSTACK_SIZE, S390_STACK_ALIGNMENT);
286 s390_lgr (code, s390_r14, STK_BASE);
287 s390_aghi (code, STK_BASE, -alloc_size);
288 s390_stg (code, s390_r14, 0, STK_BASE, 0);
291 s390_lgr (code, s390_r4, s390_r2);
292 s390_lg (code, s390_r3, 0, s390_r2, G_STRUCT_OFFSET(MonoException, object));
293 s390_basr (code, s390_r13, 0);
295 s390_llong(code, mono_defaults.corlib);
296 s390_llong(code, mono_exception_from_name);
297 s390_lg (code, s390_r3, 0, s390_r3, G_STRUCT_OFFSET(MonoVTable, klass));
298 s390_lg (code, s390_r2, 0, s390_r13, 4);
299 s390_lg (code, s390_r1, 0, s390_r13, 12);
300 s390_lg (code, s390_r4, 0, s390_r3, G_STRUCT_OFFSET(MonoClass, name));
301 s390_lg (code, s390_r3, 0, s390_r3, G_STRUCT_OFFSET(MonoClass, name_space));
302 s390_basr (code, s390_r14, s390_r1);
305 s390_lgr (code, s390_r3, s390_r2);
306 s390_basr (code, s390_r13, 0);
308 s390_llong(code, mono_defaults.exception_class->image);
309 s390_llong(code, mono_exception_from_token);
310 s390_lg (code, s390_r2, 0, s390_r13, 4);
311 s390_lg (code, s390_r1, 0, s390_r13, 12);
312 s390_basr (code, s390_r14, s390_r1);
317 /*------------------------------------------------------*/
318 /* save the general registers on the stack */
319 /*------------------------------------------------------*/
320 s390_stmg (code, s390_r0, s390_r13, STK_BASE, S390_THROWSTACK_INTREGS);
322 s390_lgr (code, s390_r1, STK_BASE);
323 s390_aghi (code, s390_r1, alloc_size);
324 /*------------------------------------------------------*/
325 /* save the return address in the parameter register */
326 /*------------------------------------------------------*/
327 s390_lg (code, s390_r3, 0, s390_r1, S390_RET_ADDR_OFFSET);
329 /*------------------------------------------------------*/
330 /* save the floating point registers */
331 /*------------------------------------------------------*/
332 pos = S390_THROWSTACK_FLTREGS;
333 for (i = 0; i < 16; ++i) {
334 s390_std (code, i, 0, STK_BASE, pos);
335 pos += sizeof (gdouble);
337 /*------------------------------------------------------*/
338 /* save the access registers */
339 /*------------------------------------------------------*/
340 s390_stam (code, s390_r0, s390_r15, STK_BASE, S390_THROWSTACK_ACCREGS);
342 /*------------------------------------------------------*/
343 /* call throw_exception (tkn, ip, sp, gr, fr, ar, re) */
344 /* - r2 already contains *exc */
345 /*------------------------------------------------------*/
346 s390_lgr (code, s390_r4, s390_r1); /* caller sp */
348 /*------------------------------------------------------*/
349 /* pointer to the saved int regs */
350 /*------------------------------------------------------*/
351 s390_la (code, s390_r5, 0, STK_BASE, S390_THROWSTACK_INTREGS);
352 s390_la (code, s390_r6, 0, STK_BASE, S390_THROWSTACK_FLTREGS);
353 s390_la (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCREGS);
354 s390_stg (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCPRM);
355 s390_stfpc(code, STK_BASE, S390_THROWSTACK_FPCPRM+4);
356 s390_lghi (code, s390_r7, rethrow);
357 s390_stg (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_RETHROW);
358 s390_basr (code, s390_r13, 0);
360 s390_llong(code, throw_exception);
361 s390_lg (code, s390_r1, 0, s390_r13, 4);
362 s390_basr (code, s390_r14, s390_r1);
363 /* we should never reach this breakpoint */
365 g_assert ((code - start) < size);
369 /*========================= End of Function ========================*/
371 /*------------------------------------------------------------------*/
373 /* Name - arch_get_throw_exception */
375 /* Function - Return a function pointer which can be used to */
376 /* raise exceptions. The returned function has the */
377 /* following signature: */
378 /* void (*func) (MonoException *exc); */
380 /*------------------------------------------------------------------*/
383 mono_arch_get_throw_exception (void)
385 static guint8 *start;
386 static int inited = 0;
390 start = mono_global_codeman_reserve (SZ_THROW);
391 get_throw_exception_generic (start, SZ_THROW, by_none, FALSE);
396 /*========================= End of Function ========================*/
398 /*------------------------------------------------------------------*/
400 /* Name - arch_get_rethrow_exception */
402 /* Function - Return a function pointer which can be used to */
403 /* raise exceptions. The returned function has the */
404 /* following signature: */
405 /* void (*func) (MonoException *exc); */
407 /*------------------------------------------------------------------*/
410 mono_arch_get_rethrow_exception (void)
412 static guint8 *start;
413 static int inited = 0;
417 start = mono_global_codeman_reserve (SZ_THROW);
418 get_throw_exception_generic (start, SZ_THROW, FALSE, TRUE);
423 /*========================= End of Function ========================*/
425 /*------------------------------------------------------------------*/
427 /* Name - arch_get_corlib_exception */
429 /* Function - Return a function pointer which can be used to */
430 /* raise corlib exceptions. The return function has */
431 /* the following signature: */
432 /* void (*func) (guint32 token, guint32 offset) */
434 /*------------------------------------------------------------------*/
437 mono_arch_get_throw_corlib_exception(void)
439 static guint8 *start;
440 static int inited = 0;
444 start = mono_global_codeman_reserve (SZ_THROW);
445 get_throw_exception_generic (start, SZ_THROW, by_token, FALSE);
450 /*========================= End of Function ========================*/
452 /*------------------------------------------------------------------*/
454 /* Name - arch_get_throw_exception_by_name */
456 /* Function - Return a function pointer which can be used to */
457 /* raise corlib exceptions. The return function has */
458 /* the following signature: */
459 /* void (*func) (char *exc_name); */
461 /*------------------------------------------------------------------*/
464 mono_arch_get_throw_exception_by_name (void)
466 static guint8 *start;
467 static int inited = 0;
471 start = mono_global_codeman_reserve (SZ_THROW);
472 get_throw_exception_generic (start, SZ_THROW, by_name, FALSE);
477 /*========================= End of Function ========================*/
479 /*------------------------------------------------------------------*/
481 /* Name - mono_arch_find_jit_info */
483 /* Function - This function is used to gather information from */
484 /* @ctx. It returns the MonoJitInfo of the corres- */
485 /* ponding function, unwinds one stack frame and */
486 /* stores the resulting context into @new_ctx. It */
487 /* also stores a string describing the stack location*/
488 /* into @trace (if not NULL), and modifies the @lmf */
489 /* if necessary. @native_offset returns the IP off- */
490 /* set from the start of the function or -1 if that */
491 /* information is not available. */
493 /*------------------------------------------------------------------*/
496 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
497 MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
498 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
501 gpointer ip = (gpointer) MONO_CONTEXT_GET_IP (ctx);
502 MonoS390StackFrame *sframe;
505 (ip >= prev_ji->code_start &&
506 ((guint8 *) ip <= ((guint8 *) prev_ji->code_start) + prev_ji->code_size)))
509 ji = mini_jit_info_table_find (domain, ip, NULL);
519 if (*lmf && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->ebp)) {
520 /* remove any unused lmf */
521 *lmf = (*lmf)->previous_lmf;
524 address = (char *)ip - (char *)ji->code_start;
527 if (!ji->method->wrapper_type)
530 sframe = (MonoS390StackFrame *) MONO_CONTEXT_GET_SP (ctx);
531 MONO_CONTEXT_SET_BP (new_ctx, sframe->prev);
532 sframe = (MonoS390StackFrame *) sframe->prev;
533 MONO_CONTEXT_SET_IP (new_ctx, sframe->return_address);
534 memcpy (&new_ctx->uc_mcontext.gregs[6], sframe->regs, (8*sizeof(gint64)));
544 if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) {
546 memset (res, 0, MONO_SIZEOF_JIT_INFO);
547 res->method = (*lmf)->method;
550 memcpy(new_ctx->uc_mcontext.gregs, (*lmf)->gregs, sizeof((*lmf)->gregs));
551 memcpy(new_ctx->uc_mcontext.fpregs.fprs, (*lmf)->fregs, sizeof((*lmf)->fregs));
553 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
554 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
555 *lmf = (*lmf)->previous_lmf;
557 return ji ? ji : res;
563 /*========================= End of Function ========================*/
565 /*------------------------------------------------------------------*/
567 /* Name - mono_arch_handle_exception */
569 /* Function - Handle an exception raised by the JIT code. */
571 /* Parameters - ctx - Saved processor state */
572 /* obj - The exception object */
573 /* test_only - Only test if the exception is caught, */
574 /* but don't call handlers */
576 /*------------------------------------------------------------------*/
579 mono_arch_handle_exception (void *uc, gpointer obj, gboolean test_only)
581 return mono_handle_exception (uc, obj, mono_arch_ip_from_context(uc), test_only);
584 /*========================= End of Function ========================*/
586 /*------------------------------------------------------------------*/
588 /* Name - mono_arch_ip_from_context */
590 /* Function - Return the instruction pointer from the context. */
592 /* Parameters - sigctx - Saved processor state */
594 /*------------------------------------------------------------------*/
597 mono_arch_ip_from_context (void *sigctx)
599 return ((gpointer) MONO_CONTEXT_GET_IP(((MonoContext *) sigctx)));
603 /*========================= End of Function ========================*/
605 /*------------------------------------------------------------------*/
607 /* Name - mono_arch_get_restore_context */
609 /* Function - Return the address of the routine that will rest- */
610 /* ore the context. */
612 /*------------------------------------------------------------------*/
615 mono_arch_get_restore_context ()
621 /*========================= End of Function ========================*/
623 /*------------------------------------------------------------------*/
625 /* Name - mono_arch_is_int_overflow */
627 /* Function - Inspect the code that raised the SIGFPE signal */
628 /* to see if the DivideByZero or Arithmetic exception*/
629 /* should be raised. */
631 /*------------------------------------------------------------------*/
634 mono_arch_is_int_overflow (void *uc, void *info)
639 gboolean arithExc = TRUE;
644 ctx = (MonoContext *) uc;
645 code = (guint8 *) ((siginfo_t *)info)->si_addr;
646 /*----------------------------------------------------------*/
647 /* Divide operations are the only ones that will give the */
648 /* divide by zero exception so just check for these ops. */
649 /*----------------------------------------------------------*/
651 case 0x1d : /* Divide Register */
652 regNo = code[1] & 0x0f;
653 if (ctx->uc_mcontext.gregs[regNo] == 0)
656 case 0x5d : /* Divide */
657 regNo = (code[2] & 0xf0 >> 8);
658 idxNo = (code[1] & 0x0f);
659 offset = *((guint16 *) code+2) & 0x0fff;
660 operand = (guint64*)(ctx->uc_mcontext.gregs[regNo] + offset);
662 operand += ctx->uc_mcontext.gregs[idxNo];
666 case 0xb9 : /* DL[GR] or DS[GR] */
667 if ((code[1] == 0x97) || (code[1] == 0x87) ||
668 (code[1] == 0x0d) || (code[1] == 0x1d)) {
669 regNo = (code[3] & 0x0f);
670 if (ctx->uc_mcontext.gregs[regNo] == 0)
674 case 0xe3 : /* DL[G] | DS[G] */
675 if ((code[5] == 0x97) || (code[5] == 0x87) ||
676 (code[5] == 0x0d) || (code[5] == 0x1d)) {
677 regNo = (code[2] & 0xf0 >> 8);
678 idxNo = (code[1] & 0x0f);
679 offset = (code[2] & 0x0f << 8) +
680 code[3] + (code[4] << 12);
681 operand = (guint64*)(ctx->uc_mcontext.gregs[regNo] + offset);
683 operand += ctx->uc_mcontext.gregs[idxNo];
691 ctx->uc_mcontext.psw.addr = (guint64)code;
695 /*========================= End of Function ========================*/