-/* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions
+/* src/vm/jit/s390/md.c - machine dependent s390 Linux functions
- Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+ Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
J. Wenninger, Institut f. Computersprachen - TU Wien
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Christian Thalinger
-
- Changes: Edwin Steiner
-
- $Id: md.c 7848 2007-05-01 21:40:26Z pm $
-
*/
+
#define _GNU_SOURCE
#include "config.h"
#include <assert.h>
+#include <stdint.h>
#include <stdlib.h>
#include <ucontext.h>
#include "vm/exceptions.h"
#include "vm/signallocal.h"
#include "vm/jit/asmpart.h"
+#include "vm/jit/abi.h"
+#include "vm/jit/methodheader.h"
#include "vm/jit/stacktrace.h"
#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
void md_init(void)
{
- struct sigaction act;
-
- act.sa_sigaction = md_signal_handler_sigill;
- act.sa_flags = SA_NODEFER | SA_SIGINFO;
-
- if (sigaction(SIGILL, &act, NULL) == -1) {
- vm_abort("%s: error registering SIGILL signal handler.", __FUNCTION__);
- }
}
/* md_dump_context ************************************************************
void md_dump_context(u1 *pc, mcontext_t *mc) {
int i;
-
+ u1 *pv;
+ methodinfo *m;
+
union {
u8 l;
fpreg_t fr;
log_println("Program counter: 0x%08X", pc);
+ pv = codegen_get_pv_from_pc_nocheck(pc);
+ if (pv == NULL) {
+ log_println("No java method found at location.");
+ } else {
+ m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
+ log_println(
+ "Java method: class %s, method %s, descriptor %s.",
+ m->class->name->text, m->name->text, m->descriptor->text
+ );
+ }
+
#if defined(ENABLE_DISASSEMBLER)
log_println("Printing instruction at program counter:");
disassinstr(pc);
void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pv;
- u1 *sp;
- u1 *ra;
- u1 *xpc;
- s4 type;
- ptrint val;
- java_objectheader *e;
- s4 base;
- s4 is_null;
+ stackframeinfo sfi;
+ ucontext_t *_uc;
+ mcontext_t *_mc;
+ u1 *pv;
+ u1 *sp;
+ u1 *ra;
+ u1 *xpc;
+ int type;
+ intptr_t val;
+ void *p;
+ s4 base;
+ s4 is_null;
_uc = (ucontext_t *) _p;
_mc = &_uc->uc_mcontext;
switch (xpc[0]) {
case 0x58: /* L */
case 0x50: /* ST */
+ case 0x55: /* CL (array size check on NULL array) */
base = (xpc[2] >> 4) & 0xF;
if (base == 0) {
is_null = 1;
is_null = 0;
}
break;
+ default:
+ is_null = 0;
+ break;
}
if (! is_null) {
vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
}
- pv = (u1 *)_mc->gregs[REG_PV];
+ pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
sp = (u1 *)_mc->gregs[REG_SP];
ra = xpc;
type = EXCEPTION_HARDWARE_NULLPOINTER;
val = 0;
- e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
+ /* create stackframeinfo */
+
+ stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* Handle the type. */
+
+ p = signal_handle(xpc, type, val);
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
- _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
- _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
- _mc->psw.addr = (ptrint) asm_handle_exception;
+ if (p != NULL) {
+ _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
+ _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
+ _mc->psw.addr = (intptr_t) asm_handle_exception;
+ }
+ else {
+ _mc->psw.addr = (intptr_t) xpc;
+ }
}
-void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *xpc;
- u1 *ra;
- u1 *pv;
- u1 *sp;
- s4 type;
- ptrint val;
- java_objectheader *e;
- s4 reg;
+void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
+{
+ stackframeinfo sfi;
+ ucontext_t *_uc;
+ mcontext_t *_mc;
+ u1 *xpc;
+ u1 *ra;
+ u1 *pv;
+ u1 *sp;
+ int type;
+ intptr_t val;
+ void *p;
+ s4 reg;
_uc = (ucontext_t *) _p;
_mc = &_uc->uc_mcontext;
/* bits 3-0 designate the exception type */
type = xpc[1] & 0xF;
- pv = (u1 *)_mc->gregs[REG_PV];
+ pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
sp = (u1 *)_mc->gregs[REG_SP];
val = (ptrint)_mc->gregs[reg];
- e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
+ /* create stackframeinfo */
+
+ stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
- _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
- _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
- _mc->psw.addr = (ptrint) asm_handle_exception;
+ /* Handle the type. */
+ p = signal_handle(xpc, type, val);
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ if (p != NULL) {
+ _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
+ _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
+ _mc->psw.addr = (intptr_t) asm_handle_exception;
+ }
+ else {
+ _mc->psw.addr = (intptr_t) xpc;
+ }
} else {
#if !defined(NDEBUG)
md_dump_context(xpc, _mc);
void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pv;
- u1 *sp;
- u1 *ra;
- u1 *xpc;
- u1 *pc;
- s4 r1, r2;
- s4 type;
- ptrint val;
- java_objectheader *e;
+ stackframeinfo sfi;
+ ucontext_t *_uc;
+ mcontext_t *_mc;
+ u1 *pv;
+ u1 *sp;
+ u1 *ra;
+ u1 *xpc;
+ u1 *pc;
+ int r1, r2;
+ int type;
+ intptr_t val;
+ void *p;
_uc = (ucontext_t *) _p;
_mc = &_uc->uc_mcontext;
(_mc->gregs[r1 + 1] == 0x80000000) &&
(_mc->gregs[r2] == 0xFFFFFFFF)
) {
- /* handle special case */
+ /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
/* next instruction */
pc = (u1 *)_mc->psw.addr;
/* reminder */
_mc->psw.addr = (ptrint) pc;
return;
- } else if (_mc->gregs[r2] == 0) {
+ }
+ else if (_mc->gregs[r2] == 0) {
/* division by 0 */
- pv = (u1 *)_mc->gregs[REG_PV];
+ pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
sp = (u1 *)_mc->gregs[REG_SP];
ra = xpc;
type = EXCEPTION_HARDWARE_ARITHMETIC;
val = 0;
- e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
+ /* create stackframeinfo */
+
+ stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* Handle the type. */
+
+ p = signal_handle(xpc, type, val);
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
- _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
- _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
- _mc->psw.addr = (ptrint) asm_handle_exception;
+ _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
+ _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
+ _mc->psw.addr = (intptr_t) asm_handle_exception;
return;
}
#if defined(ENABLE_THREADS)
-void thread_restartcriticalsection(ucontext_t *_uc)
+void md_critical_section_restart(ucontext_t *_uc)
{
mcontext_t *_mc;
- void *pc;
+ u1 *pc;
+ void *npc;
_mc = &_uc->uc_mcontext;
- pc = critical_find_restart_point((void *) _mc->psw.addr);
+ pc = (u1 *)_mc->psw.addr;
- if (pc != NULL)
- _mc->psw.addr = (ptrint) pc;
+ npc = critical_find_restart_point(pc);
+
+ if (npc != NULL) {
+ log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
+ _mc->psw.addr = (ptrint) npc;
+ }
}
#endif
/* on S390 the return address is located on the top of the stackframe */
- ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
+ ra = *((u1 **) (sp + framesize - 8));
return ra;
}
u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
{
- u1 base;
+ u1 base, index;
s4 offset;
u1 *pa; /* patch address */
/* get the base register of the load */
base = ra[2] >> 4;
+ index = ra[1] & 0xF;
/* check for the different calls */
- if (base == 0xd) { /* pv relative */
- /* INVOKESTATIC/SPECIAL */
+ switch (base) {
+ case 0xd:
+ /* INVOKESTATIC/SPECIAL */
- /* the offset is in the load before the load */
+
+ switch (index) {
+ case 0x0:
+ /* the offset is in the load instruction */
+ offset = ((*(u2 *)(ra + 2)) & 0xFFF) + N_PV_OFFSET;
+ break;
+ case 0x1:
+ /* the offset is in the immediate load before the load */
+ offset = *((s2 *) (ra - 2));
+ break;
+ default:
+ assert(0);
+ }
- offset = *((s2 *) (ra - 2));
+ /* add the offset to the procedure vector */
- /* add the offset to the procedure vector */
+ pa = sfi->pv + offset;
- pa = sfi->pv + offset;
- }
- else if (base == 0xc) { /* mptr relative */
- /* INVOKEVIRTUAL/INTERFACE */
+ break;
- offset = *((u2 *)(ra + 2)) & 0xFFF;
+ case 0xc:
+ /* mptr relative */
+ /* INVOKEVIRTUAL/INTERFACE */
- /* add offset to method pointer */
-
- pa = mptr + offset;
- }
- else {
- /* catch any problems */
- assert(0);
+ offset = *((u2 *)(ra + 2)) & 0xFFF;
+
+ /* return NULL if no mptr was specified (used for replacement) */
+
+ if (mptr == NULL)
+ return NULL;
+
+ /* add offset to method pointer */
+
+ pa = mptr + offset;
+ break;
+ default:
+ /* catch any problems */
+ assert(0);
+ break;
}
return pa;
Patch the given replacement point.
*******************************************************************************/
-#if 0
-void md_patch_replacement_point(rplpoint *rp)
+#if defined(ENABLE_REPLACEMENT)
+void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
{
- u8 mcode;
+ assert(0);
+}
+#endif
- /* XXX this is probably unsafe! */
+void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
+
+ uint8_t *xptr;
+ uint8_t *xpc;
+ uint8_t *sp;
+ uint8_t *pv;
+ uint8_t *ra;
+ uint8_t *handler;
+ int32_t framesize;
+ int32_t intsave;
+ int32_t fltsave;
+ int64_t *savearea;
+ int i;
+ int reg;
+ int loops = 0;
- /* save the current machine code */
- mcode = *(u8*)rp->pc;
+ /* get registers */
- /* write spinning instruction */
- *(u2*)(rp->pc) = 0xebfe;
+ xptr = *(uint8_t **)(regs + REG_ITMP1_XPTR);
+ xpc = *(uint8_t **)(regs + REG_ITMP2_XPC);
+ sp = *(uint8_t **)(regs + REG_SP);
- /* write 5th byte */
- rp->pc[4] = (rp->mcode >> 32);
- /* write first word */
- *(u4*)(rp->pc) = (u4) rp->mcode;
+ /* initialize number of calle saved int regs to restore to 0 */
+ out[0] = 0;
- /* store saved mcode */
- rp->mcode = mcode;
-
-#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
- {
- u1* u1ptr = rp->pc;
- DISASSINSTR(u1ptr);
- fflush(stdout);
- }
-#endif
-
- /* XXX if required asm_cacheflush(rp->pc,8); */
+ /* initialize number of calle saved flt regs to restore to 0 */
+ out[1] = 0;
+
+ do {
+
+ ++loops;
+
+ pv = codegen_get_pv_from_pc(xpc);
+
+ handler = exceptions_handle_exception(xptr, xpc, pv, sp);
+
+ if (handler == NULL) {
+
+ /* exception was not handled
+ * get values of calee saved registers and remove stack frame
+ */
+
+ /* read stuff from data segment */
+
+ framesize = *(int32_t *)(pv + FrameSize);
+
+ intsave = *(int32_t *)(pv + IntSave);
+ if (intsave > out[0]) {
+ out[0] = intsave;
+ }
+
+ fltsave = *(int32_t *)(pv + FltSave);
+ if (fltsave > out[1]) {
+ out[1] = fltsave;
+ }
+
+ /* pointer to register save area */
+
+ savearea = (int64_t *)(sp + framesize - 8);
+
+ /* return address */
+
+ ra = *(uint8_t **)(sp + framesize - 8);
+
+ /* restore saved registers */
+
+ for (i = 0; i < intsave; ++i) {
+ --savearea;
+ reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
+ regs[reg] = *(int32_t *)(savearea);
+ }
+
+ for (i = 0; i < fltsave; ++i) {
+ --savearea;
+ reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
+ fregs[reg] = *savearea;
+ }
+
+ /* remove stack frame */
+
+ sp += framesize;
+
+ /* new xpc is call before return address */
+
+ xpc = ra;
+
+ } else {
+ xpc = handler;
+ }
+ } while (handler == NULL);
+
+ /* write new values for registers */
+
+ *(uint8_t **)(regs + REG_ITMP1_XPTR) = xptr;
+ *(uint8_t **)(regs + REG_ITMP2_XPC) = xpc;
+ *(uint8_t **)(regs + REG_SP) = sp;
+ *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
+
+ /* maybe leaf flag */
+
+ out[2] = (loops == 1);
}
-#endif
+
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where