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  switch (type) {
179  /* Get the index into the array causing the exception. */
180 
181  index = (int32_t) val;
182  break;
183 
185  /* Wrap the value into a handle, as it is a reference. */
186 
187  o = LLNI_WRAP((java_object_t *) val);
188  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  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 
203  pv = NULL;
204 
205  break;
206 
208  case TRAP_NAT_EXCEPTION:
209 #if !STACKFRAME_LEAFMETHODS_RA_REGISTER
210  ra = *(u1**) sp - 1;
211  sp = (u1*) sp + SIZEOF_VOID_P;
212  es.sp += SIZEOF_VOID_P;
213 #endif
214  xpc = ra;
215  pv = 0;
216  break;
217 
218  default:
219  /* do nothing */
220  break;
221  }
222 
223 #if !defined(NDEBUG)
224  // Trace this trap.
225  if (opt_TraceTraps)
226  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  if (type != TRAP_NAT_EXCEPTION)
232  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  void* entry = 0;
238  bool was_patched = false;
239 #if defined(ENABLE_REPLACEMENT)
240  bool was_replaced;
241 #endif
242 
243  switch (type) {
246  break;
247 
250  break;
251 
254  break;
255 
258  break;
259 
262  break;
263 
266  break;
267 
268  case TRAP_PATCHER:
269  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  was_patched = patcher_handler((uint8_t*) xpc);
276  break;
277 
278  case TRAP_COMPILER:
279  p = NULL;
280  entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
281  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 
300  break;
301 
302  case TRAP_THROW:
303  case TRAP_NAT_EXCEPTION:
304  p = (java_handle_t*) (void*) es.intregs[REG_ITMP1_XPTR];
305  break;
306 
307  default:
308  /* Let's try to get a backtrace. */
309 
310  (void) methodtree_find(xpc);
311 
312  /* If that does not work, print more debug info. */
313 
314  vm_abort_disassemble(xpc, 1, "trap_handle: Unknown hardware exception type %d", type);
315 
316  /* keep compiler happy */
317 
318  p = NULL;
319  }
320 
321  /* Remove stackframeinfo. */
322 
323  if (type != TRAP_NAT_EXCEPTION)
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  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  if (entry != NULL) {
336  es.pc = (uint8_t *) (uintptr_t) entry;
337  // The s390 executionstate offsets pv, so we need to
338  // compensate here.
339  es.pv = (uint8_t *) (uintptr_t) entry - N_PV_OFFSET;
340  break;
341  }
342 
343  // In case of an exception during JIT compilation, we fetch
344  // the exception here and proceed with exception handling.
345 
347  assert(p != NULL);
348 
349  // Remove RA from stack on some archs.
350 
351  es.sp = (uint8_t*) sp;
352 
353  // Get and set the PV from the parent Java method.
354 
355  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  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) {
368  if (e)
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  if (was_patched) {
381  if (e)
383  assert(e == NULL);
384  es.pc = (uint8_t *) (uintptr_t) xpc;
385  break;
386  }
387 
388  // In case patching was not successful, we try to fetch the pending
389  // exception here.
390 
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  if (p == NULL) {
403 #if !defined(NDEBUG)
404  if (opt_PrintWarnings)
405  log_println("trap_handle: Detected reusable trap at %p", xpc);
406 #endif
407  es.pc = (uint8_t *) (uintptr_t) xpc;
409  break;
410  }
411 
412  // Fall-through to default exception handling.
413 
414  trap_handle_exception:
415  default:
416  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  es.pc = (uint8_t *) (uintptr_t) xpc;
420  if (type == TRAP_NAT_EXCEPTION)
421  es.pv = (uint8_t*) md_codegen_get_pv_from_pc(xpc);
422  else
423  es.pv = (uint8_t *) (uintptr_t) sfi.pv;
425 
426  // Pass the exception object to the exception handler.
427  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  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 ...]");
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  */
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:1064
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:66
void log_println(const char *text,...)
Definition: logging.cpp:193
#define TRACESUBSYSTEMINITIALIZATION(text)
Definition: options.hpp:258
#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)
static int getpagesize(void)
Definition: os.hpp:433
int type
Specific trap type (see md-trap.h).
Definition: trap.hpp:43
int opt_TraceTraps
Definition: options.cpp:234
#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:147
static void * md_codegen_get_pv_from_pc(void *ra)
Definition: md.hpp:99
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:111
#define sp
Definition: md-asm.hpp:81
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
java_handle_t * exceptions_fillinstacktrace(void)
bool replace_handler(u1 *pc, executionstate_t *es)
Definition: replace.cpp:2758
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
#define OFFSET(s, el)
Definition: memory.hpp:90
java_handle_t * exceptions_new_arithmeticexception(void)
bool patcher_is_patched_at(void *pc)