update readme (#21797)
[mono-project.git] / mono / mini / exceptions-s390x.c
blob096a585a5b3e8e62e1febd594b88a6432f5168b9
1 /**
2 * \file
4 * Function - Exception support for S/390.
6 * Name - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
8 * Date - January, 2004
10 * Derivation - From exceptions-x86 & exceptions-ppc
11 * Paolo Molaro (lupus@ximian.com)
12 * Dietmar Maurer (dietmar@ximian.com)
14 * Copyright - 2001 Ximian, Inc.
15 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 /*------------------------------------------------------------------*/
20 /* D e f i n e s */
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 // 160
29 #define S390_THROWSTACK_FPCPRM (S390_THROWSTACK_ACCPRM+sizeof(gpointer)) // 168
30 #define S390_THROWSTACK_RETHROW (S390_THROWSTACK_FPCPRM+sizeof(gulong)) // 170
31 #define S390_THROWSTACK_PRESERVE_IPS (S390_THROWSTACK_RETHROW+sizeof(gulong)) // 178
32 #define S390_THROWSTACK_INTREGS (S390_THROWSTACK_PRESERVE_IPS+sizeof(gulong)) // 180
33 #define S390_THROWSTACK_FLTREGS (S390_THROWSTACK_INTREGS+(16*sizeof(gulong))) // 308
34 #define S390_THROWSTACK_ACCREGS (S390_THROWSTACK_FLTREGS+(16*sizeof(gdouble))) // 430
35 #define S390_THROWSTACK_SIZE (S390_THROWSTACK_ACCREGS+(16*sizeof(gint32))) // 494
37 #define SZ_THROW 384
39 #define setup_context(ctx)
41 /*========================= End of Defines =========================*/
43 /*------------------------------------------------------------------*/
44 /* I n c l u d e s */
45 /*------------------------------------------------------------------*/
47 #include <config.h>
48 #include <glib.h>
49 #include <signal.h>
50 #include <string.h>
51 #include <ucontext.h>
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 #include <mono/utils/mono-hwcap.h>
61 #include <mono/utils/mono-state.h>
63 #include "mini.h"
64 #include "mini-s390x.h"
65 #include "mini-runtime.h"
66 #include "aot-runtime.h"
67 #include "mono/utils/mono-tls-inline.h"
69 /*========================= End of Includes ========================*/
71 /*------------------------------------------------------------------*/
72 /* P r o t o t y p e s */
73 /*------------------------------------------------------------------*/
75 static void throw_exception (MonoObject *, unsigned long, unsigned long,
76 host_mgreg_t *, gdouble *, gint32 *, guint, gboolean, gboolean);
77 static gpointer mono_arch_get_throw_exception_generic (int, MonoTrampInfo **,
78 int, gboolean, gboolean, gboolean);
79 static void handle_signal_exception (gpointer);
81 /*========================= End of Prototypes ======================*/
83 /*------------------------------------------------------------------*/
84 /* G l o b a l V a r i a b l e s */
85 /*------------------------------------------------------------------*/
87 typedef enum {
88 by_none,
89 by_token
90 } throwType;
92 /*====================== End of Global Variables ===================*/
94 /*------------------------------------------------------------------*/
95 /* */
96 /* Name - mono_arch_get_call_filter */
97 /* */
98 /* Function - Return a pointer to a method which calls an */
99 /* exception filter. We also use this function to */
100 /* call finally handlers (we pass NULL as @exc */
101 /* object in this case). */
102 /* */
103 /*------------------------------------------------------------------*/
105 gpointer
106 mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
108 static guint8 *start;
109 static int inited = 0;
110 guint8 *code;
111 int gr_offset, alloc_size, pos, i;
112 GSList *unwind_ops = NULL;
113 MonoJumpInfo *ji = NULL;
115 g_assert (!aot);
117 if (inited)
118 return start;
120 inited = 1;
121 /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
122 code = start = (guint8 *) mono_global_codeman_reserve (512);
124 mono_add_unwind_op_def_cfa (unwind_ops, code, start, STK_BASE, S390_CFA_OFFSET);
125 s390_stmg (code, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET);
126 gr_offset = S390_REG_SAVE_OFFSET - S390_CFA_OFFSET;
127 for (i = s390_r6; i <= s390_r15; i++) {
128 mono_add_unwind_op_offset (unwind_ops, code, start, i, gr_offset);
129 gr_offset += sizeof(uintptr_t);
131 s390_lgr (code, s390_r14, STK_BASE);
132 alloc_size = S390_ALIGN(S390_CALLFILTER_SIZE, S390_STACK_ALIGNMENT);
133 s390_aghi (code, STK_BASE, -alloc_size);
134 mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, alloc_size + S390_CFA_OFFSET);
135 s390_stg (code, s390_r14, 0, STK_BASE, 0);
137 /*------------------------------------------------------*/
138 /* save general registers on stack */
139 /*------------------------------------------------------*/
140 s390_stmg (code, s390_r0, STK_BASE, STK_BASE, S390_CALLFILTER_INTREGS);
142 /*------------------------------------------------------*/
143 /* save floating point registers on stack */
144 /*------------------------------------------------------*/
145 pos = S390_CALLFILTER_FLTREGS;
146 for (i = 0; i < 16; ++i) {
147 s390_std (code, i, 0, STK_BASE, pos);
148 pos += sizeof (gdouble);
151 /*------------------------------------------------------*/
152 /* save access registers on stack */
153 /*------------------------------------------------------*/
154 s390_stam (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
156 /*------------------------------------------------------*/
157 /* Get A(Context) */
158 /*------------------------------------------------------*/
159 s390_lgr (code, s390_r13, s390_r2);
161 /*------------------------------------------------------*/
162 /* Get A(Handler Entry Point) */
163 /*------------------------------------------------------*/
164 s390_lgr (code, s390_r0, s390_r3);
166 /*------------------------------------------------------*/
167 /* Set parameter register with Exception */
168 /*------------------------------------------------------*/
169 s390_lgr (code, s390_r2, s390_r4);
171 /*------------------------------------------------------*/
172 /* Load all registers with values from the context */
173 /*------------------------------------------------------*/
174 s390_lmg (code, s390_r3, s390_r12, s390_r13,
175 G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs[3]));
176 pos = G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs[0]);
177 for (i = 0; i < 16; ++i) {
178 s390_ld (code, i, 0, s390_r13, pos);
179 pos += sizeof(gdouble);
182 #if 0
183 /*------------------------------------------------------*/
184 /* We need to preserve current SP before calling filter */
185 /* with SP from the context */
186 /*------------------------------------------------------*/
187 s390_lgr (code, s390_r14, STK_BASE);
188 s390_lg (code, STK_BASE, 0, s390_r13,
189 G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs[15]));
190 s390_lgr (code, s390_r13, s390_r14);
191 #endif
193 /*------------------------------------------------------*/
194 /* Go call filter */
195 /*------------------------------------------------------*/
196 s390_lgr (code, s390_r1, s390_r0);
197 s390_basr (code, s390_r14, s390_r1);
199 /*------------------------------------------------------*/
200 /* Save return value */
201 /*------------------------------------------------------*/
202 s390_lgr (code, s390_r14, s390_r2);
204 #if 0
205 /*------------------------------------------------------*/
206 /* Reload our stack register with value saved in context*/
207 /*------------------------------------------------------*/
208 s390_lgr (code, STK_BASE, s390_r13);
209 #endif
211 /*------------------------------------------------------*/
212 /* Restore all the regs from the stack */
213 /*------------------------------------------------------*/
214 s390_lmg (code, s390_r0, s390_r13, STK_BASE, S390_CALLFILTER_INTREGS);
215 pos = S390_CALLFILTER_FLTREGS;
216 for (i = 0; i < 16; ++i) {
217 s390_ld (code, i, 0, STK_BASE, pos);
218 pos += sizeof (gdouble);
221 s390_lgr (code, s390_r2, s390_r14);
222 s390_lam (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
223 s390_aghi (code, s390_r15, alloc_size);
224 s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
225 s390_br (code, s390_r14);
227 g_assert ((code - start) < SZ_THROW);
229 mono_arch_flush_icache(start, code - start);
230 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL));
232 if (info)
233 *info = mono_tramp_info_create ("call_filter",
234 start, code - start, ji,
235 unwind_ops);
237 return start;
240 /*========================= End of Function ========================*/
242 /*------------------------------------------------------------------*/
243 /* */
244 /* Name - throw_exception. */
245 /* */
246 /* Function - Raise an exception based on the parameters passed.*/
247 /* */
248 /*------------------------------------------------------------------*/
250 static void
251 throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp,
252 host_mgreg_t *int_regs, gdouble *fp_regs, gint32 *acc_regs,
253 guint fpc, gboolean rethrow, gboolean preserve_ips)
255 ERROR_DECL (error);
256 MonoContext ctx;
257 int iReg;
259 memset(&ctx, 0, sizeof(ctx));
261 setup_context(&ctx);
263 /* adjust eip so that it point into the call instruction */
264 ip -= 2;
266 for (iReg = 0; iReg < 16; iReg++) {
267 ctx.uc_mcontext.gregs[iReg] = int_regs[iReg];
268 ctx.uc_mcontext.fpregs.fprs[iReg].d = fp_regs[iReg];
269 ctx.uc_mcontext.aregs[iReg] = acc_regs[iReg];
272 ctx.uc_mcontext.fpregs.fpc = fpc;
274 MONO_CONTEXT_SET_BP (&ctx, sp);
275 MONO_CONTEXT_SET_IP (&ctx, ip);
277 if (mono_object_isinst_checked (exc, mono_defaults.exception_class, error)) {
278 MonoException *mono_ex = (MonoException*)exc;
279 if (!rethrow && !mono_ex->caught_in_unmanaged) {
280 mono_ex->stack_trace = NULL;
281 mono_ex->trace_ips = NULL;
282 } else if (preserve_ips) {
283 mono_ex->caught_in_unmanaged = TRUE;
286 mono_error_assert_ok (error);
287 // mono_arch_handle_exception (&ctx, exc, FALSE);
288 mono_handle_exception (&ctx, exc);
289 mono_restore_context(&ctx);
291 g_assert_not_reached ();
294 /*========================= End of Function ========================*/
296 /*------------------------------------------------------------------*/
297 /* */
298 /* Name - get_throw_exception_generic */
299 /* */
300 /* Function - Return a function pointer which can be used to */
301 /* raise exceptions. The returned function has the */
302 /* following signature: */
303 /* void (*func) (MonoException *exc); or, */
304 /* void (*func) (char *exc_name); */
305 /* */
306 /*------------------------------------------------------------------*/
308 static gpointer
309 mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, int corlib,
310 gboolean rethrow, gboolean aot, gboolean preserve_ips)
312 guint8 *code, *start;
313 int gr_offset, alloc_size, pos, i;
314 MonoJumpInfo *ji = NULL;
315 GSList *unwind_ops = NULL;
317 code = start = (guint8 *) mono_global_codeman_reserve(size);
319 mono_add_unwind_op_def_cfa (unwind_ops, code, start, STK_BASE, S390_CFA_OFFSET);
320 s390_stmg (code, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET);
321 gr_offset = S390_REG_SAVE_OFFSET - S390_CFA_OFFSET;
322 for (i = s390_r6; i <= s390_r15; i++) {
323 mono_add_unwind_op_offset (unwind_ops, code, start, i, gr_offset);
324 gr_offset += sizeof(uintptr_t);
326 alloc_size = S390_ALIGN(S390_THROWSTACK_SIZE, S390_STACK_ALIGNMENT);
327 s390_lgr (code, s390_r14, STK_BASE);
328 s390_aghi (code, STK_BASE, -alloc_size);
329 mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, alloc_size + S390_CFA_OFFSET);
330 s390_stg (code, s390_r14, 0, STK_BASE, 0);
331 s390_lgr (code, s390_r3, s390_r2);
332 if (corlib) {
333 S390_SET (code, s390_r1, (guint8 *)mono_exception_from_token);
334 S390_SET (code, s390_r2, (guint8 *)m_class_get_image (mono_defaults.exception_class));
335 s390_basr (code, s390_r14, s390_r1);
338 /*------------------------------------------------------*/
339 /* save the general registers on the stack */
340 /*------------------------------------------------------*/
341 s390_stmg (code, s390_r0, s390_r13, STK_BASE, S390_THROWSTACK_INTREGS);
343 s390_lgr (code, s390_r1, STK_BASE);
344 s390_aghi (code, s390_r1, alloc_size);
345 /*------------------------------------------------------*/
346 /* save the return address in the parameter register */
347 /*------------------------------------------------------*/
348 s390_lg (code, s390_r3, 0, s390_r1, S390_RET_ADDR_OFFSET);
350 /*------------------------------------------------------*/
351 /* save the floating point registers */
352 /*------------------------------------------------------*/
353 pos = S390_THROWSTACK_FLTREGS;
354 for (i = 0; i < 16; ++i) {
355 s390_std (code, i, 0, STK_BASE, pos);
356 pos += sizeof (gdouble);
359 /*------------------------------------------------------*/
360 /* save the access registers */
361 /*------------------------------------------------------*/
362 s390_stam (code, s390_r0, s390_r15, STK_BASE, S390_THROWSTACK_ACCREGS);
364 /*------------------------------------------------------*/
365 /* call throw_exception (tkn, ip, sp, gr, fr, ar, re) */
366 /* - r2 already contains *exc */
367 /*------------------------------------------------------*/
368 s390_lgr (code, s390_r4, s390_r1); /* caller sp */
370 /*------------------------------------------------------*/
371 /* pointer to the saved int regs */
372 /*------------------------------------------------------*/
373 s390_la (code, s390_r5, 0, STK_BASE, S390_THROWSTACK_INTREGS);
374 s390_la (code, s390_r6, 0, STK_BASE, S390_THROWSTACK_FLTREGS);
375 s390_la (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCREGS);
376 s390_stg (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCPRM);
377 s390_stfpc(code, STK_BASE, S390_THROWSTACK_FPCPRM+4);
378 S390_SET (code, s390_r1, (guint8 *)throw_exception);
379 s390_lghi (code, s390_r7, rethrow);
380 s390_stg (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_RETHROW);
381 s390_lghi (code, s390_r7, preserve_ips);
382 s390_stg (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_PRESERVE_IPS);
383 s390_basr (code, s390_r14, s390_r1);
384 /* we should never reach this breakpoint */
385 s390_break (code);
386 g_assert ((code - start) < size);
388 mono_arch_flush_icache (start, code - start);
389 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL));
391 if (info)
392 *info = mono_tramp_info_create (corlib ? "throw_corlib_exception"
393 : (rethrow ? "rethrow_exception"
394 : (preserve_ips ? "rethrow_preserve_exception"
395 : "throw_exception")),
396 start, code - start, ji, unwind_ops);
398 return start;
401 /*========================= End of Function ========================*/
403 /*------------------------------------------------------------------*/
404 /* */
405 /* Name - arch_get_throw_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 /*------------------------------------------------------------------*/
414 gpointer
415 mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
417 g_assert (!aot);
418 if (info)
419 *info = NULL;
421 return (mono_arch_get_throw_exception_generic (SZ_THROW, info, FALSE, FALSE, aot, FALSE));
424 /*========================= End of Function ========================*/
426 /*------------------------------------------------------------------*/
427 /* */
428 /* Name - arch_get_rethrow_preserve_exception */
429 /* */
430 /* Function - Return a function pointer which can be used to */
431 /* raise exceptions. This preserves the stored ips. */
432 /* The returned function has the */
433 /* following signature: */
434 /* void (*func) (MonoException *exc); */
435 /* */
436 /*------------------------------------------------------------------*/
438 gpointer
439 mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot)
441 g_assert (!aot);
442 if (info)
443 *info = NULL;
445 return (mono_arch_get_throw_exception_generic (SZ_THROW, info, FALSE, TRUE, aot, TRUE));
448 /*========================= End of Function ========================*/
450 /*------------------------------------------------------------------*/
451 /* */
452 /* Name - arch_get_rethrow_exception */
453 /* */
454 /* Function - Return a function pointer which can be used to */
455 /* raise exceptions. The returned function has the */
456 /* following signature: */
457 /* void (*func) (MonoException *exc); */
458 /* */
459 /*------------------------------------------------------------------*/
461 gpointer
462 mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
464 g_assert (!aot);
465 if (info)
466 *info = NULL;
468 return (mono_arch_get_throw_exception_generic (SZ_THROW, info, FALSE, TRUE, aot, FALSE));
471 /*========================= End of Function ========================*/
473 /*------------------------------------------------------------------*/
474 /* */
475 /* Name - arch_get_corlib_exception */
476 /* */
477 /* Function - Return a function pointer which can be used to */
478 /* raise corlib exceptions. The return function has */
479 /* the following signature: */
480 /* void (*func) (guint32 token, guint32 offset) */
481 /* */
482 /*------------------------------------------------------------------*/
484 gpointer
485 mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
487 g_assert (!aot);
488 if (info)
489 *info = NULL;
491 return (mono_arch_get_throw_exception_generic (SZ_THROW, info, TRUE, FALSE, aot, FALSE));
494 /*========================= End of Function ========================*/
496 /*------------------------------------------------------------------*/
497 /* */
498 /* Name - mono_arch_unwind_frame */
499 /* */
500 /* Function - See exceptions-amd64.c for docs. */
501 /* */
502 /*------------------------------------------------------------------*/
504 gboolean
505 mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
506 MonoJitInfo *ji, MonoContext *ctx,
507 MonoContext *new_ctx, MonoLMF **lmf,
508 host_mgreg_t **save_locations,
509 StackFrameInfo *frame)
511 gpointer ip = (gpointer) MONO_CONTEXT_GET_IP (ctx);
512 guint8 *epilog = NULL;
514 memset (frame, 0, sizeof (StackFrameInfo));
515 frame->ji = ji;
517 *new_ctx = *ctx;
519 if (ji != NULL) {
520 uintptr_t address;
521 guint8 *cfa;
522 guint32 unwind_info_len;
523 guint8 *unwind_info;
524 host_mgreg_t regs[32];
526 if (ji->is_trampoline)
527 frame->type = FRAME_TYPE_TRAMPOLINE;
528 else
529 frame->type = FRAME_TYPE_MANAGED;
531 unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len);
533 address = (char *)ip - (char *)ji->code_start;
535 if (ji->has_arch_eh_info)
536 epilog = (guint8*)ji->code_start + ji->code_size - mono_jinfo_get_epilog_size (ji);
538 memcpy (&regs[0], &ctx->uc_mcontext.gregs, 16 * sizeof(host_mgreg_t));
539 memcpy (&regs[16], &ctx->uc_mcontext.fpregs.fprs, 16 * sizeof(host_mgreg_t));
540 gboolean success = mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start,
541 (guint8 *) ji->code_start + ji->code_size,
542 ip, epilog ? &epilog : NULL, regs, 32, save_locations,
543 MONO_MAX_IREGS, &cfa);
545 if (!success)
546 return FALSE;
548 memcpy (&new_ctx->uc_mcontext.gregs, &regs[0], 16 * sizeof(host_mgreg_t));
549 memcpy (&new_ctx->uc_mcontext.fpregs.fprs, &regs[16], 16 * sizeof(host_mgreg_t));
550 MONO_CONTEXT_SET_IP(new_ctx, regs[14] - 2);
551 MONO_CONTEXT_SET_BP(new_ctx, regs[15]);
552 MONO_CONTEXT_SET_SP(new_ctx, regs[15]);
554 return TRUE;
555 } else if (*lmf) {
557 ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL);
558 if (!ji) {
559 if (!(*lmf)->method)
560 return FALSE;
562 frame->method = (*lmf)->method;
565 frame->ji = ji;
566 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
568 memcpy(new_ctx->uc_mcontext.gregs, (*lmf)->gregs, sizeof((*lmf)->gregs));
569 memcpy(new_ctx->uc_mcontext.fpregs.fprs, (*lmf)->fregs, sizeof((*lmf)->fregs));
570 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
571 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip - 2);
572 *lmf = (struct MonoLMF *) (*lmf)->previous_lmf;
574 return TRUE;
577 return FALSE;
580 /*========================= End of Function ========================*/
582 static void
583 altstack_handle_and_restore (MonoContext *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, gpointer obj, guint32 flags)
585 MonoContext mctx;
586 MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (ctx), NULL);
587 gboolean stack_ovf = (flags & 1) != 0;
588 gboolean nullref = (flags & 2) != 0;
590 if (!ji || (!stack_ovf && !nullref)) {
591 if (mono_dump_start ())
592 mono_handle_native_crash (mono_get_signame (SIGSEGV), ctx, siginfo);
593 /* if couldn't dump or if mono_handle_native_crash returns, abort */
594 abort ();
597 mctx = *ctx;
599 mono_handle_exception (&mctx, obj);
600 if (stack_ovf) {
601 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
602 jit_tls->stack_ovf_pending = 1;
604 mono_restore_context (&mctx);
607 void
608 mono_arch_handle_altstack_exception (void *sigctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, gpointer fault_addr, gboolean stack_ovf)
610 #ifdef MONO_ARCH_USE_SIGACTION
611 MonoContext *uc = (MonoContext *) sigctx;
612 MonoContext *uc_copy;
613 MonoException *exc = NULL;
614 MonoJitTlsData *jit_tls = NULL;
615 gboolean nullref = TRUE;
616 uintptr_t sp;
618 jit_tls = mono_tls_get_jit_tls();
619 g_assert (jit_tls);
621 /* use TLS as temporary storage as we want to avoid
622 * (1) stack allocation on the application stack
623 * (2) calling malloc, because it is not async-safe
624 * (3) using a global storage, because this function is not reentrant
626 * tls->orig_ex_ctx is used by the stack walker, which shouldn't be running at this point.
628 uc_copy = &jit_tls->orig_ex_ctx;
630 if (!mono_is_addr_implicit_null_check (fault_addr))
631 nullref = FALSE;
633 if (stack_ovf)
634 exc = mono_domain_get ()->stack_overflow_ex;
637 * Setup the call frame on the application stack so that control is
638 * returned there and exception handling can continue. we want the call
639 * frame to be minimal as possible, for example no argument passing that
640 * requires allocation on the stack, as this wouldn't be encoded in unwind
641 * information for the caller frame.
643 sp = (uintptr_t) (UCONTEXT_REG_Rn(uc, 15));
644 sp = sp - S390_MINIMAL_STACK_SIZE;
646 mono_sigctx_to_monoctx (uc, uc_copy);
647 g_assert ((uintptr_t) mono_arch_ip_from_context (uc) == (uintptr_t) UCONTEXT_IP (uc_copy));
649 /* At the return form the signal handler execution starts in altstack_handle_and_restore() */
650 UCONTEXT_REG_Rn(uc, 14) = (uintptr_t) UCONTEXT_IP(uc);
651 UCONTEXT_IP(uc) = (uintptr_t) altstack_handle_and_restore;
652 UCONTEXT_REG_Rn(uc, 1) = (uintptr_t) sp;
653 UCONTEXT_REG_Rn(uc, S390_FIRST_ARG_REG) = (uintptr_t) uc_copy;
654 UCONTEXT_REG_Rn(uc, S390_FIRST_ARG_REG + 1) = (uintptr_t) siginfo;
655 UCONTEXT_REG_Rn(uc, S390_FIRST_ARG_REG + 2) = (uintptr_t) exc;
656 UCONTEXT_REG_Rn(uc, S390_FIRST_ARG_REG + 3) = (stack_ovf ? 1 : 0) | (nullref ? 2 : 0);
657 #endif
660 /*========================= End of Function ========================*/
662 /*------------------------------------------------------------------*/
663 /* */
664 /* Name - handle_signal_exception */
665 /* */
666 /* Function - Handle an exception raised by the JIT code. */
667 /* */
668 /* Parameters - obj - The exception object */
669 /* */
670 /*------------------------------------------------------------------*/
672 static void
673 handle_signal_exception (gpointer obj)
675 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
676 MonoContext ctx;
678 memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));
679 mono_handle_exception (&ctx, obj);
680 mono_restore_context (&ctx);
683 /*========================= End of Function ========================*/
685 /*------------------------------------------------------------------*/
686 /* */
687 /* Name - mono_arch_handle_exception */
688 /* */
689 /* Function - Handle an exception raised by the JIT code. */
690 /* */
691 /* Parameters - ctx - Saved processor state */
692 /* obj - The exception object */
693 /* */
694 /*------------------------------------------------------------------*/
696 gboolean
697 mono_arch_handle_exception (void *sigctx, gpointer obj)
699 MonoContext mctx;
702 * Handling the exception in the signal handler is problematic, since the original
703 * signal is disabled, and we could run arbitrary code though the debugger. So
704 * resume into the normal stack and do most work there if possible.
706 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
708 /* Pass the ctx parameter in TLS */
709 mono_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);
711 mctx = jit_tls->ex_ctx;
712 mono_arch_setup_async_callback (&mctx, handle_signal_exception, obj);
713 mono_monoctx_to_sigctx (&mctx, sigctx);
715 return TRUE;
718 /*========================= End of Function ========================*/
720 /*------------------------------------------------------------------*/
721 /* */
722 /* Name - mono_arch_setup_async_callback */
723 /* */
724 /* Function - Establish the async callback. */
725 /* */
726 /* Parameters - ctx - Context */
727 /* async_cb - Callback routine address */
728 /* user_data - Data to be passed to callback */
729 /* */
730 /*------------------------------------------------------------------*/
732 void
733 mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
735 uintptr_t sp = (uintptr_t) MONO_CONTEXT_GET_SP(ctx);
737 ctx->uc_mcontext.gregs[2] = (gsize)user_data;
739 sp -= S390_MINIMAL_STACK_SIZE;
740 *(unsigned long *)sp = (uintptr_t) MONO_CONTEXT_GET_SP(ctx);
741 MONO_CONTEXT_SET_BP(ctx, sp);
742 MONO_CONTEXT_SET_IP(ctx, (gsize)async_cb);
745 /*========================= End of Function ========================*/
747 /*------------------------------------------------------------------*/
748 /* */
749 /* Name - mono_arch_ip_from_context */
750 /* */
751 /* Function - Return the instruction pointer from the context. */
752 /* */
753 /* Parameters - sigctx - Saved processor state */
754 /* */
755 /*------------------------------------------------------------------*/
757 gpointer
758 mono_arch_ip_from_context (void *sigctx)
760 return ((gpointer) MONO_CONTEXT_GET_IP(((MonoContext *) sigctx)));
764 /*========================= End of Function ========================*/
766 /*------------------------------------------------------------------*/
767 /* */
768 /* Name - mono_arch_get_restore_context */
769 /* */
770 /* Function - Return the address of the routine that will rest- */
771 /* ore the context. */
772 /* */
773 /*------------------------------------------------------------------*/
775 gpointer
776 mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
778 g_assert (!aot);
779 if (info)
780 *info = NULL;
782 return setcontext;
785 /*========================= End of Function ========================*/
789 * @brief Setup CTX so execution resumes at FUNC
791 * @param[in] Context to be resumed
792 * @param[in] Location to be resumed at
794 * Set the IP of the passed context to the address so that on resumption
795 * we jump to this location
798 void
799 mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func)
801 MONO_CONTEXT_SET_IP (ctx, func);
804 /*========================= End of Function ========================*/
806 /*------------------------------------------------------------------*/
807 /* */
808 /* Name - mono_arch_is_int_overflow */
809 /* */
810 /* Function - Inspect the code that raised the SIGFPE signal */
811 /* to see if the DivideByZero or Arithmetic exception*/
812 /* should be raised. */
813 /* */
814 /*------------------------------------------------------------------*/
816 gboolean
817 mono_arch_is_int_overflow (void *uc, void *info)
819 MonoContext *ctx;
820 guint8 *code;
821 guint64 *operand;
822 gboolean arithExc = TRUE;
823 gint regNo,
824 idxNo,
825 offset;
827 ctx = (MonoContext *) uc;
828 code = (guint8 *) ((siginfo_t *)info)->si_addr;
829 /*----------------------------------------------------------*/
830 /* Divide operations are the only ones that will give the */
831 /* divide by zero exception so just check for these ops. */
832 /*----------------------------------------------------------*/
833 switch (code[0]) {
834 case 0x1d : /* Divide Register */
835 regNo = code[1] & 0x0f;
836 if (ctx->uc_mcontext.gregs[regNo] == 0)
837 arithExc = FALSE;
838 break;
839 case 0x5d : /* Divide */
840 regNo = (code[2] & 0xf0 >> 8);
841 idxNo = (code[1] & 0x0f);
842 offset = *((guint16 *) code+2) & 0x0fff;
843 operand = (guint64*)(ctx->uc_mcontext.gregs[regNo] + offset);
844 if (idxNo != 0)
845 operand += ctx->uc_mcontext.gregs[idxNo];
846 if (*operand == 0)
847 arithExc = FALSE;
848 break;
849 case 0xb9 : /* DL[GR] or DS[GR] */
850 if ((code[1] == 0x97) || (code[1] == 0x87) ||
851 (code[1] == 0x0d) || (code[1] == 0x1d)) {
852 regNo = (code[3] & 0x0f);
853 if (ctx->uc_mcontext.gregs[regNo] == 0)
854 arithExc = FALSE;
856 break;
857 case 0xe3 : /* DL[G] | DS[G] */
858 if ((code[5] == 0x97) || (code[5] == 0x87) ||
859 (code[5] == 0x0d) || (code[5] == 0x1d)) {
860 regNo = (code[2] & 0xf0 >> 8);
861 idxNo = (code[1] & 0x0f);
862 offset = (code[2] & 0x0f << 8) +
863 code[3] + (code[4] << 12);
864 operand = (guint64*)(ctx->uc_mcontext.gregs[regNo] + offset);
865 if (idxNo != 0)
866 operand += ctx->uc_mcontext.gregs[idxNo];
867 if (*operand == 0)
868 arithExc = FALSE;
870 break;
871 default:
872 arithExc = TRUE;
874 ctx->uc_mcontext.psw.addr = (guint64)code;
875 return (arithExc);
878 /*========================= End of Function ========================*/