* src/vm/jit/trap.cpp (trap_init): Disabled mmapping of first page by default.
[cacao.git] / src / vm / jit / trap.cpp
1 /* src/vm/jit/trap.cpp - hardware traps
2
3    Copyright (C) 2008, 2009
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.h"
34 #include "md-trap.h"
35
36 #include "mm/memory.hpp"
37
38 #include "native/llni.h"
39
40 #include "toolbox/logging.hpp"
41
42 #include "vm/exceptions.hpp"
43 #include "vm/options.h"
44 #include "vm/os.hpp"
45 #include "vm/vm.hpp"
46
47 #include "vm/jit/asmpart.h"
48 #include "vm/jit/code.hpp"
49 #include "vm/jit/disass.h"
50 #include "vm/jit/executionstate.h"
51 #include "vm/jit/jit.hpp"
52 #include "vm/jit/methodtree.h"
53 #include "vm/jit/patcher-common.hpp"
54 #include "vm/jit/replace.hpp"
55 #include "vm/jit/stacktrace.hpp"
56 #include "vm/jit/trap.hpp"
57
58 #ifdef __cplusplus
59 extern "C" {
60 #endif
61
62 /**
63  * Mmap the first memory page to support hardware exceptions and check
64  * the maximum hardware trap displacement on the architectures where
65  * it is required (TRAP_INSTRUCTION_IS_LOAD defined to 1).
66  */
67 void trap_init(void)
68 {
69         TRACESUBSYSTEMINITIALIZATION("trap_init");
70
71         /* If requested we mmap a memory page at address 0x0,
72            so our hardware-exceptions work. */
73
74         if (opt_AlwaysMmapFirstPage) {
75                 int pagesize = os::getpagesize();
76                 (void) os::mmap_anonymous(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED);
77         }
78
79 #if !defined(TRAP_INSTRUCTION_IS_LOAD)
80 # error TRAP_INSTRUCTION_IS_LOAD is not defined in your md-trap.h
81 #endif
82
83 #if TRAP_INSTRUCTION_IS_LOAD == 1
84         /* Check if we get into trouble with our hardware-exceptions. */
85
86         if (TRAP_END > OFFSET(java_bytearray_t, data))
87                 vm_abort("trap_init: maximum hardware trap displacement is greater than the array-data offset: %d > %d", TRAP_END, OFFSET(java_bytearray_t, data));
88 #endif
89 }
90
91
92 /**
93  * Handles the signal which is generated by trap instructions, caught
94  * by a signal handler and calls the correct function.
95  *
96  * @param sig signal number
97  * @param xpc exception PC
98  * @param context pointer to OS dependent machine context
99  */
100 void trap_handle(int sig, void *xpc, void *context)
101 {
102         executionstate_t es;
103         stackframeinfo_t sfi;
104         trapinfo_t       trp;
105
106         // Prevent compiler warnings.
107         java_handle_t* o = NULL;
108         methodinfo*    m = NULL;
109
110 #if !defined(NDEBUG)
111         // Sanity checking the XPC.
112         if (xpc == NULL)
113                 vm_abort("trap_handle: The program counter is NULL!");
114 #endif
115
116 #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
117 # if !defined(NDEBUG)
118         /* Perform a sanity check on our execution state functions. */
119
120         executionstate_sanity_check(context);
121 # endif
122
123         /* Read execution state from current context. */
124
125         es.code = NULL;
126         md_executionstate_read(&es, context);
127
128 //# define TRAP_TRACE_VERBOSE
129 # if !defined(NDEBUG) && defined(TRAP_TRACE_VERBOSE)
130         /* Dump contents of execution state */
131
132         if (opt_TraceTraps) {
133                 log_println("[trap_handle: dumping execution state BEFORE ...]");
134                 executionstate_println(&es);
135         }
136 # endif
137 #endif
138
139         // Extract information from executionstate
140         void* pv = es.pv;  // Maybe null, resolved during stackframeinfo creation.
141         void* sp = es.sp;
142 #if defined(__I386__) || defined(__X86_64__)
143         void* ra = xpc;  // Return address is equal to XPC.
144 #else
145         void* ra = es.ra;  // This is correct for leafs.
146 #endif
147
148         // Decode machine-dependent trap instruction.
149         bool decode_result = md_trap_decode(&trp, sig, xpc, &es);
150
151         // Check if the trap instruction is valid and was decoded
152         // successfully.
153         if (!decode_result) {
154                 // Check if the PC has been patched during our way to this
155                 // trap handler (see PR85).
156                 // NOTE: Some archs use SIGILL for other traps too, but it's OK to
157                 // do this check anyway because it will fail.
158                 if (patcher_is_patched_at(xpc) == true) {
159                         if (opt_PrintWarnings)
160                                 log_println("trap_handle: Detected patcher race condition (PR85) at %p", xpc);
161                         return;
162                 }
163
164                 // We have a problem...
165                 vm_abort_disassemble(xpc, 1, "trap_handle: Unknown trap instruction at %p", xpc);
166         }
167
168         // For convenience only.
169         int      type = trp.type;
170         intptr_t val  = trp.value;
171
172         /* Do some preparations before we enter the nativeworld. */
173         /* BEFORE: creating stackframeinfo */
174
175         switch (type) {
176         case TRAP_ClassCastException:
177                 /* Wrap the value into a handle, as it is a reference. */
178
179                 o = LLNI_WRAP((java_object_t *) val);
180                 break;
181
182         case TRAP_COMPILER:
183                 /* We need to fixup the XPC, SP and RA here because they
184                    all might point into the compiler stub instead of the
185                    calling method. */
186
187                 MD_TRAP_COMPILER_FIXUP(xpc, ra, sp, pv);
188
189                 /* In this case the passed PV points to the compiler stub.  We
190                    get the methodinfo pointer here and set PV to NULL so
191                    stacktrace_stackframeinfo_add determines the PV for the
192                    parent Java method. */
193
194                 m  = code_get_methodinfo_for_pv(pv);
195                 pv = NULL;
196
197                 break;
198
199         default:
200                 /* do nothing */
201                 break;
202         }
203
204 #if !defined(NDEBUG)
205         // Trace this trap.
206         if (opt_TraceTraps)
207                 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);
208 #endif
209
210 #if defined(ENABLE_VMLOG)
211         vmlog_cacao_signl_type(type);
212 #endif
213
214         /* Fill and add a stackframeinfo. */
215
216         stacktrace_stackframeinfo_add(&sfi, pv, sp, ra, xpc);
217
218         /* Get resulting exception (or pointer to compiled method). */
219
220         int32_t        index;
221         java_handle_t* p;
222         void*          entry;
223
224         switch (type) {
225         case TRAP_NullPointerException:
226                 p = exceptions_new_nullpointerexception();
227                 break;
228
229         case TRAP_ArithmeticException:
230                 p = exceptions_new_arithmeticexception();
231                 break;
232
233         case TRAP_ArrayIndexOutOfBoundsException:
234                 index = (int32_t) val;
235                 p = exceptions_new_arrayindexoutofboundsexception(index);
236                 break;
237
238         case TRAP_ArrayStoreException:
239                 p = exceptions_new_arraystoreexception();
240                 break;
241
242         case TRAP_ClassCastException:
243                 p = exceptions_new_classcastexception(o);
244                 break;
245
246         case TRAP_CHECK_EXCEPTION:
247                 p = exceptions_fillinstacktrace();
248                 break;
249
250         case TRAP_PATCHER:
251 #if defined(ENABLE_REPLACEMENT)
252                 if (replace_me_wrapper((uint8_t*) xpc, context)) {
253                         p = NULL;
254                         break;
255                 }
256 #endif
257                 p = patcher_handler((uint8_t*) xpc);
258                 break;
259
260         case TRAP_COMPILER:
261                 entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
262                 p = NULL;
263                 break;
264
265 #if defined(ENABLE_REPLACEMENT)
266         case TRAP_COUNTDOWN:
267 # if defined(__I386__)
268                 replace_me_wrapper((uint8_t*) xpc - 13, context);
269 # endif
270                 p = NULL;
271                 break;
272 #endif
273
274         default:
275                 /* Let's try to get a backtrace. */
276
277                 (void) methodtree_find(xpc);
278
279                 /* If that does not work, print more debug info. */
280
281                 vm_abort_disassemble(xpc, 1, "trap_handle: Unknown hardware exception type %d", type);
282
283                 /* keep compiler happy */
284
285                 p = NULL;
286         }
287
288         /* Remove stackframeinfo. */
289
290         stacktrace_stackframeinfo_remove(&sfi);
291
292 #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
293         /* Update execution state and set registers. */
294         /* AFTER: removing stackframeinfo */
295
296         switch (type) {
297         case TRAP_COMPILER:
298                 // The normal case for a compiler trap is to jump directly to
299                 // the newly compiled method.
300
301                 if (entry != NULL) {
302                         es.pc = (uint8_t *) (uintptr_t) entry;
303                         es.pv = (uint8_t *) (uintptr_t) entry;
304                         break;
305                 }
306
307                 // In case of an exception during JIT compilation, we fetch
308                 // the exception here and proceed with exception handling.
309
310                 p = exceptions_get_and_clear_exception();
311                 assert(p != NULL);
312
313                 // Remove RA from stack on some archs.
314
315                 es.sp = (uint8_t*) sp;
316
317                 // Get and set the PV from the parent Java method.
318
319                 es.pv = (uint8_t*) md_codegen_get_pv_from_pc(ra);
320
321                 // Now fall-through to default exception handling.
322
323                 goto trap_handle_exception;
324
325         case TRAP_PATCHER:
326                 // The normal case for a patcher trap is to continue execution at
327                 // the trap instruction. On some archs the PC may point after the
328                 // trap instruction, so we reset it here.
329
330                 if (p == NULL) {
331                         es.pc = (uint8_t *) (uintptr_t) xpc;
332                         break;
333                 }
334
335                 // Fall-through to default exception handling.
336
337         trap_handle_exception:
338         default:
339                 if (p != NULL) {
340                         es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
341                         es.intregs[REG_ITMP2_XPC]  = (uintptr_t) xpc;
342                         es.pc                      = (uint8_t *) (uintptr_t) asm_handle_exception;
343                 }
344         }
345
346         /* Write back execution state to current context. */
347
348         md_executionstate_write(&es, context);
349
350 # if !defined(NDEBUG) && defined(TRAP_TRACE_VERBOSE)
351         /* Dump contents of execution state */
352
353         if (opt_TraceTraps) {
354                 log_println("[trap_handle: dumping execution state AFTER ...]");
355                 executionstate_println(&es);
356         }
357 # endif
358 #endif
359 }
360
361 #ifdef __cplusplus
362 }
363 #endif
364
365
366 /*
367  * These are local overrides for various environment variables in Emacs.
368  * Please do not remove this and leave it at the end of the file, where
369  * Emacs will automagically detect them.
370  * ---------------------------------------------------------------------
371  * Local variables:
372  * mode: c++
373  * indent-tabs-mode: t
374  * c-basic-offset: 4
375  * tab-width: 4
376  * End:
377  * vim:noexpandtab:sw=4:ts=4:
378  */