4 * Function - Exception support for S/390.
6 * Name - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
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 /*------------------------------------------------------------------*/
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
39 #define setup_context(ctx)
41 /*========================= End of Defines =========================*/
43 /*------------------------------------------------------------------*/
45 /*------------------------------------------------------------------*/
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>
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 /*------------------------------------------------------------------*/
92 /*====================== End of Global Variables ===================*/
94 /*------------------------------------------------------------------*/
96 /* Name - mono_arch_get_call_filter */
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). */
103 /*------------------------------------------------------------------*/
106 mono_arch_get_call_filter (MonoTrampInfo
**info
, gboolean aot
)
108 static guint8
*start
;
109 static int inited
= 0;
111 int gr_offset
, alloc_size
, pos
, i
;
112 GSList
*unwind_ops
= NULL
;
113 MonoJumpInfo
*ji
= NULL
;
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 /*------------------------------------------------------*/
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
);
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
);
193 /*------------------------------------------------------*/
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
);
205 /*------------------------------------------------------*/
206 /* Reload our stack register with value saved in context*/
207 /*------------------------------------------------------*/
208 s390_lgr (code
, STK_BASE
, s390_r13
);
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
));
233 *info
= mono_tramp_info_create ("call_filter",
234 start
, code
- start
, ji
,
240 /*========================= End of Function ========================*/
242 /*------------------------------------------------------------------*/
244 /* Name - throw_exception. */
246 /* Function - Raise an exception based on the parameters passed.*/
248 /*------------------------------------------------------------------*/
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
)
259 memset(&ctx
, 0, sizeof(ctx
));
263 /* adjust eip so that it point into the call instruction */
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 /*------------------------------------------------------------------*/
298 /* Name - get_throw_exception_generic */
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); */
306 /*------------------------------------------------------------------*/
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
);
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 */
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
));
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
);
401 /*========================= End of Function ========================*/
403 /*------------------------------------------------------------------*/
405 /* Name - arch_get_throw_exception */
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); */
412 /*------------------------------------------------------------------*/
415 mono_arch_get_throw_exception (MonoTrampInfo
**info
, gboolean aot
)
421 return (mono_arch_get_throw_exception_generic (SZ_THROW
, info
, FALSE
, FALSE
, aot
, FALSE
));
424 /*========================= End of Function ========================*/
426 /*------------------------------------------------------------------*/
428 /* Name - arch_get_rethrow_preserve_exception */
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); */
436 /*------------------------------------------------------------------*/
439 mono_arch_get_rethrow_preserve_exception (MonoTrampInfo
**info
, gboolean aot
)
445 return (mono_arch_get_throw_exception_generic (SZ_THROW
, info
, FALSE
, TRUE
, aot
, TRUE
));
448 /*========================= End of Function ========================*/
450 /*------------------------------------------------------------------*/
452 /* Name - arch_get_rethrow_exception */
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); */
459 /*------------------------------------------------------------------*/
462 mono_arch_get_rethrow_exception (MonoTrampInfo
**info
, gboolean aot
)
468 return (mono_arch_get_throw_exception_generic (SZ_THROW
, info
, FALSE
, TRUE
, aot
, FALSE
));
471 /*========================= End of Function ========================*/
473 /*------------------------------------------------------------------*/
475 /* Name - arch_get_corlib_exception */
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) */
482 /*------------------------------------------------------------------*/
485 mono_arch_get_throw_corlib_exception (MonoTrampInfo
**info
, gboolean aot
)
491 return (mono_arch_get_throw_exception_generic (SZ_THROW
, info
, TRUE
, FALSE
, aot
, FALSE
));
494 /*========================= End of Function ========================*/
496 /*------------------------------------------------------------------*/
498 /* Name - mono_arch_unwind_frame */
500 /* Function - See exceptions-amd64.c for docs. */
502 /*------------------------------------------------------------------*/
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
));
522 guint32 unwind_info_len
;
524 host_mgreg_t regs
[32];
526 if (ji
->is_trampoline
)
527 frame
->type
= FRAME_TYPE_TRAMPOLINE
;
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 (®s
[0], &ctx
->uc_mcontext
.gregs
, 16 * sizeof(host_mgreg_t
));
539 memcpy (®s
[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
);
548 memcpy (&new_ctx
->uc_mcontext
.gregs
, ®s
[0], 16 * sizeof(host_mgreg_t
));
549 memcpy (&new_ctx
->uc_mcontext
.fpregs
.fprs
, ®s
[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]);
557 ji
= mini_jit_info_table_find (domain
, (gpointer
)(*lmf
)->eip
, NULL
);
562 frame
->method
= (*lmf
)->method
;
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
;
580 /*========================= End of Function ========================*/
583 altstack_handle_and_restore (MonoContext
*ctx
, MONO_SIG_HANDLER_INFO_TYPE
*siginfo
, gpointer obj
, guint32 flags
)
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 */
599 mono_handle_exception (&mctx
, obj
);
601 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
602 jit_tls
->stack_ovf_pending
= 1;
604 mono_restore_context (&mctx
);
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
;
618 jit_tls
= mono_tls_get_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
))
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);
660 /*========================= End of Function ========================*/
662 /*------------------------------------------------------------------*/
664 /* Name - handle_signal_exception */
666 /* Function - Handle an exception raised by the JIT code. */
668 /* Parameters - obj - The exception object */
670 /*------------------------------------------------------------------*/
673 handle_signal_exception (gpointer obj
)
675 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
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 /*------------------------------------------------------------------*/
687 /* Name - mono_arch_handle_exception */
689 /* Function - Handle an exception raised by the JIT code. */
691 /* Parameters - ctx - Saved processor state */
692 /* obj - The exception object */
694 /*------------------------------------------------------------------*/
697 mono_arch_handle_exception (void *sigctx
, gpointer obj
)
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
);
718 /*========================= End of Function ========================*/
720 /*------------------------------------------------------------------*/
722 /* Name - mono_arch_setup_async_callback */
724 /* Function - Establish the async callback. */
726 /* Parameters - ctx - Context */
727 /* async_cb - Callback routine address */
728 /* user_data - Data to be passed to callback */
730 /*------------------------------------------------------------------*/
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 /*------------------------------------------------------------------*/
749 /* Name - mono_arch_ip_from_context */
751 /* Function - Return the instruction pointer from the context. */
753 /* Parameters - sigctx - Saved processor state */
755 /*------------------------------------------------------------------*/
758 mono_arch_ip_from_context (void *sigctx
)
760 return ((gpointer
) MONO_CONTEXT_GET_IP(((MonoContext
*) sigctx
)));
764 /*========================= End of Function ========================*/
766 /*------------------------------------------------------------------*/
768 /* Name - mono_arch_get_restore_context */
770 /* Function - Return the address of the routine that will rest- */
771 /* ore the context. */
773 /*------------------------------------------------------------------*/
776 mono_arch_get_restore_context (MonoTrampInfo
**info
, gboolean aot
)
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
799 mono_arch_setup_resume_sighandler_ctx (MonoContext
*ctx
, gpointer func
)
801 MONO_CONTEXT_SET_IP (ctx
, func
);
804 /*========================= End of Function ========================*/
806 /*------------------------------------------------------------------*/
808 /* Name - mono_arch_is_int_overflow */
810 /* Function - Inspect the code that raised the SIGFPE signal */
811 /* to see if the DivideByZero or Arithmetic exception*/
812 /* should be raised. */
814 /*------------------------------------------------------------------*/
817 mono_arch_is_int_overflow (void *uc
, void *info
)
822 gboolean arithExc
= TRUE
;
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 /*----------------------------------------------------------*/
834 case 0x1d : /* Divide Register */
835 regNo
= code
[1] & 0x0f;
836 if (ctx
->uc_mcontext
.gregs
[regNo
] == 0)
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
);
845 operand
+= ctx
->uc_mcontext
.gregs
[idxNo
];
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)
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
);
866 operand
+= ctx
->uc_mcontext
.gregs
[idxNo
];
874 ctx
->uc_mcontext
.psw
.addr
= (guint64
)code
;
878 /*========================= End of Function ========================*/