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"
60 /* prototypes *****************************************************************/
62 u1 *exceptions_handle_exception(java_object_t *xptro, u1 *xpc, u1 *pv, u1 *sp);
64 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
66 void md_dump_context(u1 *pc, mcontext_t *mc);
68 /* md_init *********************************************************************
70 Do some machine dependent initialization.
72 *******************************************************************************/
78 /* md_dump_context ************************************************************
80 Logs the machine context
82 *******************************************************************************/
84 void md_dump_context(u1 *pc, mcontext_t *mc) {
94 log_println("Dumping context.");
96 log_println("Program counter: 0x%08X", pc);
98 pv = codegen_get_pv_from_pc_nocheck(pc);
100 log_println("No java method found at location.");
102 m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
104 "Java method: class %s, method %s, descriptor %s.",
105 m->class->name->text, m->name->text, m->descriptor->text
109 #if defined(ENABLE_DISASSEMBLER)
110 log_println("Printing instruction at program counter:");
114 log_println("General purpose registers:");
116 for (i = 0; i < 16; i++) {
117 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
120 log_println("Floating point registers:");
122 for (i = 0; i < 16; i++) {
123 freg.fr.d = mc->fpregs.fprs[i].d;
124 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
127 #if defined(ENABLE_THREADS)
128 log_println("Dumping the current stacktrace:");
129 threads_print_stacktrace();
134 /* md_signal_handler_sigsegv ***************************************************
136 NullPointerException signal handler for hardware null pointer
139 *******************************************************************************/
141 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
155 _uc = (ucontext_t *) _p;
156 _mc = &_uc->uc_mcontext;
158 xpc = (u1 *)_mc->psw.addr;
160 /* Check opcodes and verify it is a null pointer exception */
162 switch (N_RX_GET_OPC(xpc)) {
165 case OPC_CL: /* array size check on NULL array */
166 base = N_RX_GET_BASE(xpc);
169 } else if (_mc->gregs[base] == 0) {
182 md_dump_context(xpc, _mc);
184 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
187 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
188 sp = (u1 *)_mc->gregs[REG_SP];
190 type = EXCEPTION_HARDWARE_NULLPOINTER;
193 /* Handle the type. */
195 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
198 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
199 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
200 _mc->psw.addr = (intptr_t) asm_handle_exception;
203 _mc->psw.addr = (intptr_t) xpc;
207 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
220 _uc = (ucontext_t *) _p;
221 _mc = &_uc->uc_mcontext;
222 xpc = ra = siginfo->si_addr;
224 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
226 if ((siginfo->si_code == ILL_ILLOPC) && (N_RR_GET_OPC(xpc) == OPC_ILL)) {
228 /* bits 7-4 contain a register holding a value */
229 reg = N_ILL_GET_REG(xpc);
231 /* bits 3-0 designate the exception type */
232 type = N_ILL_GET_TYPE(xpc);
234 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
235 sp = (u1 *)_mc->gregs[REG_SP];
236 val = (ptrint)_mc->gregs[reg];
238 if (EXCEPTION_HARDWARE_COMPILER == type) {
239 /* The PV from the compiler stub is equal to the XPC. */
243 /* The return address in is REG_RA */
245 ra = (u1 *)_mc->gregs[REG_RA];
250 /* Handle the type. */
252 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
254 if (EXCEPTION_HARDWARE_COMPILER == type) {
256 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) builtin_retrieve_exception();
257 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) ra - 2;
258 _mc->gregs[REG_PV] = (intptr_t) md_codegen_get_pv_from_pc(ra);
259 _mc->psw.addr = (intptr_t) asm_handle_exception;
261 _mc->gregs[REG_PV] = (intptr_t) p;
262 _mc->psw.addr = (intptr_t) p;
266 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
267 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
268 _mc->psw.addr = (intptr_t) asm_handle_exception;
271 _mc->psw.addr = (intptr_t) xpc;
276 md_dump_context(xpc, _mc);
278 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
282 /* md_signal_handler_sigfpe ****************************************************
284 ArithmeticException signal handler for hardware divide by zero
287 *******************************************************************************/
289 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
303 _uc = (ucontext_t *) _p;
304 _mc = &_uc->uc_mcontext;
306 /* Instruction that raised signal */
307 xpc = siginfo->si_addr;
311 if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
313 r1 = N_RR_GET_REG1(xpc);
314 r2 = N_RR_GET_REG2(xpc);
317 (_mc->gregs[r1] == 0xFFFFFFFF) &&
318 (_mc->gregs[r1 + 1] == 0x80000000) &&
319 (_mc->gregs[r2] == 0xFFFFFFFF)
321 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
322 /* next instruction */
323 pc = (u1 *)_mc->psw.addr;
327 _mc->gregs[r1 + 1] = 0x80000000;
328 /* continue at next instruction */
329 _mc->psw.addr = (ptrint) pc;
333 else if (_mc->gregs[r2] == 0) {
336 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
337 sp = (u1 *)_mc->gregs[REG_SP];
340 type = EXCEPTION_HARDWARE_ARITHMETIC;
343 /* Handle the type. */
345 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
347 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
348 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
349 _mc->psw.addr = (intptr_t) asm_handle_exception;
355 /* Could not handle signal */
358 md_dump_context(xpc, _mc);
360 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
364 /* md_signal_handler_sigusr2 ***************************************************
366 Signal handler for profiling sampling.
368 *******************************************************************************/
370 #if defined(ENABLE_THREADS)
371 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
380 _uc = (ucontext_t *) _p;
381 _mc = &_uc->uc_mcontext;
383 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
384 different to the ones in <ucontext.h>. */
386 pc = (u1 *) _mc->psw.addr;
393 #if defined(ENABLE_THREADS)
394 void md_critical_section_restart(ucontext_t *_uc)
400 _mc = &_uc->uc_mcontext;
402 pc = (u1 *)_mc->psw.addr;
404 npc = critical_find_restart_point(pc);
407 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
408 _mc->psw.addr = (ptrint) npc;
414 /* md_jit_method_patch_address *************************************************
416 Gets the patch address of the currently compiled method. The offset
417 is extracted from the load instruction(s) before the jump and added
418 to the right base address (PV or REG_METHODPTR).
420 INVOKESTATIC/SPECIAL:
422 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
424 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
426 0x7748d7ba: 0d ed basr %r14,%r13
431 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
433 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
435 0x7748d832: 0d ed basr %r14,%r13
441 last 2 instructions the same as in invokevirtual
443 *******************************************************************************/
445 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
450 void *pa; /* patch address */
452 /* go back to the load before the call instruction */
454 pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
456 /* get the base register of the load */
458 base = N_RX_GET_BASE(pc);
459 index = N_RX_GET_INDEX(pc);
461 /* check for the different calls */
465 /* INVOKESTATIC/SPECIAL */
469 /* the offset is in the load instruction */
470 offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
473 /* the offset is in the immediate load before the load */
474 offset = N_RI_GET_IMM(pc - SZ_L);
480 /* add the offset to the procedure vector */
482 pa = ((uint8_t *) pv) + offset;
487 /* INVOKEVIRTUAL/INTERFACE */
489 offset = N_RX_GET_DISP(pc);
491 /* return NULL if no mptr was specified (used for replacement) */
496 /* add offset to method pointer */
498 pa = (uint8_t *)mptr + offset;
502 /* catch any problems */
503 vm_abort("md_jit_method_patch_address");
511 /* md_patch_replacement_point **************************************************
513 Patch the given replacement point.
515 *******************************************************************************/
516 #if defined(ENABLE_REPLACEMENT)
517 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
523 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
541 xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
542 xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
543 sp = *(uint8_t **)(regs + REG_SP);
546 /* initialize number of calle saved int regs to restore to 0 */
549 /* initialize number of calle saved flt regs to restore to 0 */
556 pv = codegen_get_pv_from_pc(xpc);
558 handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
560 if (handler == NULL) {
562 /* exception was not handled
563 * get values of calee saved registers and remove stack frame
566 /* read stuff from data segment */
568 framesize = *(int32_t *)(pv + FrameSize);
570 intsave = *(int32_t *)(pv + IntSave);
571 if (intsave > out[0]) {
575 fltsave = *(int32_t *)(pv + FltSave);
576 if (fltsave > out[1]) {
580 /* pointer to register save area */
582 savearea = (int64_t *)(sp + framesize - 8);
586 ra = *(uint8_t **)(sp + framesize - 8);
588 /* restore saved registers */
590 for (i = 0; i < intsave; ++i) {
592 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
593 regs[reg] = *(int32_t *)(savearea);
596 for (i = 0; i < fltsave; ++i) {
598 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
599 fregs[reg] = *savearea;
602 /* remove stack frame */
606 /* new xpc is call before return address */
613 } while (handler == NULL);
615 /* write new values for registers */
617 *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
618 *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
619 *(uint8_t **)(regs + REG_SP) = sp;
620 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
622 /* maybe leaf flag */
624 out[2] = (loops == 1);
628 * These are local overrides for various environment variables in Emacs.
629 * Please do not remove this and leave it at the end of the file, where
630 * Emacs will automagically detect them.
631 * ---------------------------------------------------------------------
634 * indent-tabs-mode: t
638 * vim:noexpandtab:sw=4:ts=4: