LCOV - code coverage report
Current view: top level - vm/jit - trap.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 79 95 83.2 %
Date: 2015-06-10 18:10:59 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* src/vm/jit/trap.cpp - hardware traps
       2             : 
       3             :    Copyright (C) 1996-2013
       4             :    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
       5             :    Copyright (C) 2009 Theobroma Systems Ltd.
       6             : 
       7             :    This file is part of CACAO.
       8             : 
       9             :    This program is free software; you can redistribute it and/or
      10             :    modify it under the terms of the GNU General Public License as
      11             :    published by the Free Software Foundation; either version 2, or (at
      12             :    your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful, but
      15             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :    General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program; if not, write to the Free Software
      21             :    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      22             :    02110-1301, USA.
      23             : 
      24             : */
      25             : 
      26             : 
      27             : #include "config.h"
      28             : 
      29             : #include <stdint.h>
      30             : 
      31             : /* Include machine dependent trap stuff. */
      32             : 
      33             : #include "md.hpp"
      34             : #include "md-trap.hpp"
      35             : 
      36             : #include "mm/memory.hpp"
      37             : 
      38             : #include "native/llni.hpp"
      39             : 
      40             : #include "toolbox/logging.hpp"
      41             : 
      42             : #include "vm/exceptions.hpp"
      43             : #include "vm/options.hpp"
      44             : #include "vm/os.hpp"
      45             : #include "vm/vm.hpp"
      46             : 
      47             : #include "vm/jit/code.hpp"
      48             : #include "vm/jit/disass.hpp"
      49             : #include "vm/jit/executionstate.hpp"
      50             : #include "vm/jit/jit.hpp"
      51             : #include "vm/jit/methodtree.hpp"
      52             : #include "vm/jit/patcher-common.hpp"
      53             : #include "vm/jit/replace.hpp"
      54             : #include "vm/jit/stacktrace.hpp"
      55             : #include "vm/jit/trap.hpp"
      56             : 
      57             : #if defined(__S390__)
      58             : #include "vm/jit/s390/codegen.hpp"
      59             : #else
      60             : #define N_PV_OFFSET 0
      61             : #endif
      62             : 
      63             : /**
      64             :  * Mmap the first memory page to support hardware exceptions and check
      65             :  * the maximum hardware trap displacement on the architectures where
      66             :  * it is required (TRAP_INSTRUCTION_IS_LOAD defined to 1).
      67             :  */
      68         163 : void trap_init(void)
      69             : {
      70         163 :         TRACESUBSYSTEMINITIALIZATION("trap_init");
      71             : 
      72             :         /* If requested we mmap a memory page at address 0x0,
      73             :            so our hardware-exceptions work. */
      74             : 
      75         163 :         if (opt_AlwaysMmapFirstPage) {
      76           0 :                 int pagesize = os::getpagesize();
      77           0 :                 (void) os::mmap_anonymous(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED);
      78             :         }
      79             : 
      80             : #if !defined(TRAP_INSTRUCTION_IS_LOAD)
      81             : # error TRAP_INSTRUCTION_IS_LOAD is not defined in your md-trap.h
      82             : #endif
      83             : 
      84             : #if TRAP_INSTRUCTION_IS_LOAD == 1
      85             :         /* Check if we get into trouble with our hardware-exceptions. */
      86             : 
      87         163 :         if (TRAP_END > OFFSET(java_bytearray_t, data))
      88           0 :                 vm_abort("trap_init: maximum hardware trap displacement is greater than the array-data offset: %d > %d", TRAP_END, OFFSET(java_bytearray_t, data));
      89             : #endif
      90         163 : }
      91             : 
      92             : 
      93             : /**
      94             :  * Handles the signal which is generated by trap instructions, caught
      95             :  * by a signal handler and calls the correct function.
      96             :  *
      97             :  * @param sig signal number
      98             :  * @param xpc exception PC
      99             :  * @param context pointer to OS dependent machine context
     100             :  */
     101      197445 : void trap_handle(int sig, void *xpc, void *context)
     102             : {
     103             :         executionstate_t es;
     104             :         stackframeinfo_t sfi;
     105             :         trapinfo_t       trp;
     106             : 
     107             : #if !defined(NDEBUG)
     108             :         // Sanity checking the XPC.
     109      197445 :         if (xpc == NULL)
     110           0 :                 vm_abort("trap_handle: The program counter is NULL!");
     111             : #endif
     112             : 
     113             : #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__)
     114             : # if !defined(NDEBUG)
     115             :         /* Perform a sanity check on our execution state functions. */
     116             : 
     117      197445 :         executionstate_sanity_check(context);
     118             : # endif
     119             : 
     120             :         /* Read execution state from current context. */
     121             : 
     122      197445 :         es.code = NULL;
     123      197445 :         md_executionstate_read(&es, context);
     124             : 
     125             : //# define TRAP_TRACE_VERBOSE
     126             : # if !defined(NDEBUG) && defined(TRAP_TRACE_VERBOSE)
     127             :         /* Dump contents of execution state */
     128             : 
     129             :         if (opt_TraceTraps) {
     130             :                 log_println("[trap_handle: dumping execution state BEFORE ...]");
     131             :                 executionstate_println(&es);
     132             :         }
     133             : # endif
     134             : #endif
     135             : 
     136             :         // Extract information from executionstate
     137      197445 :         void* pv = es.pv;  // Maybe null, resolved during stackframeinfo creation.
     138      197445 :         void* sp = es.sp;
     139             : #if defined(__I386__) || defined(__X86_64__)
     140      197445 :         void* ra = xpc;  // Return address is equal to XPC.
     141             : #else
     142             :         void* ra = es.ra;  // This is correct for leafs.
     143             : #endif
     144             : 
     145             :         // Decode machine-dependent trap instruction.
     146      197445 :         bool decode_result = md_trap_decode(&trp, sig, xpc, &es);
     147             : 
     148             :         // Check if the trap instruction is valid and was decoded
     149             :         // successfully.
     150      197445 :         if (!decode_result) {
     151             :                 // Check if the PC has been patched during our way to this
     152             :                 // trap handler (see PR85).
     153             :                 // NOTE: Some archs use SIGILL for other traps too, but it's OK to
     154             :                 // do this check anyway because it will fail.
     155           1 :                 if (patcher_is_patched_at(xpc) == true) {
     156           1 :                         if (opt_PrintWarnings)
     157           0 :                                 log_println("trap_handle: Detected patcher race condition (PR85) at %p", xpc);
     158           1 :                         return;
     159             :                 }
     160             : 
     161             :                 // We have a problem...
     162           0 :                 vm_abort_disassemble(xpc, 1, "trap_handle: Unknown trap instruction at %p", xpc);
     163             :         }
     164             : 
     165             :         // For convenience only.
     166      197444 :         int      type = trp.type;
     167      197444 :         intptr_t val  = trp.value;
     168             : 
     169             :         /* Do some preparations before we enter the nativeworld. */
     170             :         /* BEFORE: creating stackframeinfo */
     171             : 
     172             :         // Prevent compiler warnings.
     173      197444 :         int32_t        index = 0;
     174      197444 :         java_handle_t* o     = NULL;
     175      197444 :         methodinfo*    m     = NULL;
     176             : 
     177      197444 :         switch (type) {
     178             :         case TRAP_ArrayIndexOutOfBoundsException:
     179             :                 /* Get the index into the array causing the exception. */
     180             : 
     181          25 :                 index = (int32_t) val;
     182          25 :                 break;
     183             : 
     184             :         case TRAP_ClassCastException:
     185             :                 /* Wrap the value into a handle, as it is a reference. */
     186             : 
     187          10 :                 o = LLNI_WRAP((java_object_t *) val);
     188          10 :                 break;
     189             : 
     190             :         case TRAP_COMPILER:
     191             :                 /* We need to fixup the XPC, SP and RA here because they
     192             :                    all might point into the compiler stub instead of the
     193             :                    calling method. */
     194             : 
     195      126224 :                 MD_TRAP_COMPILER_FIXUP(xpc, ra, sp, pv);
     196             : 
     197             :                 /* In this case the passed PV points to the compiler stub.  We
     198             :                    get the methodinfo pointer here and set PV to NULL so
     199             :                    stacktrace_stackframeinfo_add determines the PV for the
     200             :                    parent Java method. */
     201             : 
     202      126224 :                 m  = code_get_methodinfo_for_pv(pv);
     203      126224 :                 pv = NULL;
     204             : 
     205             :                 break;
     206             : 
     207             :         default:
     208             :                 /* do nothing */
     209             :                 break;
     210             :         }
     211             : 
     212             : #if !defined(NDEBUG)
     213             :         // Trace this trap.
     214      197444 :         if (opt_TraceTraps)
     215           0 :                 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);
     216             : #endif
     217             : 
     218             :         /* Fill and add a stackframeinfo. */
     219             : 
     220      197444 :         stacktrace_stackframeinfo_add(&sfi, pv, sp, ra, xpc);
     221             : 
     222             :         /* Get resulting exception (or pointer to compiled method). */
     223             : 
     224             :         java_handle_t* p;
     225      197444 :         void*          entry = 0;
     226      197444 :         bool           was_patched = false;
     227             : #if defined(ENABLE_REPLACEMENT)
     228             :         bool           was_replaced;
     229             : #endif
     230             : 
     231      197444 :         switch (type) {
     232             :         case TRAP_NullPointerException:
     233          22 :                 p = exceptions_new_nullpointerexception();
     234          22 :                 break;
     235             : 
     236             :         case TRAP_ArithmeticException:
     237           8 :                 p = exceptions_new_arithmeticexception();
     238           8 :                 break;
     239             : 
     240             :         case TRAP_ArrayIndexOutOfBoundsException:
     241          25 :                 p = exceptions_new_arrayindexoutofboundsexception(index);
     242          25 :                 break;
     243             : 
     244             :         case TRAP_ArrayStoreException:
     245           6 :                 p = exceptions_new_arraystoreexception();
     246           6 :                 break;
     247             : 
     248             :         case TRAP_ClassCastException:
     249          10 :                 p = exceptions_new_classcastexception(o);
     250          10 :                 break;
     251             : 
     252             :         case TRAP_CHECK_EXCEPTION:
     253           3 :                 p = exceptions_fillinstacktrace();
     254           3 :                 break;
     255             : 
     256             :         case TRAP_PATCHER:
     257       71146 :                 p = NULL;
     258             : #if defined(ENABLE_REPLACEMENT)
     259             :                 was_replaced = replace_handler((uint8_t*) xpc, &es);
     260             :                 if (was_replaced)
     261             :                         break;
     262             : #endif
     263       71146 :                 was_patched = patcher_handler((uint8_t*) xpc);
     264       71146 :                 break;
     265             : 
     266             :         case TRAP_COMPILER:
     267      126224 :                 p = NULL;
     268      126224 :                 entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
     269      126224 :                 break;
     270             : 
     271             : #if defined(__I386__) && defined(ENABLE_REPLACEMENT)
     272             : # warning Port the below stuff to use the patching subsystem.
     273             :         case TRAP_COUNTDOWN:
     274             :                 p = NULL;
     275             :                 (void) replace_handler((uint8_t*) xpc - 13, &es);
     276             :                 break;
     277             : #endif
     278             : 
     279             :         default:
     280             :                 /* Let's try to get a backtrace. */
     281             : 
     282           0 :                 (void) methodtree_find(xpc);
     283             : 
     284             :                 /* If that does not work, print more debug info. */
     285             : 
     286           0 :                 vm_abort_disassemble(xpc, 1, "trap_handle: Unknown hardware exception type %d", type);
     287             : 
     288             :                 /* keep compiler happy */
     289             : 
     290           0 :                 p = NULL;
     291             :         }
     292             : 
     293             :         /* Remove stackframeinfo. */
     294             : 
     295      197444 :         stacktrace_stackframeinfo_remove(&sfi);
     296             : 
     297             : #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__)
     298             :         /* Update execution state and set registers. */
     299             :         /* AFTER: removing stackframeinfo */
     300             : 
     301      197444 :         switch (type) {
     302             :         case TRAP_COMPILER:
     303             :                 // The normal case for a compiler trap is to jump directly to
     304             :                 // the newly compiled method.
     305             : 
     306      126224 :                 if (entry != NULL) {
     307      126220 :                         es.pc = (uint8_t *) (uintptr_t) entry;
     308             :                         // The s390 executionstate offsets pv, so we need to
     309             :                         // compensate here.
     310      126220 :                         es.pv = (uint8_t *) (uintptr_t) entry - N_PV_OFFSET;
     311      126220 :                         break;
     312             :                 }
     313             : 
     314             :                 // In case of an exception during JIT compilation, we fetch
     315             :                 // the exception here and proceed with exception handling.
     316             : 
     317           4 :                 p = exceptions_get_and_clear_exception();
     318           4 :                 assert(p != NULL);
     319             : 
     320             :                 // Remove RA from stack on some archs.
     321             : 
     322           4 :                 es.sp = (uint8_t*) sp;
     323             : 
     324             :                 // Get and set the PV from the parent Java method.
     325             : 
     326           4 :                 es.pv = (uint8_t*) md_codegen_get_pv_from_pc(ra) - N_PV_OFFSET;
     327             : 
     328             :                 // Now fall-through to default exception handling.
     329             : 
     330           4 :                 goto trap_handle_exception;
     331             : 
     332             :         case TRAP_PATCHER:
     333             : #if defined(ENABLE_REPLACEMENT)
     334             :                 // If on-stack-replacement suceeded, we are not allowed to touch
     335             :                 // the execution state. We assume that there was no exception.
     336             : 
     337             :                 if (was_replaced) {
     338             :                         java_object_t *e = exceptions_get_exception();
     339             :                         if (e)
     340             :                                 exceptions_print_stacktrace();
     341             :                         assert(e == NULL);
     342             :                         break;
     343             :                 }
     344             : #endif
     345             : 
     346             :                 // The normal case for a patcher trap is to continue execution at
     347             :                 // the trap instruction. On some archs the PC may point after the
     348             :                 // trap instruction, so we reset it here.
     349             : 
     350       71146 :                 if (was_patched) {
     351       71133 :                         java_object_t *e = exceptions_get_exception();
     352       71133 :                         if (e)
     353           0 :                                 exceptions_print_stacktrace();
     354       71133 :                         assert(e == NULL);
     355       71133 :                         es.pc = (uint8_t *) (uintptr_t) xpc;
     356       71133 :                         break;
     357             :                 }
     358             : 
     359             :                 // In case patching was not successful, we try to fetch the pending
     360             :                 // exception here.
     361             : 
     362          13 :                 p = exceptions_get_and_clear_exception();
     363             : 
     364             :                 // If there is no pending exception, we continue execution behind
     365             :                 // the position still in need of patching. Normally this would
     366             :                 // indicate an error in the patching subsystem, but others might
     367             :                 // want to piggyback patchers and we want to be able to provide
     368             :                 // "reusable trap points" and avoid inifinite loops here. This is
     369             :                 // especially useful to implement breakpoints or profiling points
     370             :                 // of any kind. So before changing the trap logic, think about
     371             :                 // utilizing the patching subsystem on your quest. :)
     372             : 
     373          13 :                 if (p == NULL) {
     374             : #if !defined(NDEBUG)
     375           0 :                         if (opt_PrintWarnings)
     376           0 :                                 log_println("trap_handle: Detected reusable trap at %p", xpc);
     377             : #endif
     378           0 :                         es.pc = (uint8_t *) (uintptr_t) xpc;
     379           0 :                         es.pc += REPLACEMENT_PATCH_SIZE;
     380           0 :                         break;
     381             :                 }
     382             : 
     383             :                 // Fall-through to default exception handling.
     384             : 
     385             :         trap_handle_exception:
     386             :         default:
     387          91 :                 if (p != NULL) {
     388             : #if defined(__ALPHA__) || defined(__I386__) || defined(__X86_64__)
     389             :                         // Perform stack unwinding for exceptions on execution state.
     390          91 :                         es.pc = (uint8_t *) (uintptr_t) xpc;
     391          91 :                         es.pv = (uint8_t *) (uintptr_t) sfi.pv;
     392          91 :                         executionstate_unwind_exception(&es, p);
     393             : 
     394             :                         // Pass the exception object to the exception handler.
     395          91 :                         es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
     396             : #else
     397             :                         es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
     398             :                         es.intregs[REG_ITMP2_XPC]  = (uintptr_t) xpc;
     399             :                         es.pc                      = (uint8_t *) (uintptr_t) asm_handle_exception;
     400             : #endif
     401             :                 }
     402             :         }
     403             : 
     404             :         /* Write back execution state to current context. */
     405             : 
     406      197444 :         md_executionstate_write(&es, context);
     407             : 
     408             : # if !defined(NDEBUG) && defined(TRAP_TRACE_VERBOSE)
     409             :         /* Dump contents of execution state */
     410             : 
     411             :         if (opt_TraceTraps) {
     412             :                 log_println("[trap_handle: dumping execution state AFTER ...]");
     413             :                 executionstate_println(&es);
     414             :         }
     415             : # endif
     416             : #endif
     417             : }
     418             : 
     419             : 
     420             : /*
     421             :  * These are local overrides for various environment variables in Emacs.
     422             :  * Please do not remove this and leave it at the end of the file, where
     423             :  * Emacs will automagically detect them.
     424             :  * ---------------------------------------------------------------------
     425             :  * Local variables:
     426             :  * mode: c++
     427             :  * indent-tabs-mode: t
     428             :  * c-basic-offset: 4
     429             :  * tab-width: 4
     430             :  * End:
     431             :  * vim:noexpandtab:sw=4:ts=4:
     432             :  */

Generated by: LCOV version 1.11