Merged revisions 7797-7917 via svnmerge from
[cacao.git] / src / vm / jit / s390 / md.c
index e3d250353b175726564b2aa8bd535bea699f3e68..6129ff20a1db309d808130c084cb6b6cd47a9d6b 100644 (file)
 
    Changes: Edwin Steiner
 
-   $Id: md.c 7581 2007-03-26 07:23:16Z pm $
+   $Id: md.c 7848 2007-05-01 21:40:26Z pm $
 
 */
 
-#define REG_RSP 0
-#define REG_RIP 0
-#define REG_RAX 0
-#define REG_R10 0
-#define REG_RIP 0
-#define REG_RSP 0
-#define REG_RIP 0
-#define REG_RAX 0
-#define REG_R10 0
-#define REG_RIP 0
-
-
 #define _GNU_SOURCE
 
 #include "config.h"
@@ -55,6 +43,7 @@
 #include "vm/jit/s390/md-abi.h"
 
 #if defined(ENABLE_THREADS)
+# include "threads/threads-common.h"
 # include "threads/native/threads.h"
 #endif
 
 #include <assert.h>
 #define OOPS() assert(0);
 
+/* prototypes *****************************************************************/
+
+void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
+
+void md_dump_context(u1 *pc, mcontext_t *mc);
+
 /* md_init *********************************************************************
 
    Do some machine dependent initialization.
 
 void md_init(void)
 {
-       /* nothing to do */
+       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 ************************************************************
+   Logs the machine context
+  
+*******************************************************************************/
+
+void md_dump_context(u1 *pc, mcontext_t *mc) {
+       int i;
+       
+       union {
+               u8 l;
+               fpreg_t fr;
+       } freg;
+
+       log_println("Dumping context.");
+
+       log_println("Program counter: 0x%08X", pc);
+
+#if defined(ENABLE_DISASSEMBLER)
+       log_println("Printing instruction at program counter:");
+       disassinstr(pc);
+#endif
+
+       log_println("General purpose registers:");
+
+       for (i = 0; i < 16; i++) {
+               log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
+       }
+
+       log_println("Floating point registers:");
+
+       for (i = 0; i < 16; i++) {
+               freg.fr.d = mc->fpregs.fprs[i].d;
+               log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
+       }
+
+#if defined(ENABLE_THREADS)
+       log_println("Dumping the current stacktrace:");
+       threads_print_stacktrace();
+#endif
+
+}
 
 /* md_signal_handler_sigsegv ***************************************************
 
@@ -95,35 +139,102 @@ void md_init(void)
 
 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
 {
-       ucontext_t *_uc;
-       mcontext_t *_mc;
-       u1         *sp;
-       u1         *ra;
-       u1         *xpc;
+       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;
 
        _uc = (ucontext_t *) _p;
        _mc = &_uc->uc_mcontext;
 
-       /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
-          different to the ones in <ucontext.h>. */
-
-       sp  = (u1 *) _mc->gregs[REG_RSP];
-       xpc = (u1 *) _mc->gregs[REG_RIP];
-       ra  = xpc;                          /* return address is equal to xpc     */
-
-#if 0
-       /* check for StackOverflowException */
+       xpc = (u1 *)_mc->psw.addr;
+
+       /* Check opcodes and verify it is a null pointer exception */
+
+       switch (xpc[0]) {
+               case 0x58: /* L */
+               case 0x50: /* ST */
+                       base = (xpc[2] >> 4) & 0xF;
+                       if (base == 0) {
+                               is_null = 1;
+                       } else if (_mc->gregs[base] == 0) {
+                               is_null = 1;
+                       } else {
+                               is_null = 0;
+                       }
+                       break;
+       }
 
-       threads_check_stackoverflow(sp);
+       if (! is_null) {
+#if !defined(NDEBUG)
+               md_dump_context(xpc, _mc);
 #endif
+               vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
+       }
+
+       pv = (u1 *)_mc->gregs[REG_PV];
+       sp = (u1 *)_mc->gregs[REG_SP];
+       ra = xpc;
+       type = EXCEPTION_HARDWARE_NULLPOINTER;
+       val = 0;
 
-       _mc->gregs[REG_RAX] =
-               (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc);
+       e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
 
