CACAO
trap.cpp
Go to the documentation of this file.
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"
50 #include "vm/jit/jit.hpp"
51 #include "vm/jit/methodtree.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 void trap_init(void)
69 {
70  TRACESUBSYSTEMINITIALIZATION("trap_init");
71 
72  /* If requested we mmap a memory page at address 0x0,
73  so our hardware-exceptions work. */
74 
76  int pagesize = os::getpagesize();
77  (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  if (TRAP_END > OFFSET(java_bytearray_t, data))
88  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 }
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 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  if (xpc == NULL)
110  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 
118 # endif
119 
120  /* Read execution state from current context. */
121 
122  es.code = NULL;
123  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 ...]");
132  }
133 # endif
134 #endif
135 
136  // Extract information from executionstate
137  void* pv = es.pv; // Maybe null, resolved during stackframeinfo creation.
138  void* sp = es.sp;
139 #if defined(__I386__) || defined(__X86_64__)
140  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  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  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  if (patcher_is_patched_at(xpc) == true) {
156  if (opt_PrintWarnings)
157  log_println("trap_handle: Detected patcher race condition (PR85) at %p", xpc);
158  return;
159  }
160 
161  // We have a problem...
162  vm_abort_disassemble(xpc, 1, "trap_handle: Unknown trap instruction at %p", xpc);
163  }
164 
165  // For convenience only.
166  int type = trp.type;
167  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  int32_t index = 0;
174  java_handle_t* o = NULL;
175  methodinfo* m = NULL;
176 
177  // If the trap was triggered within compiler2-optimized code due to an
178  // implicit exception (i.e. NullPointerException,
179  // ArrayIndexOutOfBoundsException, or ArithmeticException) we deoptimize
180  // instead of throwing the exception.
181 #if defined(ENABLE_COMPILER2)
182  if (type == TRAP_NullPointerException
184  || type == TRAP_ArithmeticException) {
185  void *xpv = md_codegen_get_pv_from_pc(xpc);
187  if (code->optlevel > 0) {
188  type = TRAP_DEOPTIMIZE;
189  }
190  }
191 #endif
192 
193  switch (type) {
195  /* Get the index into the array causing the exception. */
196 
197  index = (int32_t) val;
198  break;
199 
201  /* Wrap the value into a handle, as it is a reference. */
202 
203  o = LLNI_WRAP((java_object_t *) val);
204  break;
205 
206  case TRAP_COMPILER:
207  /* We need to fixup the XPC, SP and RA here because they
208  all might point into the compiler stub instead of the
209  calling method. */
210 
211  MD_TRAP_COMPILER_FIXUP(xpc, ra, sp, pv);
212 
213  /* In this case the passed PV points to the compiler stub. We
214  get the methodinfo pointer here and set PV to NULL so
215  stacktrace_stackframeinfo_add determines the PV for the
216  parent Java method. */
217 
219  pv = NULL;
220 
221  break;
222 
224  case TRAP_NAT_EXCEPTION:
225 #if !STACKFRAME_LEAFMETHODS_RA_REGISTER
226  ra = *(u1**) sp - 1;
227  sp = (u1*) sp + SIZEOF_VOID_P;
228  es.sp += SIZEOF_VOID_P;
229 #endif
230  xpc = ra;
231  pv = 0;
232  break;
233 
234  default:
235  /* do nothing */
236  break;
237  }
238 
239 #if !defined(NDEBUG)
240  // Trace this trap.
241  if (opt_TraceTraps)
242  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);
243 #endif
244 
245  /* Fill and add a stackframeinfo. */
246 
247  if (type != TRAP_NAT_EXCEPTION)
248  stacktrace_stackframeinfo_add(&sfi, pv, sp, ra, xpc);
249 
250  /* Get resulting exception (or pointer to compiled method). */
251 
252  java_handle_t* p;
253  void* entry = 0;
254  bool was_patched = false;
255 #if defined(ENABLE_REPLACEMENT)
256  bool was_replaced;
257 #endif
258 
259  switch (type) {
262  break;
263 
266  break;
267 
270  break;
271 
274  break;
275 
278  break;
279 
282  break;
283 
284  case TRAP_PATCHER:
285  p = NULL;
286 #if defined(ENABLE_REPLACEMENT)
287  was_replaced = replace_handle_replacement_trap((uint8_t*) xpc, &es);
288  if (was_replaced)
289  break;
290 #endif
291  was_patched = patcher_handler((uint8_t*) xpc);
292  break;
293 
294  case TRAP_COMPILER:
295  p = NULL;
296  entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
297  break;
298 
299 #if (defined(__AARCH64__) || defined(__X86_64__)) && defined(ENABLE_COMPILER2)
300  case TRAP_COUNTDOWN:
301  p = NULL;
302  replace_handle_countdown_trap((uint8_t*) xpc, &es);
303  break;
304 
305  case TRAP_DEOPTIMIZE:
306  p = NULL;
307  replace_handle_deoptimization_trap((uint8_t*) xpc, &es);
308  break;
309 #endif
310 
313  break;
314 
315  case TRAP_THROW:
316  case TRAP_NAT_EXCEPTION:
317  p = (java_handle_t*) (void*) es.intregs[REG_ITMP1_XPTR];
318  break;
319 
320  default:
321  /* Let's try to get a backtrace. */
322 
323  (void) methodtree_find(xpc);
324 
325  /* If that does not work, print more debug info. */
326 
327  vm_abort_disassemble(xpc, 1, "trap_handle: Unknown hardware exception type %d", type);
328 
329  /* keep compiler happy */
330 
331  p = NULL;
332  }
333 
334  /* Remove stackframeinfo. */
335 
336  if (type != TRAP_NAT_EXCEPTION)
338 
339 #if defined(__AARCH64__) || defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__)
340  /* Update execution state and set registers. */
341  /* AFTER: removing stackframeinfo */
342 
343  switch (type) {
344  case TRAP_COMPILER:
345  // The normal case for a compiler trap is to jump directly to
346  // the newly compiled method.
347 
348  if (entry != NULL) {
349  es.pc = (uint8_t *) (uintptr_t) entry;
350  // The s390 executionstate offsets pv, so we need to
351  // compensate here.
352  es.pv = (uint8_t *) (uintptr_t) entry - N_PV_OFFSET;
353  break;
354  }
355 
356  // In case of an exception during JIT compilation, we fetch
357  // the exception here and proceed with exception handling.
358 
360  assert(p != NULL);
361 
362  // Remove RA from stack on some archs.
363 
364  es.sp = (uint8_t*) sp;
365 
366  // Get and set the PV from the parent Java method.
367 
368  es.pv = (uint8_t*) md_codegen_get_pv_from_pc(ra) - N_PV_OFFSET;
369 
370  // Now fall-through to default exception handling.
371 
372  goto trap_handle_exception;
373 
374  case TRAP_PATCHER:
375 #if defined(ENABLE_REPLACEMENT)
376  // If on-stack-replacement suceeded, we are not allowed to touch
377  // the execution state. We assume that there was no exception.
378 
379  if (was_replaced) {
381  if (e)
383  assert(e == NULL);
384  break;
385  }
386 #endif
387 
388  // The normal case for a patcher trap is to continue execution at
389  // the trap instruction. On some archs the PC may point after the
390  // trap instruction, so we reset it here.
391 
392  if (was_patched) {
394  if (e)
396  assert(e == NULL);
397  es.pc = (uint8_t *) (uintptr_t) xpc;
398  break;
399  }
400 
401  // In case patching was not successful, we try to fetch the pending
402  // exception here.
403 
405 
406  // If there is no pending exception, we continue execution behind
407  // the position still in need of patching. Normally this would
408  // indicate an error in the patching subsystem, but others might
409  // want to piggyback patchers and we want to be able to provide
410  // "reusable trap points" and avoid inifinite loops here. This is
411  // especially useful to implement breakpoints or profiling points
412  // of any kind. So before changing the trap logic, think about
413  // utilizing the patching subsystem on your quest. :)
414 
415  if (p == NULL) {
416 #if !defined(NDEBUG)
417  if (opt_PrintWarnings)
418  log_println("trap_handle: Detected reusable trap at %p", xpc);
419 #endif
420  es.pc = (uint8_t *) (uintptr_t) xpc;
422  break;
423  }
424 
425  // Fall-through to default exception handling.
426 
427  trap_handle_exception:
428  default:
429  if (p != NULL) {
430 #if defined(__AARCH64__) || defined(__ALPHA__) || defined(__MIPS__) || defined(__ARM__) || defined(__I386__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
431  // Perform stack unwinding for exceptions on execution state.
432  es.pc = (uint8_t *) (uintptr_t) xpc;
433  if (type == TRAP_NAT_EXCEPTION)
434  es.pv = (uint8_t*) md_codegen_get_pv_from_pc(xpc);
435  else
436  es.pv = (uint8_t *) (uintptr_t) sfi.pv;
438 
439  // Pass the exception object to the exception handler.
440  es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
441 #else
442  es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
443  es.intregs[REG_ITMP2_XPC] = (uintptr_t) xpc;
444  es.pc = (uint8_t *) (uintptr_t) asm_handle_exception;
445 #endif
446  }
447  }
448 
449  /* Write back execution state to current context. */
450 
451  md_executionstate_write(&es, context);
452 
453 # if !defined(NDEBUG) && defined(TRAP_TRACE_VERBOSE)
454  /* Dump contents of execution state */
455 
456  if (opt_TraceTraps) {
457  log_println("[trap_handle: dumping execution state AFTER ...]");
459  }
460 # endif
461 #endif
462 }
463 
464 
465 /*
466  * These are local overrides for various environment variables in Emacs.
467  * Please do not remove this and leave it at the end of the file, where
468  * Emacs will automagically detect them.
469  * ---------------------------------------------------------------------
470  * Local variables:
471  * mode: c++
472  * indent-tabs-mode: t
473  * c-basic-offset: 4
474  * tab-width: 4
475  * End:
476  * vim:noexpandtab:sw=4:ts=4:
477  */
bool patcher_handler(u1 *pc)
#define methodtree_find
Definition: md-asm.hpp:101
std::size_t index
#define pv
Definition: md-asm.hpp:65
intptr_t value
Value (numeric or address) passed with the trap.
Definition: trap.hpp:44
bool opt_AlwaysMmapFirstPage
Definition: options.cpp:164
java_handle_t * exceptions_new_arraystoreexception(void)
Definition: exceptions.cpp:586
static size_t pagesize
Definition: codememory.cpp:47
void exceptions_print_stacktrace(void)
#define ra
Definition: md-asm.hpp:62
methodinfo * code_get_methodinfo_for_pv(void *pv)
Definition: code.cpp:150
void * jit_compile_handle(methodinfo *m, void *pv, void *ra, void *mptr)
Definition: jit.cpp:1088
void replace_handle_deoptimization_trap(u1 *pc, executionstate_t *es)
Definition: replace.cpp:1974
u1 optlevel
Definition: code.hpp:79
Contains information about a decoded trap instruction.
Definition: trap.hpp:42
typedef void(JNICALL *jvmtiEventSingleStep)(jvmtiEnv *jvmti_env
#define REG_ITMP1_XPTR
Definition: md-abi.hpp:50
void trap_init(void)
Mmap the first memory page to support hardware exceptions and check the maximum hardware trap displac...
Definition: trap.cpp:68
java_handle_t * exceptions_new_nullpointerexception(void)
uint8_t u1
Definition: types.hpp:40
#define MD_TRAP_COMPILER_FIXUP(xpc, ra, sp, pv)
Macro to fixup a compiler stub.
Definition: md-trap.hpp:67
void log_println(const char *text,...)
Definition: logging.cpp:193
#define TRACESUBSYSTEMINITIALIZATION(text)
Definition: options.hpp:257
#define REG_ITMP2_XPC
Definition: md-abi.hpp:51
void vm_abort(const char *text,...)
Definition: vm.cpp:2586
java_handle_t * exceptions_new_classcastexception(java_handle_t *o)
#define xpc
Definition: md-asm.hpp:51
java_handle_t * exceptions_new_arrayindexoutofboundsexception(s4 index)
#define LLNI_WRAP(obj)
Definition: llni.hpp:51
void executionstate_println(executionstate_t *es)
#define OFFSET(s, el)
Definition: memory.hpp:90
static int getpagesize(void)
Definition: os.hpp:433
static codeinfo * code_get_codeinfo_for_pv(void *pv)
Definition: code.hpp:222
int type
Specific trap type (see md-trap.h).
Definition: trap.hpp:43
int opt_TraceTraps
Definition: options.cpp:233
#define exceptions_get_and_clear_exception
Definition: md-asm.hpp:98
void executionstate_unwind_exception(executionstate_t *es, java_handle_t *e)
Performs stack unwinding in case of an exception.
void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, void *pv, void *sp, void *ra, void *xpc)
Definition: stacktrace.cpp:84
void md_executionstate_write(executionstate_t *es, void *context)
Definition: md-os.cpp:148
static void * md_codegen_get_pv_from_pc(void *ra)
Definition: md.hpp:100
codeinfo * code
Definition: method.hpp:103
void asm_handle_exception(void)
MIIterator e
static void * mmap_anonymous(void *addr, size_t len, int prot, int flags)
Maps anonymous memory, even on systems not defining MAP_ANON(YMOUS).
Definition: os.cpp:215
#define REPLACEMENT_PATCH_SIZE
Definition: arch.hpp:119
#define sp
Definition: md-asm.hpp:81
bool replace_handle_replacement_trap(u1 *pc, executionstate_t *es)
Definition: replace.cpp:1931
int opt_PrintWarnings
Definition: options.cpp:198
void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
Definition: stacktrace.cpp:204
void md_executionstate_read(executionstate_t *es, void *context)
Definition: md-os.cpp:107
void replace_handle_countdown_trap(u1 *pc, executionstate_t *es)
Definition: replace.cpp:1887
java_handle_t * exceptions_fillinstacktrace(void)
bool md_trap_decode(trapinfo_t *trp, int sig, void *xpc, executionstate_t *es)
Decode the trap instruction at the given PC.
Definition: md.cpp:192
void trap_handle(int sig, void *xpc, void *context)
Handles the signal which is generated by trap instructions, caught by a signal handler and calls the ...
Definition: trap.cpp:101
void executionstate_sanity_check(void *context)
java_handle_t * exceptions_get_exception(void)
Definition: exceptions.cpp:76
uintptr_t intregs[INT_REG_CNT]
#define LLNI_DIRECT(hdl)
Definition: llni.hpp:54
void vm_abort_disassemble(void *pc, int count, const char *text,...)
Definition: vm.cpp:2001
#define N_PV_OFFSET
Definition: trap.cpp:60
java_handle_t * exceptions_new_abstractmethoderror(void)
Definition: exceptions.cpp:552
java_handle_t * exceptions_new_arithmeticexception(void)
bool patcher_is_patched_at(void *pc)