LCOV - code coverage report
Current view: top level - vm/jit - trap.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 93 109 85.3 %
Date: 2017-07-14 10:03:36 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      218378 : 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      218378 :         if (xpc == NULL)
     110           0 :                 vm_abort("trap_handle: The program counter is NULL!");
     111             : #endif
     112             : 
     113             : #if defined(__AARCH64__) || 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      218378 :         executionstate_sanity_check(context);
     118             : # endif
     119             : 
     120             :         /* Read execution state from current context. */
     121             : 
     122      218378 :         es.code = NULL;
     123      218378 :         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      218378 :         void* pv = es.pv;  // Maybe null, resolved during stackframeinfo creation.
     138      218378 :         void* sp = es.sp;
     139             : #if defined(__I386__) || defined(__X86_64__)
     140      218378 :         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      218378 :         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      218378 :         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      218377 :         int      type = trp.type;
     167      218377 :         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      218377 :         int32_t        index = 0;
     174      218377 :         java_handle_t* o     = NULL;
     175      218377 :         methodinfo*    m     = NULL;
     176             : 
     177      218377 :         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      126223 :                 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      126223 :                 m  = code_get_methodinfo_for_pv(pv);
     203      126223 :                 pv = NULL;
     204             : 
     205      126223 :                 break;
     206             : 
     207             :         case TRAP_AbstractMethodError:
     208             :         case TRAP_NAT_EXCEPTION:
     209             : #if !STACKFRAME_LEAFMETHODS_RA_REGISTER
     210       20809 :                 ra = *(u1**) sp - 1;
     211       20809 :                 sp = (u1*) sp + SIZEOF_VOID_P;
     212       20809 :                 es.sp += SIZEOF_VOID_P;
     213             : #endif
     214       20809 :                 xpc = ra;
     215       20809 :                 pv = 0;
     216             :                 break;
     217             : 
     218             :         default:
     219             :                 /* do nothing */
     220             :                 break;
     221             :         }
     222             : 
     223             : #if !defined(NDEBUG)
     224             :         // Trace this trap.
     225      218377 :         if (opt_TraceTraps)
     226           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);
     227             : #endif
     228             : 
     229             :         /* Fill and add a stackframeinfo. */
     230             : 
     231      218377 :         if (type != TRAP_NAT_EXCEPTION)
     232      197569 :                 stacktrace_stackframeinfo_add(&sfi, pv, sp, ra, xpc);
     233             : 
     234             :         /* Get resulting exception (or pointer to compiled method). */
     235             : 
     236             :         java_handle_t* p;
     237      218377 :         void*          entry = 0;
     238      218377 :         bool           was_patched = false;
     239             : #if defined(ENABLE_REPLACEMENT)
     240             :         bool           was_replaced;
     241             : #endif
     242             : 
     243      218377 :         switch (type) {
     244             :         case TRAP_NullPointerException:
     245          22 :                 p = exceptions_new_nullpointerexception();
     246          22 :                 break;
     247             : 
     248             :         case TRAP_ArithmeticException:
     249           8 :                 p = exceptions_new_arithmeticexception();
     250           8 :                 break;
     251             : 
     252             :         case TRAP_ArrayIndexOutOfBoundsException:
     253          25 :                 p = exceptions_new_arrayindexoutofboundsexception(index);
     254          25 :                 break;
     255             : 
     256             :         case TRAP_ArrayStoreException:
     257           6 :                 p = exceptions_new_arraystoreexception();
     258           6 :                 break;
     259             : 
     260             :         case TRAP_ClassCastException:
     261          10 :                 p = exceptions_new_classcastexception(o);
     262          10 :                 break;
     263             : 
     264             :         case TRAP_CHECK_EXCEPTION:
     265           3 :                 p = exceptions_fillinstacktrace();
     266           3 :                 break;
     267             : 
     268             :         case TRAP_PATCHER:
     269       71146 :                 p = NULL;
     270             : #if defined(ENABLE_REPLACEMENT)
     271             :                 was_replaced = replace_handler((uint8_t*) xpc, &es);
     272             :                 if (was_replaced)
     273             :                         break;
     274             : #endif
     275       71146 :                 was_patched = patcher_handler((uint8_t*) xpc);
     276       71146 :                 break;
     277             : 
     278             :         case TRAP_COMPILER:
     279      126223 :                 p = NULL;
     280      126223 :                 entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
     281      126223 :                 break;
     282             : 
     283             : #if defined(__I386__) && defined(ENABLE_REPLACEMENT)
     284             :         // XXX #warning Port the below stuff to use the patching subsystem.
     285             :         case TRAP_COUNTDOWN:
     286             :                 p = NULL;
     287             :                 (void) replace_handler((uint8_t*) xpc - 13, &es);
     288             :                 break;
     289             : #endif
     290             : #if defined(__X86_64__) && defined(ENABLE_REPLACEMENT)
     291             :         // XXX #warning Port the below stuff to use the patching subsystem.
     292             :         case TRAP_COUNTDOWN:
     293             :                 p = NULL;
     294             :                 (void) replace_handler((uint8_t*) xpc - 19, &es);
     295             :                 break;
     296             : #endif
     297             : 
     298             :         case TRAP_AbstractMethodError:
     299           1 :                 p = exceptions_new_abstractmethoderror();
     300           1 :                 break;
     301             : 
     302             :         case TRAP_THROW:
     303             :         case TRAP_NAT_EXCEPTION:
     304       20933 :                 p = (java_handle_t*) (void*) es.intregs[REG_ITMP1_XPTR];
     305       20933 :                 break;
     306             : 
     307             :         default:
     308             :                 /* Let's try to get a backtrace. */
     309             : 
     310           0 :                 (void) methodtree_find(xpc);
     311             : 
     312             :                 /* If that does not work, print more debug info. */
     313             : 
     314           0 :                 vm_abort_disassemble(xpc, 1, "trap_handle: Unknown hardware exception type %d", type);
     315             : 
     316             :                 /* keep compiler happy */
     317             : 
     318           0 :                 p = NULL;
     319             :         }
     320             : 
     321             :         /* Remove stackframeinfo. */
     322             : 
     323      218377 :         if (type != TRAP_NAT_EXCEPTION)
     324      197569 :                 stacktrace_stackframeinfo_remove(&sfi);
     325             : 
     326             : #if defined(__AARCH64__) || defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__)
     327             :         /* Update execution state and set registers. */
     328             :         /* AFTER: removing stackframeinfo */
     329             : 
     330      218377 :         switch (type) {
     331             :         case TRAP_COMPILER:
     332             :                 // The normal case for a compiler trap is to jump directly to
     333             :                 // the newly compiled method.
     334             : 
     335      126223 :                 if (entry != NULL) {
     336      126219 :                         es.pc = (uint8_t *) (uintptr_t) entry;
     337             :                         // The s390 executionstate offsets pv, so we need to
     338             :                         // compensate here.
     339      126219 :                         es.pv = (uint8_t *) (uintptr_t) entry - N_PV_OFFSET;
     340      126219 :                         break;
     341             :                 }
     342             : 
     343             :                 // In case of an exception during JIT compilation, we fetch
     344             :                 // the exception here and proceed with exception handling.
     345             : 
     346           4 :                 p = exceptions_get_and_clear_exception();
     347           4 :                 assert(p != NULL);
     348             : 
     349             :                 // Remove RA from stack on some archs.
     350             : 
     351           4 :                 es.sp = (uint8_t*) sp;
     352             : 
     353             :                 // Get and set the PV from the parent Java method.
     354             : 
     355           4 :                 es.pv = (uint8_t*) md_codegen_get_pv_from_pc(ra) - N_PV_OFFSET;
     356             : 
     357             :                 // Now fall-through to default exception handling.
     358             : 
     359           4 :                 goto trap_handle_exception;
     360             : 
     361             :         case TRAP_PATCHER:
     362             : #if defined(ENABLE_REPLACEMENT)
     363             :                 // If on-stack-replacement suceeded, we are not allowed to touch
     364             :                 // the execution state. We assume that there was no exception.
     365             : 
     366             :                 if (was_replaced) {
     367             :                         java_object_t *e = exceptions_get_exception();
     368             :                         if (e)
     369             :                                 exceptions_print_stacktrace();
     370             :                         assert(e == NULL);
     371             :                         break;
     372             :                 }
     373             : #endif
     374             : 
     375             :                 // The normal case for a patcher trap is to continue execution at
     376             :                 // the trap instruction. On some archs the PC may point after the
     377             :                 // trap instruction, so we reset it here.
     378             : 
     379       71146 :                 if (was_patched) {
     380       71133 :                         java_object_t *e = exceptions_get_exception();
     381       71133 :                         if (e)
     382           0 :                                 exceptions_print_stacktrace();
     383       71133 :                         assert(e == NULL);
     384       71133 :                         es.pc = (uint8_t *) (uintptr_t) xpc;
     385       71133 :                         break;
     386             :                 }
     387             : 
     388             :                 // In case patching was not successful, we try to fetch the pending
     389             :                 // exception here.
     390             : 
     391          13 :                 p = exceptions_get_and_clear_exception();
     392             : 
     393             :                 // If there is no pending exception, we continue execution behind
     394             :                 // the position still in need of patching. Normally this would
     395             :                 // indicate an error in the patching subsystem, but others might
     396             :                 // want to piggyback patchers and we want to be able to provide
     397             :                 // "reusable trap points" and avoid inifinite loops here. This is
     398             :                 // especially useful to implement breakpoints or profiling points
     399             :                 // of any kind. So before changing the trap logic, think about
     400             :                 // utilizing the patching subsystem on your quest. :)
     401             : 
     402          13 :                 if (p == NULL) {
     403             : #if !defined(NDEBUG)
     404           0 :                         if (opt_PrintWarnings)
     405           0 :                                 log_println("trap_handle: Detected reusable trap at %p", xpc);
     406             : #endif
     407           0 :                         es.pc = (uint8_t *) (uintptr_t) xpc;
     408           0 :                         es.pc += REPLACEMENT_PATCH_SIZE;
     409           0 :                         break;
     410             :                 }
     411             : 
     412             :                 // Fall-through to default exception handling.
     413             : 
     414             :         trap_handle_exception:
     415             :         default:
     416       21025 :                 if (p != NULL) {
     417             : #if defined(__AARCH64__) || defined(__ALPHA__) || defined(__MIPS__) || defined(__ARM__) || defined(__I386__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
     418             :                         // Perform stack unwinding for exceptions on execution state.
     419       21025 :                         es.pc = (uint8_t *) (uintptr_t) xpc;
     420       21025 :                         if (type == TRAP_NAT_EXCEPTION)
     421       20808 :                                 es.pv = (uint8_t*) md_codegen_get_pv_from_pc(xpc);
     422             :                         else
     423         217 :                                 es.pv = (uint8_t *) (uintptr_t) sfi.pv;
     424       21025 :                         executionstate_unwind_exception(&es, p);
     425             : 
     426             :                         // Pass the exception object to the exception handler.
     427       21025 :                         es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
     428             : #else
     429             :                         es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
     430             :                         es.intregs[REG_ITMP2_XPC]  = (uintptr_t) xpc;
     431             :                         es.pc                      = (uint8_t *) (uintptr_t) asm_handle_exception;
     432             : #endif
     433             :                 }
     434             :         }
     435             : 
     436             :         /* Write back execution state to current context. */
     437             : 
     438      218377 :         md_executionstate_write(&es, context);
     439             : 
     440             : # if !defined(NDEBUG) && defined(TRAP_TRACE_VERBOSE)
     441             :         /* Dump contents of execution state */
     442             : 
     443             :         if (opt_TraceTraps) {
     444             :                 log_println("[trap_handle: dumping execution state AFTER ...]");
     445             :                 executionstate_println(&es);
     446             :         }
     447             : # endif
     448             : #endif
     449             : }
     450             : 
     451             : 
     452             : /*
     453             :  * These are local overrides for various environment variables in Emacs.
     454             :  * Please do not remove this and leave it at the end of the file, where
     455             :  * Emacs will automagically detect them.
     456             :  * ---------------------------------------------------------------------
     457             :  * Local variables:
     458             :  * mode: c++
     459             :  * indent-tabs-mode: t
     460             :  * c-basic-offset: 4
     461             :  * tab-width: 4
     462             :  * End:
     463             :  * vim:noexpandtab:sw=4:ts=4:
     464             :  */

Generated by: LCOV version 1.11