1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions
3 Copyright (C) 1996-2005, 2006 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
25 Contact: cacao@cacaojvm.org
27 Authors: Christian Thalinger
29 Changes: Edwin Steiner
31 $Id: md.c 8178 2007-07-05 11:13:20Z michi $
43 #include "vm/jit/s390/md-abi.h"
45 #if defined(ENABLE_THREADS)
46 # include "threads/threads-common.h"
47 # include "threads/native/threads.h"
50 #include "vm/exceptions.h"
51 #include "vm/signallocal.h"
52 #include "vm/jit/asmpart.h"
53 #include "vm/jit/methodheader.h"
54 #include "vm/jit/stacktrace.h"
56 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
57 #include "vmcore/options.h" /* XXX debug */
58 #include "vm/jit/disass.h" /* XXX debug */
61 #include "vm/jit/codegen-common.h"
62 #include "vm/jit/s390/codegen.h"
65 #define OOPS() assert(0);
67 /* prototypes *****************************************************************/
69 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
71 void md_dump_context(u1 *pc, mcontext_t *mc);
73 /* md_init *********************************************************************
75 Do some machine dependent initialization.
77 *******************************************************************************/
83 /* md_dump_context ************************************************************
85 Logs the machine context
87 *******************************************************************************/
89 void md_dump_context(u1 *pc, mcontext_t *mc) {
99 log_println("Dumping context.");
101 log_println("Program counter: 0x%08X", pc);
103 pv = codegen_get_pv_from_pc_nocheck(pc);
105 log_println("No java method found at location.");
107 m = ((codeinfo *)(pv + CodeinfoPointer))->m;
109 "Java method: class %s, method %s, descriptor %s.",
110 utf_bytes(m->class->name), utf_bytes(m->name), utf_bytes(m->descriptor)
114 #if defined(ENABLE_DISASSEMBLER)
115 log_println("Printing instruction at program counter:");
119 log_println("General purpose registers:");
121 for (i = 0; i < 16; i++) {
122 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
125 log_println("Floating point registers:");
127 for (i = 0; i < 16; i++) {
128 freg.fr.d = mc->fpregs.fprs[i].d;
129 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
132 #if defined(ENABLE_THREADS)
133 log_println("Dumping the current stacktrace:");
134 threads_print_stacktrace();
139 /* md_signal_handler_sigsegv ***************************************************
141 NullPointerException signal handler for hardware null pointer
144 *******************************************************************************/
146 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
157 java_objectheader *e;
161 _uc = (ucontext_t *) _p;
162 _mc = &_uc->uc_mcontext;
164 xpc = (u1 *)_mc->psw.addr;
166 /* Check opcodes and verify it is a null pointer exception */
171 base = (xpc[2] >> 4) & 0xF;
174 } else if (_mc->gregs[base] == 0) {
184 md_dump_context(xpc, _mc);
186 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
189 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
190 sp = (u1 *)_mc->gregs[REG_SP];
192 type = EXCEPTION_HARDWARE_NULLPOINTER;
195 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val, &sfi);
197 _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
198 _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
199 _mc->psw.addr = (ptrint) asm_handle_exception;
202 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
212 java_objectheader *e;
215 _uc = (ucontext_t *) _p;
216 _mc = &_uc->uc_mcontext;
217 xpc = ra = siginfo->si_addr;
219 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
221 if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
223 /* bits 7-4 contain a register holding a value */
224 reg = (xpc[1] >> 4) & 0xF;
226 /* bits 3-0 designate the exception type */
229 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
230 sp = (u1 *)_mc->gregs[REG_SP];
231 val = (ptrint)_mc->gregs[reg];
233 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val, &sfi);
235 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
236 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
237 _mc->psw.addr = (ptrint) asm_handle_exception;
241 md_dump_context(xpc, _mc);
243 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
247 /* md_signal_handler_sigfpe ****************************************************
249 ArithmeticException signal handler for hardware divide by zero
252 *******************************************************************************/
254 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
267 java_objectheader *e;
269 _uc = (ucontext_t *) _p;
270 _mc = &_uc->uc_mcontext;
272 /* Instruction that raised signal */
273 xpc = siginfo->si_addr;
277 if (xpc[0] == 0x1D) { /* DR */
279 r1 = (xpc[1] >> 4) & 0xF;
283 (_mc->gregs[r1] == 0xFFFFFFFF) &&
284 (_mc->gregs[r1 + 1] == 0x80000000) &&
285 (_mc->gregs[r2] == 0xFFFFFFFF)
287 /* handle special case */
288 /* next instruction */
289 pc = (u1 *)_mc->psw.addr;
293 _mc->gregs[r1 + 1] = 0x80000000;
294 /* continue at next instruction */
295 _mc->psw.addr = (ptrint) pc;
298 } else if (_mc->gregs[r2] == 0) {
301 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
302 sp = (u1 *)_mc->gregs[REG_SP];
305 type = EXCEPTION_HARDWARE_ARITHMETIC;
308 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val, &sfi);
310 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
311 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
312 _mc->psw.addr = (ptrint) asm_handle_exception;
318 /* Could not handle signal */
321 md_dump_context(xpc, _mc);
323 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
327 /* md_signal_handler_sigusr2 ***************************************************
329 Signal handler for profiling sampling.
331 *******************************************************************************/
333 #if defined(ENABLE_THREADS)
334 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
343 _uc = (ucontext_t *) _p;
344 _mc = &_uc->uc_mcontext;
346 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
347 different to the ones in <ucontext.h>. */
349 pc = (u1 *) _mc->psw.addr;
356 #if defined(ENABLE_THREADS)
357 void md_critical_section_restart(ucontext_t *_uc)
363 _mc = &_uc->uc_mcontext;
365 pc = (u1 *)_mc->psw.addr;
367 npc = critical_find_restart_point(pc);
370 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
371 _mc->psw.addr = (ptrint) npc;
377 /* md_codegen_patch_branch *****************************************************
379 Back-patches a branch instruction.
381 *******************************************************************************/
383 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
387 s4 disp; /* branch displacement */
389 /* calculate the patch position */
391 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
393 /* Calculate the branch displacement. */
395 disp = targetmpc - branchmpc;
396 disp += 4; /* size of branch */
397 disp /= 2; /* specified in halfwords */
399 ASSERT_VALID_BRANCH(disp);
401 /* patch the branch instruction before the mcodeptr */
403 mcodeptr[-1] |= (disp & 0xFFFF);
407 /* md_stacktrace_get_returnaddress *********************************************
409 Returns the return address of the current stackframe, specified by
410 the passed stack pointer and the stack frame size.
412 *******************************************************************************/
414 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
418 /* on S390 the return address is located on the top of the stackframe */
420 ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
426 /* md_get_method_patch_address *************************************************
428 Gets the patch address of the currently compiled method. The offset
429 is extracted from the load instruction(s) before the jump and added
430 to the right base address (PV or REG_METHODPTR).
432 INVOKESTATIC/SPECIAL:
434 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
436 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
438 0x7748d7ba: 0d ed basr %r14,%r13
443 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
445 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
447 0x7748d832: 0d ed basr %r14,%r13
453 last 2 instructions the same as in invokevirtual
455 *******************************************************************************/
457 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
461 u1 *pa; /* patch address */
463 /* go back to the load before the call instruction */
465 ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
467 /* get the base register of the load */
472 /* check for the different calls */
476 /* INVOKESTATIC/SPECIAL */
481 /* the offset is in the load instruction */
482 offset = ((*(u2 *)(ra + 2)) & 0xFFF) + N_PV_OFFSET;
485 /* the offset is in the immediate load before the load */
486 offset = *((s2 *) (ra - 2));
492 /* add the offset to the procedure vector */
494 pa = sfi->pv + offset;
500 /* INVOKEVIRTUAL/INTERFACE */
502 offset = *((u2 *)(ra + 2)) & 0xFFF;
504 /* add offset to method pointer */
509 /* catch any problems */
518 /* md_codegen_get_pv_from_pc ***************************************************
520 On this architecture just a wrapper function to
521 codegen_get_pv_from_pc.
523 *******************************************************************************/
525 u1 *md_codegen_get_pv_from_pc(u1 *ra)
529 /* Get the start address of the function which contains this
530 address from the method table. */
532 pv = codegen_get_pv_from_pc(ra);
538 /* md_cacheflush ***************************************************************
540 Calls the system's function to flush the instruction and data
543 *******************************************************************************/
545 void md_cacheflush(u1 *addr, s4 nbytes)
551 /* md_icacheflush **************************************************************
553 Calls the system's function to flush the instruction cache.
555 *******************************************************************************/
557 void md_icacheflush(u1 *addr, s4 nbytes)
563 /* md_dcacheflush **************************************************************
565 Calls the system's function to flush the data cache.
567 *******************************************************************************/
569 void md_dcacheflush(u1 *addr, s4 nbytes)
575 /* md_patch_replacement_point **************************************************
577 Patch the given replacement point.
579 *******************************************************************************/
581 void md_patch_replacement_point(rplpoint *rp)
585 /* XXX this is probably unsafe! */
587 /* save the current machine code */
588 mcode = *(u8*)rp->pc;
590 /* write spinning instruction */
591 *(u2*)(rp->pc) = 0xebfe;
594 rp->pc[4] = (rp->mcode >> 32);
596 /* write first word */
597 *(u4*)(rp->pc) = (u4) rp->mcode;
599 /* store saved mcode */
602 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
610 /* XXX if required asm_cacheflush(rp->pc,8); */
614 * These are local overrides for various environment variables in Emacs.
615 * Please do not remove this and leave it at the end of the file, where
616 * Emacs will automagically detect them.
617 * ---------------------------------------------------------------------
620 * indent-tabs-mode: t
624 * vim:noexpandtab:sw=4:ts=4: