From: Michael Starzinger Date: Thu, 12 Mar 2009 14:35:16 +0000 (+0100) Subject: * src/vm/jit/trap.cpp (trap_handle): Further generalized trap handling and X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;ds=sidebyside;h=c987fe35316e518b923e13757a4399f6688c6548;p=cacao.git * src/vm/jit/trap.cpp (trap_handle): Further generalized trap handling and changed signature accordingly. * src/vm/jit/trap.hpp (trapinfo_t): Added together with signal number defines. * src/vm/jit/arm/linux/md-os.c: Simplified signal handlers. * src/vm/jit/arm/md-trap.h (MD_TRAP_COMPILER_FIXUP): Implemented. * src/vm/jit/arm/md.c (md_trap_decode): Implemented. * src/vm/jit/x86_64/linux/md-os.c: Simplified signal handlers. * src/vm/jit/x86_64/md-trap.h (MD_TRAP_COMPILER_FIXUP): Implemented. * src/vm/jit/x86_64/md.c (md_trap_decode): Implemented. --HG-- branch : new-trap-decoding --- diff --git a/src/vm/jit/arm/linux/md-os.c b/src/vm/jit/arm/linux/md-os.c index 0788aa26a..f8d29c567 100644 --- a/src/vm/jit/arm/linux/md-os.c +++ b/src/vm/jit/arm/linux/md-os.c @@ -2,7 +2,7 @@ Copyright (C) 1996-2005, 2006, 2007, 2008 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO - Copyright (C) 2008 Theobroma Systems Ltd. + Copyright (C) 2008, 2009 Theobroma Systems Ltd. This file is part of CACAO. @@ -51,72 +51,34 @@ typedef struct ucontext { #include "threads/thread.hpp" -#include "vm/os.hpp" #include "vm/signallocal.hpp" -#include "vm/vm.hpp" #include "vm/jit/asmpart.h" -#include "vm/jit/disass.h" #include "vm/jit/executionstate.h" -#include "vm/jit/patcher-common.hpp" #include "vm/jit/trap.hpp" -/* md_signal_handler_sigsegv *************************************************** - - Signal handler for hardware exceptions. - -*******************************************************************************/ - +/** + * Signal handler for hardware exceptions. + */ void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p) { - ucontext_t *_uc; - scontext_t *_sc; - u1 *pv; - u1 *sp; - u1 *ra; - u1 *xpc; - u4 mcode; - intptr_t addr; - int type; - intptr_t val; - - _uc = (ucontext_t*) _p; - _sc = &_uc->uc_mcontext; + ucontext_t* _uc = (ucontext_t*) _p; + scontext_t* _sc = &_uc->uc_mcontext; /* ATTENTION: glibc included messed up kernel headers we needed a workaround for the ucontext structure. */ - pv = (u1 *) _sc->arm_ip; - sp = (u1 *) _sc->arm_sp; - ra = (u1 *) _sc->arm_lr; /* this is correct for leafs */ - xpc = (u1 *) _sc->arm_pc; - - /* get exception-throwing instruction */ - - if (xpc == NULL) - vm_abort("md_signal_handler_sigsegv: the program counter is NULL"); - - mcode = *((s4 *) xpc); - - /* This is a NullPointerException. */ + void* xpc = (u1 *) _sc->arm_pc; - addr = *((s4 *) _sc + OFFSET(scontext_t, arm_r0)/4 + ((mcode >> 16) & 0x0f)); - type = addr; - val = 0; - - /* Handle the trap. */ - - trap_handle(type, val, pv, sp, ra, xpc, _p); + // Handle the trap. + trap_handle(TRAP_SIGSEGV, xpc, _p); } -/* md_signal_handler_sigill **************************************************** - - Illegal Instruction signal handler for hardware exception checks. - -*******************************************************************************/ - +/** + * Illegal instruction signal handler for hardware exception checks. + */ void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) { ucontext_t* _uc = (ucontext_t*) _p; @@ -125,44 +87,10 @@ void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) /* ATTENTION: glibc included messed up kernel headers we needed a workaround for the ucontext structure. */ - void* pv = (void*) _sc->arm_ip; - void* sp = (void*) _sc->arm_sp; - void* ra = (void*) _sc->arm_lr; // The RA is correct for leaf methods. void* xpc = (void*) _sc->arm_pc; - // Get the exception-throwing instruction. - uint32_t mcode = *((uint32_t*) xpc); - - // Check if the trap instruction is valid. - // TODO Move this into patcher_handler. - if (patcher_is_valid_trap_instruction_at(xpc) == false) { - // Check if the PC has been patched during our way to this - // signal handler (see PR85). - // NOTE: ARM uses 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) - return; - - // We have a problem... - log_println("md_signal_handler_sigill: Unknown illegal instruction 0x%x at 0x%x", mcode, xpc); -#if defined(ENABLE_DISASSEMBLER) - (void) disassinstr(xpc); -#endif - vm_abort("Aborting..."); - } - - int type = (mcode >> 8) & 0x0fff; - intptr_t val = *((int32_t*) _sc + OFFSET(scontext_t, arm_r0)/4 + (mcode & 0x0f)); - - if (type == TRAP_COMPILER) { - /* The XPC is the RA minus 4, because the RA points to the - instruction after the call. */ - - xpc = (void*) (((uintptr_t) ra) - 4); - } - // Handle the trap. - trap_handle(type, val, pv, sp, ra, xpc, _p); + trap_handle(TRAP_SIGILL, xpc, _p); } diff --git a/src/vm/jit/arm/md-trap.h b/src/vm/jit/arm/md-trap.h index c94a8f73c..0c7d1f499 100644 --- a/src/vm/jit/arm/md-trap.h +++ b/src/vm/jit/arm/md-trap.h @@ -54,6 +54,17 @@ enum { TRAP_COUNTDOWN = 9 }; + +/** + * Macro to fixup a compiler stub. The XPC is the RA minus 4, + * because the RA points to the instruction after the call. + */ +#define MD_TRAP_COMPILER_FIXUP(xpc, ra, sp, pv) \ + do { \ + (xpc) = (void*) (((uintptr_t) (ra)) - 4); \ + } while(0) + + #endif /* _MD_TRAP_H */ diff --git a/src/vm/jit/arm/md.c b/src/vm/jit/arm/md.c index e4549a1b7..1fecb0a83 100644 --- a/src/vm/jit/arm/md.c +++ b/src/vm/jit/arm/md.c @@ -2,6 +2,7 @@ Copyright (C) 1996-2005, 2006, 2007, 2008 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + Copyright (C) 2009 Theobroma Systems Ltd. This file is part of CACAO. @@ -32,6 +33,9 @@ #include "vm/jit/arm/md.h" #include "vm/jit/arm/md-abi.h" +#include "vm/jit/executionstate.h" +#include "vm/jit/trap.hpp" + /* md_init ********************************************************************* @@ -193,6 +197,52 @@ void *md_jit_method_patch_address(void *pv, void *ra, void *mptr) } +/** + * Decode the trap instruction at the given PC. + * + * @param trp information about trap to be filled + * @param sig signal number + * @param xpc exception PC + * @param es execution state of the machine + * @return true if trap was decoded successfully, false otherwise. + */ +bool md_trap_decode(trapinfo_t* trp, int sig, void* xpc, executionstate_t* es) +{ + // Get the exception-throwing instruction. + uint32_t mcode = *((uint32_t*) xpc); + + switch (sig) { + case TRAP_SIGILL: + // Check for valid trap instruction. + if (patcher_is_valid_trap_instruction_at(xpc)) { + trp->type = (mcode >> 8) & 0x0fff; + trp->value = es->intregs[mcode & 0x0f]; + return true; + } + return false; + + case TRAP_SIGSEGV: + { + // Sanity check for load/store instruction. +#warning Implement this! + + // Retrieve base address of load/store instruction. + uintptr_t addr = es->intregs[(mcode >> 16) & 0x0f]; + + // Check for implicit NullPointerException. + if (addr == 0) { + trp->type = TRAP_NullPointerException; + trp->value = 0; + return true; + } + } + + default: + return false; + } +} + + /** * Patch the given replacement point. */ diff --git a/src/vm/jit/trap.cpp b/src/vm/jit/trap.cpp index 903faf539..3f77c9746 100644 --- a/src/vm/jit/trap.cpp +++ b/src/vm/jit/trap.cpp @@ -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 diff --git a/src/vm/jit/trap.hpp b/src/vm/jit/trap.hpp index ce0c044c1..338921f1b 100644 --- a/src/vm/jit/trap.hpp +++ b/src/vm/jit/trap.hpp @@ -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. @@ -30,6 +31,34 @@ #include +#include "vm/options.h" + +#include "vm/jit/executionstate.h" + + +/** + * Contains information about a decoded trap instruction. + */ +typedef struct trapinfo_t { + int type; ///< Specific trap type (see md-trap.h). + intptr_t value; ///< Value (numeric or address) passed with the trap. +} trapinfo_t; + + +/** + * Trap signal number defines. Use these instead of the signal + * numbers provided by your specific OS. + */ +enum { + TRAP_SIGRESERVED = 0, + TRAP_SIGSEGV = 1, + TRAP_SIGILL = 2, + TRAP_SIGTRAP = 3, + TRAP_SIGFPE = 4, + TRAP_SIGEND +}; + + #ifdef __cplusplus extern "C" { #endif @@ -41,8 +70,10 @@ extern "C" { /* function prototypes ********************************************************/ -void trap_init(void); -void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xpc, void *context); +void trap_init(void); +void trap_handle(int sig, void* xpc, void* context); + +bool md_trap_decode(trapinfo_t* trp, int sig, void* xpc, executionstate_t* es); #ifdef __cplusplus } diff --git a/src/vm/jit/x86_64/freebsd/md-os.c b/src/vm/jit/x86_64/freebsd/md-os.c index fd9244d33..62ac3da95 100644 --- a/src/vm/jit/x86_64/freebsd/md-os.c +++ b/src/vm/jit/x86_64/freebsd/md-os.c @@ -2,6 +2,7 @@ Copyright (C) 2007, 2008 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + Copyright (C) 2009 Theobroma Systems Ltd. This file is part of CACAO. diff --git a/src/vm/jit/x86_64/linux/md-os.c b/src/vm/jit/x86_64/linux/md-os.c index ca42a1926..ad8fbd9fd 100644 --- a/src/vm/jit/x86_64/linux/md-os.c +++ b/src/vm/jit/x86_64/linux/md-os.c @@ -39,251 +39,65 @@ #include "threads/thread.hpp" -#include "vm/jit/builtin.hpp" #include "vm/signallocal.hpp" #include "vm/jit/asmpart.h" #include "vm/jit/executionstate.h" #include "vm/jit/trap.hpp" -#include "vm/jit/stacktrace.hpp" -/* md_signal_handler_sigsegv *************************************************** - - Signal handler for hardware exception. - -*******************************************************************************/ - +/** + * Signal handler for hardware exception. + */ void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p) { - ucontext_t *_uc; - mcontext_t *_mc; - void *pv; - u1 *sp; - u1 *ra; - u1 *xpc; - u1 opc; - u1 mod; - u1 rm; - s4 d; - s4 disp; - int type; - intptr_t val; - void *p; - - _uc = (ucontext_t *) _p; - _mc = &_uc->uc_mcontext; + ucontext_t* _uc = (ucontext_t *) _p; + mcontext_t* _mc = &_uc->uc_mcontext; /* ATTENTION: Don't use CACAO's internal REG_* defines as they are different to the ones in . */ - pv = NULL; /* is resolved during stackframeinfo creation */ - 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 */ - - threads_check_stackoverflow(sp); -#endif - - /* 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 == 4)) { - /* this was a hardware-exception */ - - d = M_ALD_MEM_GET_REG(xpc); - disp = M_ALD_MEM_GET_DISP(xpc); - - /* we use the exception type as load displacement */ - - type = disp; - - /* XXX FIX ME! */ - - /* ATTENTION: The _mc->gregs layout is even worse than on - i386! See /usr/include/sys/ucontext.h. We need a - switch-case here... */ - - switch (d) { - case 0: /* REG_RAX == 13 */ - d = REG_RAX; - break; - case 1: /* REG_RCX == 14 */ - d = REG_RCX; - break; - case 2: /* REG_RDX == 12 */ - d = REG_RDX; - break; - case 3: /* REG_RBX == 11 */ - d = REG_RBX; - break; - case 4: /* REG_RSP == 15 */ - d = REG_RSP; - break; - case 5: /* REG_RBP == 10 */ - d = REG_RBP; - break; - case 6: /* REG_RSI == 9 */ - d = REG_RSI; - break; - case 7: /* REG_RDI == 8 */ - d = REG_RDI; - break; - case 8: /* REG_R8 == 0 */ - case 9: /* REG_R9 == 1 */ - case 10: /* REG_R10 == 2 */ - case 11: /* REG_R11 == 3 */ - case 12: /* REG_R12 == 4 */ - case 13: /* REG_R13 == 5 */ - case 14: /* REG_R14 == 6 */ - case 15: /* REG_R15 == 7 */ - d = d - 8; - break; - } - - val = _mc->gregs[d]; - - if (type == TRAP_COMPILER) { - /* The PV from the compiler stub is equal to the XPC. */ - - pv = xpc; - - /* We use a framesize of zero here because the call pushed - the return addres onto the stack. */ - - ra = md_stacktrace_get_returnaddress(sp, 0); - - /* Skip the RA on the stack. */ - - sp = sp + 1 * SIZEOF_VOID_P; - - /* The XPC is the RA minus 1, because the RA points to the - instruction after the call. */ - - xpc = ra - 3; - } - } - else { - /* this was a normal NPE */ - - type = TRAP_NullPointerException; - val = 0; - } - - /* Handle the trap. */ - - p = trap_handle(type, val, pv, sp, ra, xpc, _p); - - /* Set registers. */ + void* xpc = (void*) _mc->gregs[REG_RIP]; - if (type == TRAP_COMPILER) { - if (p == NULL) { - _mc->gregs[REG_RSP] = (uintptr_t) sp; /* Remove RA from stack. */ - } - } + // Handle the trap. + trap_handle(TRAP_SIGSEGV, xpc, _p); } -/* md_signal_handler_sigfpe **************************************************** - - ArithmeticException signal handler for hardware divide by zero - check. - -*******************************************************************************/ - +/** + * ArithmeticException signal handler for hardware divide by zero + * check. + */ 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; - int type; - intptr_t val; - - _uc = (ucontext_t *) _p; - _mc = &_uc->uc_mcontext; + ucontext_t* _uc = (ucontext_t *) _p; + mcontext_t* _mc = &_uc->uc_mcontext; /* ATTENTION: Don't use CACAO's internal REG_* defines as they are different to the ones in . */ - pv = NULL; - sp = (u1 *) _mc->gregs[REG_RSP]; - xpc = (u1 *) _mc->gregs[REG_RIP]; - ra = xpc; /* return address is equal to xpc */ - - /* This is an ArithmeticException. */ - - type = TRAP_ArithmeticException; - val = 0; - - /* Handle the trap. */ + void* xpc = (void*) _mc->gregs[REG_RIP]; - trap_handle(type, val, pv, sp, ra, xpc, _p); + // Handle the trap. + trap_handle(TRAP_SIGFPE, xpc, _p); } -/* md_signal_handler_sigill **************************************************** - - Signal handler for patchers. - -*******************************************************************************/ - +/** + * Signal handler for patchers. + */ void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) { - ucontext_t *_uc; - mcontext_t *_mc; - u1 *pv; - u1 *sp; - u1 *ra; - u1 *xpc; - int type; - intptr_t val; - - _uc = (ucontext_t *) _p; - _mc = &_uc->uc_mcontext; + ucontext_t* _uc = (ucontext_t *) _p; + mcontext_t* _mc = &_uc->uc_mcontext; /* ATTENTION: Don't use CACAO's internal REG_* defines as they are different to the ones in . */ - pv = NULL; - sp = (u1 *) _mc->gregs[REG_RSP]; - xpc = (u1 *) _mc->gregs[REG_RIP]; - ra = xpc; /* return address is equal to xpc */ - - // Check if the trap instruction is valid. - // TODO Move this into patcher_handler. - if (patcher_is_valid_trap_instruction_at(xpc) == false) { - // Check if the PC has been patched during our way to this - // signal handler (see PR85). - if (patcher_is_patched_at(xpc) == true) - return; - - // We have a problem... - log_println("md_signal_handler_sigill: Unknown illegal instruction at 0x%lx", xpc); -#if defined(ENABLE_DISASSEMBLER) - (void) disassinstr(xpc); -#endif - vm_abort("Aborting..."); - } - - /* This is a patcher. */ - - type = TRAP_PATCHER; - val = 0; - - /* Handle the trap. */ + void* xpc = (void*) _mc->gregs[REG_RIP]; - trap_handle(type, val, pv, sp, ra, xpc, _p); + // Handle the trap. + trap_handle(TRAP_SIGILL, xpc, _p); } @@ -362,6 +176,9 @@ void md_executionstate_read(executionstate_t *es, void *context) _uc = (ucontext_t *) context; _mc = &_uc->uc_mcontext; + /* ATTENTION: Don't use CACAO's internal REG_* defines as they are + different to the ones in . */ + /* read special registers */ es->pc = (u1 *) _mc->gregs[REG_RIP]; es->sp = (u1 *) _mc->gregs[REG_RSP]; @@ -433,6 +250,9 @@ void md_executionstate_write(executionstate_t *es, void *context) _uc = (ucontext_t *) context; _mc = &_uc->uc_mcontext; + /* ATTENTION: Don't use CACAO's internal REG_* defines as they are + different to the ones in . */ + /* write integer registers */ for (i = 0; i < INT_REG_CNT; i++) { /* XXX FIX ME! */ diff --git a/src/vm/jit/x86_64/md-trap.h b/src/vm/jit/x86_64/md-trap.h index c78e31b95..8b09e3c6e 100644 --- a/src/vm/jit/x86_64/md-trap.h +++ b/src/vm/jit/x86_64/md-trap.h @@ -62,6 +62,25 @@ enum { TRAP_END }; + +/** + * Macro to fixup a compiler stub. + * PV : The PV from the compiler stub is equal to the XPC. + * RA : We use a framesize of zero here because the call pushed + * the return addres onto the stack. + * SP : Skip the RA on the stack. + * XPC: The XPC is the RA minus 1, because the RA points to the + * instruction after the call. + */ +#define MD_TRAP_COMPILER_FIXUP(xpc, ra, sp, pv) \ + do { \ + (pv) = (xpc); \ + (ra) = md_stacktrace_get_returnaddress((sp), 0); \ + (sp) = (void*) (((uintptr_t) (sp)) + 1 * SIZEOF_VOID_P); \ + (xpc) = (void*) (((uintptr_t) (ra)) - 3); \ + } while(0) + + #endif /* _MD_TRAP_H */ diff --git a/src/vm/jit/x86_64/md.c b/src/vm/jit/x86_64/md.c index 586550cfd..cf682e09f 100644 --- a/src/vm/jit/x86_64/md.c +++ b/src/vm/jit/x86_64/md.c @@ -2,6 +2,7 @@ Copyright (C) 1996-2005, 2006, 2007, 2008 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + Copyright (C) 2009 Theobroma Systems Ltd. This file is part of CACAO. @@ -29,12 +30,15 @@ #include #include +#include "vm/jit/x86_64/codegen.h" #include "vm/jit/x86_64/md-abi.h" #include "vm/vm.hpp" #include "vm/jit/codegen-common.hpp" +#include "vm/jit/executionstate.h" #include "vm/jit/jit.hpp" +#include "vm/jit/trap.hpp" /* md_init ********************************************************************* @@ -135,6 +139,73 @@ void *md_jit_method_patch_address(void *pv, void *ra, void *mptr) } +/** + * Decode the trap instruction at the given PC. + * + * @param trp information about trap to be filled + * @param sig signal number + * @param xpc exception PC + * @param es execution state of the machine + * @return true if trap was decoded successfully, false otherwise. + */ +bool md_trap_decode(trapinfo_t* trp, int sig, void* _xpc, executionstate_t* es) +{ + uint8_t* xpc = (uint8_t*) _xpc; + +#if 0 + // Check for StackOverflowException. + threads_check_stackoverflow(sp); +#endif + + switch (sig) { + case TRAP_SIGFPE: + // Check for ArithmeticException. + trp->type = TRAP_ArithmeticException; + trp->value = 0; + return true; + + case TRAP_SIGILL: + // Check for valid trap instruction. + if (patcher_is_valid_trap_instruction_at(xpc)) { + trp->type = TRAP_PATCHER; + trp->value = 0; + return true; + } + return false; + + case TRAP_SIGSEGV: + { + // Get exception-throwing instruction. + uint8_t opc = M_ALD_MEM_GET_OPC(xpc); + uint8_t mod = M_ALD_MEM_GET_MOD(xpc); + uint8_t rm = M_ALD_MEM_GET_RM(xpc); + + // Check for hardware exception, for values + // see emit_mov_mem_reg and emit_mem. + if ((opc == 0x8b) && (mod == 0) && (rm == 4)) { + int32_t d = M_ALD_MEM_GET_REG(xpc); + int32_t disp = M_ALD_MEM_GET_DISP(xpc); + + // We use the exception type as load displacement. + trp->type = disp; + trp->value = es->intregs[d]; + return true; + } + + // Default case is a normal NullPointerException. + else { + trp->type = TRAP_NullPointerException; + trp->value = 0; + return true; + } + } + + default: + return false; + } +} + + /* md_patch_replacement_point ************************************************** Patch the given replacement point.