Merged revisions 8245-8298 via svnmerge from
[cacao.git] / src / vm / jit / i386 / linux / md-os.c
index 58a7afc555ad5c41b73af9f51d5e063773976e6d..031c6774afe8aa75d8ac377a6d89c01d12536e05 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/i386/linux/md-os.c - machine dependent i386 Linux functions
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 1996-2005, 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:
-
-   $Id: md-os.c 5172 2006-07-25 15:33:58Z twisti $
+   $Id: md-os.c 8299 2007-08-13 08:41:18Z michi $
 
 */
 
 
 #include "config.h"
 
+#include <stdint.h>
 #include <ucontext.h>
 
 #include "vm/types.h"
 
+#include "vm/jit/i386/codegen.h"
+
+#include "threads/threads-common.h"
+
 #include "vm/exceptions.h"
 #include "vm/signallocal.h"
 #include "vm/stringlocal.h"
+
 #include "vm/jit/asmpart.h"
 #include "vm/jit/stacktrace.h"
 
 
 /* md_signal_handler_sigsegv ***************************************************
 
-   NullPointerException signal handler for hardware null pointer
-   check.
+   Signal handler for hardware exceptions.
 
 *******************************************************************************/
 
 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
 {
-       ucontext_t *_uc;
-       mcontext_t *_mc;
-       u1         *sp;
-       u1         *ra;
-       u1         *xpc;
+       stackframeinfo  sfi;
+       ucontext_t     *_uc;
+       mcontext_t     *_mc;
+       u1             *pv;
+       u1             *sp;
+       u1             *ra;
+       u1             *xpc;
+       u1              opc;
+       u1              mod;
+       u1              rm;
+       s4              d;
+       s4              disp;
+       ptrint          val;
+       s4              type;
+       void           *p;
 
        _uc = (ucontext_t *) _p;
        _mc = &_uc->uc_mcontext;
 
+       pv  = NULL;                 /* is resolved during stackframeinfo creation */
        sp  = (u1 *) _mc->gregs[REG_ESP];
        xpc = (u1 *) _mc->gregs[REG_EIP];
-       ra  = xpc;                          /* return address is equal to xpc     */
+       ra  = xpc;                              /* return address is equal to XPC */
+
+       /* get exception-throwing instruction */
+
+       opc = M_ALD_MEM_GET_OPC(xpc);
+       mod = M_ALD_MEM_GET_MOD(xpc);
+       rm  = M_ALD_MEM_GET_RM(xpc);
+
+       /* for values see emit_mov_mem_reg and emit_mem */
+
+       if ((opc == 0x8b) && (mod == 0) && (rm == 5)) {
+               /* this was a hardware-exception */
+
+               d    = M_ALD_MEM_GET_REG(xpc);
+               disp = M_ALD_MEM_GET_DISP(xpc);
 
-       _mc->gregs[REG_EAX] =
-               (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc);
+               /* we use the exception type as load displacement */
 
-       _mc->gregs[REG_ECX] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
-       _mc->gregs[REG_EIP] = (ptrint) asm_handle_exception;
+               type = disp;
+
+               /* ATTENTION: The _mc->gregs layout is completely crazy!  The
+                  registers are reversed starting with number 4 for REG_EDI
+                  (see /usr/include/sys/ucontext.h).  We have to convert that
+                  here. */
+
+               val = _mc->gregs[REG_EAX - d];
+       }
+       else {
+               /* this was a normal NPE */
+
+               type = EXCEPTION_HARDWARE_NULLPOINTER;
+               val  = 0;
+       }
+
+       /* 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);
+
+       /* set registers */
+
+       _mc->gregs[REG_EAX] = (intptr_t) p;
+       _mc->gregs[REG_ECX] = (intptr_t) xpc;                    /* REG_ITMP2_XPC */
+       _mc->gregs[REG_EIP] = (intptr_t) asm_handle_exception;
 }
 
 
@@ -87,25 +141,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;
+       stackframeinfo  sfi;
+       ucontext_t     *_uc;
+       mcontext_t     *_mc;
+       u1             *pv;
+       u1             *sp;
+       u1             *ra;
+       u1             *xpc;
+       s4              type;
+       ptrint          val;
+       void           *p;
 
        _uc = (ucontext_t *) _p;
        _mc = &_uc->uc_mcontext;
 
+       pv  = NULL;                 /* is resolved during stackframeinfo creation */
        sp  = (u1 *) _mc->gregs[REG_ESP];
        xpc = (u1 *) _mc->gregs[REG_EIP];
        ra  = xpc;                          /* return address is equal to xpc     */
 
-       _mc->gregs[REG_EAX] =
-               (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc);
+       /* this is an ArithmeticException */
+
+       type = EXCEPTION_HARDWARE_ARITHMETIC;
+       val  = 0;
+
+       /* create stackframeinfo */
 
-       _mc->gregs[REG_ECX] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
-       _mc->gregs[REG_EIP] = (ptrint) asm_handle_exception;
+       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_EAX] = (intptr_t) p;
+       _mc->gregs[REG_ECX] = (intptr_t) xpc;                    /* REG_ITMP2_XPC */
+       _mc->gregs[REG_EIP] = (intptr_t) asm_handle_exception;
+}
+
+
+/* md_signal_handler_sigusr1 ***************************************************
+
+   Signal handler for suspending threads.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
+void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
+{
+       ucontext_t *_uc;
+       mcontext_t *_mc;
+       u1         *pc;
+       u1         *sp;
+
+       _uc = (ucontext_t *) _p;
+       _mc = &_uc->uc_mcontext;
+
+       /* get the PC and SP for this thread */
+       pc = (u1 *) _mc->gregs[REG_EIP];
+       sp = (u1 *) _mc->gregs[REG_ESP];
+
+       /* now suspend the current thread */
+       threads_suspend_ack(pc, sp);
 }
+#endif
 
 
 /* md_signal_handler_sigusr2 ***************************************************
@@ -134,15 +236,28 @@ void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
 #endif
 
 
+/* md_critical_section_restart *************************************************
+
+   Search the critical sections tree for a matching section and set
+   the PC to the restart point, if necessary.
+
+*******************************************************************************/
+
 #if defined(ENABLE_THREADS)
-void thread_restartcriticalsection(ucontext_t *uc)
+void md_critical_section_restart(ucontext_t *_uc)
 {
-       void *critical;
+       mcontext_t *_mc;
+       u1         *pc;
+       u1         *npc;
+
+       _mc = &_uc->uc_mcontext;
+
+       pc = (u1 *) _mc->gregs[REG_EIP];
 
-       critical = critical_find_restart_point((void *) uc->uc_mcontext.gregs[REG_EIP]);
+       npc = critical_find_restart_point(pc);
 
-       if (critical)
-               uc->uc_mcontext.gregs[REG_EIP] = (ptrint) critical;
+       if (npc != NULL)
+               _mc->gregs[REG_EIP] = (ptrint) npc;
 }
 #endif