-       _mc->gregs[REG_R10] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
-       _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
+       _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
+       _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
+       _mc->psw.addr = (ptrint) asm_handle_exception;
 }
 
+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;
+
+       _uc = (ucontext_t *) _p;
+       _mc = &_uc->uc_mcontext;
+       xpc = ra = siginfo->si_addr;
+
+       /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
+
+       if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
+
+               /* bits 7-4 contain a register holding a value */
+               reg = (xpc[1] >> 4) & 0xF;
+
+               /* bits 3-0 designate the exception type */
+               type = xpc[1] & 0xF;  
+
+               pv = (u1 *)_mc->gregs[REG_PV];
+               sp = (u1 *)_mc->gregs[REG_SP];
+               val = (ptrint)_mc->gregs[reg];
+
+               e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
+
+               _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
+               _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
+               _mc->psw.addr = (ptrint) asm_handle_exception;
+
+       } else {
+#if !defined(NDEBUG)
+               md_dump_context(xpc, _mc);
+#endif
+               vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
+       }
+}
 
 /* md_signal_handler_sigfpe ****************************************************
 
@@ -134,27 +245,73 @@ void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
 
 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
 {
-       ucontext_t  *_uc;
-       mcontext_t  *_mc;
-       u1          *sp;
-       u1          *ra;
-       u1          *xpc;
+       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;
 
        _uc = (ucontext_t *) _p;
        _mc = &_uc->uc_mcontext;
 
-       /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
-          different to the ones in <ucontext.h>. */
+       /* Instruction that raised signal */
+       xpc = siginfo->si_addr;
+
+       /* Check opcodes */
+
+       if (xpc[0] == 0x1D) { /* DR */
+
+               r1 = (xpc[1] >> 4) & 0xF;
+               r2 = xpc[1] & 0xF;
+
+               if (
+                       (_mc->gregs[r1] == 0xFFFFFFFF) &&
+                       (_mc->gregs[r1 + 1] == 0x80000000) && 
+                       (_mc->gregs[r2] == 0xFFFFFFFF)
+               ) {
+                       /* handle special case */
+                       /* next instruction */
+                       pc = (u1 *)_mc->psw.addr;
+                       /* reminder */
+                       _mc->gregs[r1] = 0;
+                       /* quotient */
+                       _mc->gregs[r1 + 1] = 0x80000000;
+                       /* continue at next instruction */
+                       _mc->psw.addr = (ptrint) pc;
 
-       sp  = (u1 *) _mc->gregs[REG_RSP];
-       xpc = (u1 *) _mc->gregs[REG_RIP];
-       ra  = xpc;                          /* return address is equal to xpc     */
+                       return;
+               } else if (_mc->gregs[r2] == 0) {
+                       /* division by 0 */
 
-       _mc->gregs[REG_RAX] =
-               (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc);
+                       pv = (u1 *)_mc->gregs[REG_PV];
+                       sp = (u1 *)_mc->gregs[REG_SP];
+                       ra = xpc;
 
-       _mc->gregs[REG_R10] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
-       _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
+                       type = EXCEPTION_HARDWARE_ARITHMETIC;
+                       val = 0;
+
+                       e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
+
+                       _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
+                       _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
+                       _mc->psw.addr = (ptrint) asm_handle_exception;
+
+                       return;
+               }
+       }
+
+       /* Could not handle signal */
+
+#if !defined(NDEBUG)
+       md_dump_context(xpc, _mc);
+#endif
+       vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
 }
 
 
@@ -180,7 +337,7 @@ void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
        /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
           different to the ones in <ucontext.h>. */
 
-       pc = (u1 *) _mc->gregs[REG_RIP];
+       pc = (u1 *) _mc->psw.addr;
 
        t->pc = pc;
 }
@@ -195,10 +352,10 @@ void thread_restartcriticalsection(ucontext_t *_uc)
 
        _mc = &_uc->uc_mcontext;
 
-       pc = critical_find_restart_point((void *) _mc->gregs[REG_RIP]);
+       pc = critical_find_restart_point((void *) _mc->psw.addr);
 
        if (pc != NULL)
-               _mc->gregs[REG_RIP] = (ptrint) pc;
+               _mc->psw.addr = (ptrint) pc;
 }
 #endif