* src/vm/jit/trap.cpp (trap_handle): Further generalized trap handling and
[cacao.git] / src / vm / jit / trap.cpp
index 903faf539151f9ef3b723176a3767038333c4f4d..3f77c9746e90b59ce5b2b6ef4187dcd356595889 100644 (file)
@@ -2,6 +2,7 @@
 
    Copyright (C) 2008
    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+   Copyright (C) 2009 Theobroma Systems Ltd.
 
    This file is part of CACAO.
 
@@ -52,6 +53,7 @@
 #include "vm/jit/patcher-common.hpp"
 #include "vm/jit/replace.hpp"
 #include "vm/jit/stacktrace.hpp"
+#include "vm/jit/trap.hpp"
 
 #ifdef __cplusplus
 extern "C" {
@@ -97,28 +99,26 @@ void trap_init(void)
  * Handles the signal which is generated by trap instructions, caught
  * by a signal handler and calls the correct function.
  *
- * @param type trap number
- * @param 
+ * @param sig signal number
+ * @param xpc exception PC
+ * @param context pointer to OS dependent machine context
  */
-void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xpc, void *context)
+void trap_handle(int sig, void *xpc, void *context)
 {
        executionstate_t es;
        stackframeinfo_t sfi;
+       trapinfo_t       trp;
 
-#if !defined(NDEBUG)
-       if (opt_TraceTraps)
-               log_println("[trap_handle: type=%d, val=%p, pv=%p, sp=%p, ra=%p, xpc=%p]", type, val, pv, sp, ra, xpc);
-#endif
-       
-#if defined(ENABLE_VMLOG)
-       vmlog_cacao_signl_type(type);
-#endif
-
-       /* Prevent compiler warnings. */
-
+       // Prevent compiler warnings.
        java_handle_t* o = NULL;
        methodinfo*    m = NULL;
 
+#if !defined(NDEBUG)
+       // Sanity checking the XPC.
+       if (xpc == NULL)
+               vm_abort("trap_handle: The program counter is NULL!");
+#endif
+
 #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
 # if !defined(NDEBUG)
        /* Perform a sanity check on our execution state functions. */
@@ -131,8 +131,8 @@ void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xp
        es.code = NULL;
        md_executionstate_read(&es, context);
 
-//# define TRAPS_VERBOSE
-# if !defined(NDEBUG) && defined(TRAPS_VERBOSE)
+//# define TRAP_TRACE_VERBOSE
+# if !defined(NDEBUG) && defined(TRAP_TRACE_VERBOSE)
        /* Dump contents of execution state */
 
        if (opt_TraceTraps) {
@@ -142,6 +142,39 @@ void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xp
 # endif
 #endif
 
+       // Extract information from executionstate
+       void* pv = es.pv;  // Maybe null, resolved during stackframeinfo creation.
+       void* sp = es.sp;
+#if defined(__I386__) || defined(__X86_64__)
+       void* ra = xpc;  // Return address is equal to XPC.
+#else
+       void* ra = es.ra;  // This is correct for leafs.
+#endif
+
+       // Decode machine-dependent trap instruction.
+       bool decode_result = md_trap_decode(&trp, sig, xpc, &es);
+
+       // Check if the trap instruction is valid and was decoded
+       // successfully.
+       if (!decode_result) {
+               // Check if the PC has been patched during our way to this
+               // trap handler (see PR85).
+               // NOTE: Some archs use SIGILL for other traps too, but it's OK to
+               // do this check anyway because it will fail.
+               if (patcher_is_patched_at(xpc) == true) {
+                       // XXX remove this debug output!
+                       log_println("trap_handle: Detected patcher race condition (PR85) at %p", xpc);
+                       return;
+               }
+
+               // We have a problem...
+               vm_abort_disassemble(xpc, 1, "trap_handle: Unknown trap instruction at %p", xpc);
+       }
+
+       // For convenience only.
+       int      type = trp.type;
+       intptr_t val  = trp.value;
+
        /* Do some preparations before we enter the nativeworld. */
        /* BEFORE: creating stackframeinfo */
 
@@ -153,6 +186,12 @@ void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xp
                break;
 
        case TRAP_COMPILER:
+               /* We need to fixup the XPC, SP and RA here because they
+                  all might point into the compiler stub instead of the
+                  calling method. */
+
+               MD_TRAP_COMPILER_FIXUP(xpc, ra, sp, pv);
+
                /* In this case the passed PV points to the compiler stub.  We
                   get the methodinfo pointer here and set PV to NULL so
                   stacktrace_stackframeinfo_add determines the PV for the
@@ -160,6 +199,7 @@ void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xp
 
                m  = code_get_methodinfo_for_pv(pv);
                pv = NULL;
+
                break;
 
        default:
@@ -167,6 +207,16 @@ void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xp
                break;
        }
 
+#if !defined(NDEBUG)
+       // Trace this trap.
+       if (opt_TraceTraps)
+               log_println("[trap_handle: sig=%d, type=%d, val=%p, pv=%p, sp=%p, ra=%p, xpc=%p]", sig, type, val, pv, sp, ra, xpc);
+#endif
+
+#if defined(ENABLE_VMLOG)
+       vmlog_cacao_signl_type(type);
+#endif
+
        /* Fill and add a stackframeinfo. */
 
        stacktrace_stackframeinfo_add(&sfi, pv, sp, ra, xpc);
@@ -234,20 +284,7 @@ void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xp
 
                /* If that does not work, print more debug info. */
 
-               log_println("signal_handle: unknown hardware exception type %d", type);
-
-#if SIZEOF_VOID_P == 8
-               log_println("PC=0x%016lx", xpc);
-#else
-               log_println("PC=0x%08x", xpc);
-#endif
-
-#if defined(ENABLE_DISASSEMBLER)
-               log_println("machine instruction at PC:");
-               disassinstr((uint8_t*) xpc);
-#endif
-
-               vm_abort("Exiting...");
+               vm_abort_disassemble(xpc, 1, "trap_handle: Unknown hardware exception type %d", type);
 
                /* keep compiler happy */
 
@@ -279,9 +316,13 @@ void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xp
                p = exceptions_get_and_clear_exception();
                assert(p != NULL);
 
+               // Remove RA from stack on some archs.
+
+               es.sp = (uint8_t*) sp;
+
                // Get and set the PV from the parent Java method.
 
-               es.pv = (uint8_t *) md_codegen_get_pv_from_pc(ra);
+               es.pv = (uint8_t*) md_codegen_get_pv_from_pc(ra);
 
                // Now fall-through to default exception handling.
 
@@ -312,7 +353,7 @@ void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xp
 
        md_executionstate_write(&es, context);
 
-# if !defined(NDEBUG) && defined(TRAPS_VERBOSE)
+# if !defined(NDEBUG) && defined(TRAP_TRACE_VERBOSE)
        /* Dump contents of execution state */
 
        if (opt_TraceTraps) {
@@ -321,14 +362,6 @@ void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xp
        }
 # endif
 #endif
-
-       /* Unwrap and return the exception object. */
-       /* AFTER: removing stackframeinfo */
-
-       if (type == TRAP_COMPILER)
-               return entry;
-       else
-               return LLNI_UNWRAP(p);
 }
 
 #ifdef __cplusplus