1 /* src/vm/jit/s390/md.c - machine dependent s390 Linux functions
3 Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
37 #include "vm/jit/s390/md-abi.h"
39 #if defined(ENABLE_THREADS)
40 # include "threads/threads-common.h"
41 # include "threads/native/threads.h"
44 #include "vm/exceptions.h"
45 #include "vm/signallocal.h"
46 #include "vm/jit/asmpart.h"
47 #include "vm/jit/abi.h"
48 #include "vm/jit/methodheader.h"
49 #include "vm/jit/stacktrace.h"
51 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
52 #include "vmcore/options.h" /* XXX debug */
53 #include "vm/jit/disass.h" /* XXX debug */
56 #include "vm/jit/codegen-common.h"
57 #include "vm/jit/s390/codegen.h"
61 /* prototypes *****************************************************************/
63 u1 *exceptions_handle_exception(java_object_t *xptro, u1 *xpc, u1 *pv, u1 *sp);
65 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
67 void md_dump_context(u1 *pc, mcontext_t *mc);
69 /* md_init *********************************************************************
71 Do some machine dependent initialization.
73 *******************************************************************************/
79 /* md_dump_context ************************************************************
81 Logs the machine context
83 *******************************************************************************/
85 void md_dump_context(u1 *pc, mcontext_t *mc) {
95 log_println("Dumping context.");
97 log_println("Program counter: 0x%08X", pc);
99 pv = codegen_get_pv_from_pc_nocheck(pc);
101 log_println("No java method found at location.");
103 m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
105 "Java method: class %s, method %s, descriptor %s.",
106 m->class->name->text, m->name->text, m->descriptor->text
110 #if defined(ENABLE_DISASSEMBLER)
111 log_println("Printing instruction at program counter:");
115 log_println("General purpose registers:");
117 for (i = 0; i < 16; i++) {
118 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
121 log_println("Floating point registers:");
123 for (i = 0; i < 16; i++) {
124 freg.fr.d = mc->fpregs.fprs[i].d;
125 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
128 #if defined(ENABLE_THREADS)
129 log_println("Dumping the current stacktrace:");
130 threads_print_stacktrace();
135 /* md_signal_handler_sigsegv ***************************************************
137 NullPointerException signal handler for hardware null pointer
140 *******************************************************************************/
142 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
156 _uc = (ucontext_t *) _p;
157 _mc = &_uc->uc_mcontext;
159 xpc = (u1 *)_mc->psw.addr;
161 /* Check opcodes and verify it is a null pointer exception */
163 switch (N_RX_GET_OPC(xpc)) {
166 case OPC_CL: /* array size check on NULL array */
167 base = N_RX_GET_BASE(xpc);
170 } else if (_mc->gregs[base] == 0) {
183 md_dump_context(xpc, _mc);
185 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
188 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
189 sp = (u1 *)_mc->gregs[REG_SP];
191 type = EXCEPTION_HARDWARE_NULLPOINTER;
194 /* Handle the type. */
196 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
199 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
200 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
201 _mc->psw.addr = (intptr_t) asm_handle_exception;
204 _mc->psw.addr = (intptr_t) xpc;
208 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
221 _uc = (ucontext_t *) _p;
222 _mc = &_uc->uc_mcontext;
223 xpc = ra = siginfo->si_addr;
225 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
227 if ((siginfo->si_code == ILL_ILLOPC) && (N_RR_GET_OPC(xpc) == OPC_ILL)) {
229 /* bits 7-4 contain a register holding a value */
230 reg = N_ILL_GET_REG(xpc);
232 /* bits 3-0 designate the exception type */
233 type = N_ILL_GET_TYPE(xpc);
235 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
236 sp = (u1 *)_mc->gregs[REG_SP];
237 val = (ptrint)_mc->gregs[reg];
239 /* Handle the type. */
241 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
244 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
245 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
246 _mc->psw.addr = (intptr_t) asm_handle_exception;
249 _mc->psw.addr = (intptr_t) xpc;
253 md_dump_context(xpc, _mc);
255 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
259 /* md_signal_handler_sigfpe ****************************************************
261 ArithmeticException signal handler for hardware divide by zero
264 *******************************************************************************/
266 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
280 _uc = (ucontext_t *) _p;
281 _mc = &_uc->uc_mcontext;
283 /* Instruction that raised signal */
284 xpc = siginfo->si_addr;
288 if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
290 r1 = N_RR_GET_REG1(xpc);
291 r2 = N_RR_GET_REG2(xpc);
294 (_mc->gregs[r1] == 0xFFFFFFFF) &&
295 (_mc->gregs[r1 + 1] == 0x80000000) &&
296 (_mc->gregs[r2] == 0xFFFFFFFF)
298 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
299 /* next instruction */
300 pc = (u1 *)_mc->psw.addr;
304 _mc->gregs[r1 + 1] = 0x80000000;
305 /* continue at next instruction */
306 _mc->psw.addr = (ptrint) pc;
310 else if (_mc->gregs[r2] == 0) {
313 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
314 sp = (u1 *)_mc->gregs[REG_SP];
317 type = EXCEPTION_HARDWARE_ARITHMETIC;
320 /* Handle the type. */
322 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
324 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
325 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
326 _mc->psw.addr = (intptr_t) asm_handle_exception;
332 /* Could not handle signal */
335 md_dump_context(xpc, _mc);
337 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
341 /* md_signal_handler_sigusr2 ***************************************************
343 Signal handler for profiling sampling.
345 *******************************************************************************/
347 #if defined(ENABLE_THREADS)
348 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
357 _uc = (ucontext_t *) _p;
358 _mc = &_uc->uc_mcontext;
360 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
361 different to the ones in <ucontext.h>. */
363 pc = (u1 *) _mc->psw.addr;
370 #if defined(ENABLE_THREADS)
371 void md_critical_section_restart(ucontext_t *_uc)
377 _mc = &_uc->uc_mcontext;
379 pc = (u1 *)_mc->psw.addr;
381 npc = critical_find_restart_point(pc);
384 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
385 _mc->psw.addr = (ptrint) npc;
391 /* md_stacktrace_get_returnaddress *********************************************
393 Returns the return address of the current stackframe, specified by
394 the passed stack pointer and the stack frame size.
396 *******************************************************************************/
398 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
402 /* on S390 the return address is located on the top of the stackframe */
404 ra = *((u1 **) (sp + framesize - 8));
410 /* md_jit_method_patch_address *************************************************
412 Gets the patch address of the currently compiled method. The offset
413 is extracted from the load instruction(s) before the jump and added
414 to the right base address (PV or REG_METHODPTR).
416 INVOKESTATIC/SPECIAL:
418 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
420 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
422 0x7748d7ba: 0d ed basr %r14,%r13
427 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
429 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
431 0x7748d832: 0d ed basr %r14,%r13
437 last 2 instructions the same as in invokevirtual
439 *******************************************************************************/
441 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
446 void *pa; /* patch address */
448 /* go back to the load before the call instruction */
450 pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
452 /* get the base register of the load */
454 base = N_RX_GET_BASE(pc);
455 index = N_RX_GET_INDEX(pc);
457 /* check for the different calls */
461 /* INVOKESTATIC/SPECIAL */
465 /* the offset is in the load instruction */
466 offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
469 /* the offset is in the immediate load before the load */
470 offset = N_RI_GET_IMM(pc - SZ_L);
476 /* add the offset to the procedure vector */
478 pa = ((uint8_t *) pv) + offset;
483 /* INVOKEVIRTUAL/INTERFACE */
485 offset = N_RX_GET_DISP(pc);
487 /* return NULL if no mptr was specified (used for replacement) */
492 /* add offset to method pointer */
494 pa = (uint8_t *)mptr + offset;
498 /* catch any problems */
499 vm_abort("md_jit_method_patch_address");
507 /* md_codegen_get_pv_from_pc ***************************************************
509 On this architecture just a wrapper function to
510 codegen_get_pv_from_pc.
512 *******************************************************************************/
514 u1 *md_codegen_get_pv_from_pc(u1 *ra)
518 /* Get the start address of the function which contains this
519 address from the method table. */
521 pv = codegen_get_pv_from_pc(ra);
527 /* md_cacheflush ***************************************************************
529 Calls the system's function to flush the instruction and data
532 *******************************************************************************/
534 void md_cacheflush(u1 *addr, s4 nbytes)
540 /* md_icacheflush **************************************************************
542 Calls the system's function to flush the instruction cache.
544 *******************************************************************************/
546 void md_icacheflush(u1 *addr, s4 nbytes)
552 /* md_dcacheflush **************************************************************
554 Calls the system's function to flush the data cache.
556 *******************************************************************************/
558 void md_dcacheflush(u1 *addr, s4 nbytes)
564 /* md_patch_replacement_point **************************************************
566 Patch the given replacement point.
568 *******************************************************************************/
569 #if defined(ENABLE_REPLACEMENT)
570 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
576 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
594 xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
595 xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
596 sp = *(uint8_t **)(regs + REG_SP);
599 /* initialize number of calle saved int regs to restore to 0 */
602 /* initialize number of calle saved flt regs to restore to 0 */
609 pv = codegen_get_pv_from_pc(xpc);
611 handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
613 if (handler == NULL) {
615 /* exception was not handled
616 * get values of calee saved registers and remove stack frame
619 /* read stuff from data segment */
621 framesize = *(int32_t *)(pv + FrameSize);
623 intsave = *(int32_t *)(pv + IntSave);
624 if (intsave > out[0]) {
628 fltsave = *(int32_t *)(pv + FltSave);
629 if (fltsave > out[1]) {
633 /* pointer to register save area */
635 savearea = (int64_t *)(sp + framesize - 8);
639 ra = *(uint8_t **)(sp + framesize - 8);
641 /* restore saved registers */
643 for (i = 0; i < intsave; ++i) {
645 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
646 regs[reg] = *(int32_t *)(savearea);
649 for (i = 0; i < fltsave; ++i) {
651 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
652 fregs[reg] = *savearea;
655 /* remove stack frame */
659 /* new xpc is call before return address */
666 } while (handler == NULL);
668 /* write new values for registers */
670 *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
671 *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
672 *(uint8_t **)(regs + REG_SP) = sp;
673 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
675 /* maybe leaf flag */
677 out[2] = (loops == 1);
681 * These are local overrides for various environment variables in Emacs.
682 * Please do not remove this and leave it at the end of the file, where
683 * Emacs will automagically detect them.
684 * ---------------------------------------------------------------------
687 * indent-tabs-mode: t
691 * vim:noexpandtab:sw=4:ts=4: