ced1cbee47c3965e4e7c78c5f8aaf40a28f5daff
[cacao.git] / src / vm / jit / x86_64 / linux / md-os.c
1 /* src/vm/jit/x86_64/linux/md-os.c - machine dependent x86_64 Linux functions
2
3    Copyright (C) 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25 */
26
27
28 #define _GNU_SOURCE
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <stdint.h>
34 #include <stdlib.h>
35 #include <ucontext.h>
36
37 #include "vm/types.h"
38
39 #include "vm/jit/x86_64/codegen.h"
40
41 #if defined(ENABLE_THREADS)
42 # include "threads/native/threads.h"
43 #endif
44
45 #include "vm/builtin.h"
46 #include "vm/exceptions.h"
47 #include "vm/signallocal.h"
48
49 #include "vm/jit/asmpart.h"
50 #include "vm/jit/stacktrace.h"
51
52
53 /* md_signal_handler_sigsegv ***************************************************
54
55    Signal handler for hardware exception.
56
57 *******************************************************************************/
58
59 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
60 {
61         ucontext_t     *_uc;
62         mcontext_t     *_mc;
63         void           *pv;
64         u1             *sp;
65         u1             *ra;
66         u1             *xpc;
67         u1              opc;
68         u1              mod;
69         u1              rm;
70         s4              d;
71         s4              disp;
72         int             type;
73         intptr_t        val;
74         void           *p;
75         java_object_t  *o;
76
77         _uc = (ucontext_t *) _p;
78         _mc = &_uc->uc_mcontext;
79
80         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
81            different to the ones in <ucontext.h>. */
82
83         pv  = NULL;                 /* is resolved during stackframeinfo creation */
84         sp  = (u1 *) _mc->gregs[REG_RSP];
85         xpc = (u1 *) _mc->gregs[REG_RIP];
86         ra  = xpc;                              /* return address is equal to XPC */
87
88 #if 0
89         /* check for StackOverflowException */
90
91         threads_check_stackoverflow(sp);
92 #endif
93
94         /* get exception-throwing instruction */
95
96         opc = M_ALD_MEM_GET_OPC(xpc);
97         mod = M_ALD_MEM_GET_MOD(xpc);
98         rm  = M_ALD_MEM_GET_RM(xpc);
99
100         /* for values see emit_mov_mem_reg and emit_mem */
101
102         if ((opc == 0x8b) && (mod == 0) && (rm == 4)) {
103                 /* this was a hardware-exception */
104
105                 d    = M_ALD_MEM_GET_REG(xpc);
106                 disp = M_ALD_MEM_GET_DISP(xpc);
107
108                 /* we use the exception type as load displacement */
109
110                 type = disp;
111
112                 /* XXX FIX ME! */
113
114                 /* ATTENTION: The _mc->gregs layout is even worse than on
115                    i386! See /usr/include/sys/ucontext.h.  We need a
116                    switch-case here... */
117
118                 switch (d) {
119                 case 0:  /* REG_RAX == 13 */
120                         d = REG_RAX;
121                         break;
122                 case 1:  /* REG_RCX == 14 */
123                         d = REG_RCX;
124                         break;
125                 case 2:  /* REG_RDX == 12 */
126                         d = REG_RDX;
127                         break;
128                 case 3:  /* REG_RBX == 11 */
129                         d = REG_RBX;
130                         break;
131                 case 4:  /* REG_RSP == 15 */
132                         d = REG_RSP;
133                         break;
134                 case 5:  /* REG_RBP == 10 */
135                         d = REG_RBP;
136                         break;
137                 case 6:  /* REG_RSI == 9  */
138                         d = REG_RSI;
139                         break;
140                 case 7:  /* REG_RDI == 8  */
141                         d = REG_RDI;
142                         break;
143                 case 8:  /* REG_R8  == 0  */
144                 case 9:  /* REG_R9  == 1  */
145                 case 10: /* REG_R10 == 2  */
146                 case 11: /* REG_R11 == 3  */
147                 case 12: /* REG_R12 == 4  */
148                 case 13: /* REG_R13 == 5  */
149                 case 14: /* REG_R14 == 6  */
150                 case 15: /* REG_R15 == 7  */
151                         d = d - 8;
152                         break;
153                 }
154
155                 val = _mc->gregs[d];
156
157                 if (type == EXCEPTION_HARDWARE_COMPILER) {
158                         /* The PV from the compiler stub is equal to the XPC. */
159
160                         pv = xpc;
161
162                         /* We use a framesize of zero here because the call pushed
163                            the return addres onto the stack. */
164
165                         ra = md_stacktrace_get_returnaddress(sp, 0);
166
167                         /* Skip the RA on the stack. */
168
169                         sp = sp + 1 * SIZEOF_VOID_P;
170
171                         /* The XPC is the RA minus 1, because the RA points to the
172                            instruction after the call. */
173
174                         xpc = ra - 3;
175                 }
176         }
177         else {
178                 /* this was a normal NPE */
179
180                 type = EXCEPTION_HARDWARE_NULLPOINTER;
181                 val  = 0;
182         }
183
184         /* Handle the type. */
185
186         p = signal_handle(type, val, pv, sp, ra, xpc, _p);
187
188         /* Set registers. */
189
190         if (type == EXCEPTION_HARDWARE_COMPILER) {
191                 if (p == NULL) {
192                         o = builtin_retrieve_exception();
193
194                         _mc->gregs[REG_RSP] = (uintptr_t) sp;    /* Remove RA from stack. */
195
196                         _mc->gregs[REG_RAX] = (uintptr_t) o;
197                         _mc->gregs[REG_R10] = (uintptr_t) xpc;           /* REG_ITMP2_XPC */
198                         _mc->gregs[REG_RIP] = (uintptr_t) asm_handle_exception;
199                 }
200                 else {
201                         _mc->gregs[REG_RIP] = (uintptr_t) p;
202                 }
203         }
204         else {
205                 _mc->gregs[REG_RAX] = (uintptr_t) p;
206                 _mc->gregs[REG_R10] = (uintptr_t) xpc;               /* REG_ITMP2_XPC */
207                 _mc->gregs[REG_RIP] = (uintptr_t) asm_handle_exception;
208         }
209 }
210
211
212 /* md_signal_handler_sigfpe ****************************************************
213
214    ArithmeticException signal handler for hardware divide by zero
215    check.
216
217 *******************************************************************************/
218
219 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
220 {
221         ucontext_t     *_uc;
222         mcontext_t     *_mc;
223         u1             *pv;
224         u1             *sp;
225         u1             *ra;
226         u1             *xpc;
227         int             type;
228         intptr_t        val;
229         void           *p;
230
231         _uc = (ucontext_t *) _p;
232         _mc = &_uc->uc_mcontext;
233
234         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
235            different to the ones in <ucontext.h>. */
236
237         pv  = NULL;
238         sp  = (u1 *) _mc->gregs[REG_RSP];
239         xpc = (u1 *) _mc->gregs[REG_RIP];
240         ra  = xpc;                          /* return address is equal to xpc     */
241
242         /* this is an ArithmeticException */
243
244         type = EXCEPTION_HARDWARE_ARITHMETIC;
245         val  = 0;
246
247         /* Handle the type. */
248
249         p = signal_handle(type, val, pv, sp, ra, xpc, _p);
250
251         /* set registers */
252
253         _mc->gregs[REG_RAX] = (intptr_t) p;
254         _mc->gregs[REG_R10] = (intptr_t) xpc;                    /* REG_ITMP2_XPC */
255         _mc->gregs[REG_RIP] = (intptr_t) asm_handle_exception;
256 }
257
258
259 /* md_signal_handler_sigill ****************************************************
260
261    Signal handler for patchers.
262
263 *******************************************************************************/
264
265 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
266 {
267         ucontext_t     *_uc;
268         mcontext_t     *_mc;
269         u1             *pv;
270         u1             *sp;
271         u1             *ra;
272         u1             *xpc;
273         int             type;
274         intptr_t        val;
275         void           *p;
276
277         _uc = (ucontext_t *) _p;
278         _mc = &_uc->uc_mcontext;
279
280         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
281            different to the ones in <ucontext.h>. */
282
283         pv  = NULL;
284         sp  = (u1 *) _mc->gregs[REG_RSP];
285         xpc = (u1 *) _mc->gregs[REG_RIP];
286         ra  = xpc;                          /* return address is equal to xpc     */
287
288         /* This is a patcher. */
289
290         type = EXCEPTION_HARDWARE_PATCHER;
291         val  = 0;
292
293         /* Handle the type. */
294
295         p = signal_handle(type, val, pv, sp, ra, xpc, _p);
296
297         /* set registers */
298
299         if (p != NULL) {
300                 _mc->gregs[REG_RAX] = (intptr_t) p;
301                 _mc->gregs[REG_R10] = (intptr_t) xpc;                /* REG_ITMP2_XPC */
302                 _mc->gregs[REG_RIP] = (intptr_t) asm_handle_exception;
303         }
304 }
305
306
307 /* md_signal_handler_sigusr1 ***************************************************
308
309    Signal handler for suspending threads.
310
311 *******************************************************************************/
312
313 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
314 void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
315 {
316         ucontext_t *_uc;
317         mcontext_t *_mc;
318         u1         *pc;
319         u1         *sp;
320
321         _uc = (ucontext_t *) _p;
322         _mc = &_uc->uc_mcontext;
323
324         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
325            different to the ones in <ucontext.h>. */
326
327         /* get the PC and SP for this thread */
328         pc = (u1 *) _mc->gregs[REG_RIP];
329         sp = (u1 *) _mc->gregs[REG_RSP];
330
331         /* now suspend the current thread */
332         threads_suspend_ack(pc, sp);
333 }
334 #endif
335
336
337 /* md_signal_handler_sigusr2 ***************************************************
338
339    Signal handler for profiling sampling.
340
341 *******************************************************************************/
342
343 #if defined(ENABLE_THREADS)
344 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
345 {
346         threadobject *t;
347         ucontext_t   *_uc;
348         mcontext_t   *_mc;
349         u1           *pc;
350
351         t = THREADOBJECT;
352
353         _uc = (ucontext_t *) _p;
354         _mc = &_uc->uc_mcontext;
355
356         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
357            different to the ones in <ucontext.h>. */
358
359         pc = (u1 *) _mc->gregs[REG_RIP];
360
361         t->pc = pc;
362 }
363 #endif
364
365
366 /* md_replace_executionstate_read **********************************************
367
368    Read the given context into an executionstate for Replacement.
369
370 *******************************************************************************/
371
372 #if defined(ENABLE_REPLACEMENT)
373 void md_replace_executionstate_read(executionstate_t *es, void *context)
374 {
375         ucontext_t *_uc;
376         mcontext_t *_mc;
377         s4          i;
378         s4          d;
379
380         _uc = (ucontext_t *) context;
381         _mc = &_uc->uc_mcontext;
382
383         /* read special registers */
384         es->pc = (u1 *) _mc->gregs[REG_RSP];
385         es->sp = (u1 *) _mc->gregs[REG_RSP];
386         es->pv = NULL;
387
388         /* read integer registers */
389         for (i = 0; i < INT_REG_CNT; i++) {
390                 /* XXX FIX ME! */
391
392                 switch (i) {
393                 case 0:  /* REG_RAX == 13 */
394                         d = REG_RAX;
395                         break;
396                 case 1:  /* REG_RCX == 14 */
397                         d = REG_RCX;
398                         break;
399                 case 2:  /* REG_RDX == 12 */
400                         d = REG_RDX;
401                         break;
402                 case 3:  /* REG_RBX == 11 */
403                         d = REG_RBX;
404                         break;
405                 case 4:  /* REG_RSP == 15 */
406                         d = REG_RSP;
407                         break;
408                 case 5:  /* REG_RBP == 10 */
409                         d = REG_RBP;
410                         break;
411                 case 6:  /* REG_RSI == 9  */
412                         d = REG_RSI;
413                         break;
414                 case 7:  /* REG_RDI == 8  */
415                         d = REG_RDI;
416                         break;
417                 case 8:  /* REG_R8  == 0  */
418                 case 9:  /* REG_R9  == 1  */
419                 case 10: /* REG_R10 == 2  */
420                 case 11: /* REG_R11 == 3  */
421                 case 12: /* REG_R12 == 4  */
422                 case 13: /* REG_R13 == 5  */
423                 case 14: /* REG_R14 == 6  */
424                 case 15: /* REG_R15 == 7  */
425                         d = i - 8;
426                         break;
427                 }
428
429                 es->intregs[i] = _mc->gregs[d];
430         }
431
432         /* read float registers */
433         for (i = 0; i < FLT_REG_CNT; i++)
434                 es->fltregs[i] = 0xdeadbeefdeadbeefL;
435 }
436 #endif
437
438
439 /* md_replace_executionstate_write *********************************************
440
441    Write the given executionstate back to the context for Replacement.
442
443 *******************************************************************************/
444
445 #if defined(ENABLE_REPLACEMENT)
446 void md_replace_executionstate_write(executionstate_t *es, void *context)
447 {
448         ucontext_t *_uc;
449         mcontext_t *_mc;
450         s4          i;
451         s4          d;
452
453         _uc = (ucontext_t *) context;
454         _mc = &_uc->uc_mcontext;
455
456         /* write integer registers */
457         for (i = 0; i < INT_REG_CNT; i++) {
458                 /* XXX FIX ME! */
459
460                 switch (i) {
461                 case 0:  /* REG_RAX == 13 */
462                         d = REG_RAX;
463                         break;
464                 case 1:  /* REG_RCX == 14 */
465                         d = REG_RCX;
466                         break;
467                 case 2:  /* REG_RDX == 12 */
468                         d = REG_RDX;
469                         break;
470                 case 3:  /* REG_RBX == 11 */
471                         d = REG_RBX;
472                         break;
473                 case 4:  /* REG_RSP == 15 */
474                         d = REG_RSP;
475                         break;
476                 case 5:  /* REG_RBP == 10 */
477                         d = REG_RBP;
478                         break;
479                 case 6:  /* REG_RSI == 9  */
480                         d = REG_RSI;
481                         break;
482                 case 7:  /* REG_RDI == 8  */
483                         d = REG_RDI;
484                         break;
485                 case 8:  /* REG_R8  == 0  */
486                 case 9:  /* REG_R9  == 1  */
487                 case 10: /* REG_R10 == 2  */
488                 case 11: /* REG_R11 == 3  */
489                 case 12: /* REG_R12 == 4  */
490                 case 13: /* REG_R13 == 5  */
491                 case 14: /* REG_R14 == 6  */
492                 case 15: /* REG_R15 == 7  */
493                         d = i - 8;
494                         break;
495                 }
496
497                 _mc->gregs[d] = es->intregs[i];
498         }
499
500         /* write special registers */
501         _mc->gregs[REG_RIP] = (ptrint) es->pc;
502         _mc->gregs[REG_RSP] = (ptrint) es->sp;
503 }
504 #endif
505
506
507 /* md_critical_section_restart *************************************************
508
509    Search the critical sections tree for a matching section and set
510    the PC to the restart point, if necessary.
511
512 *******************************************************************************/
513
514 #if defined(ENABLE_THREADS)
515 void md_critical_section_restart(ucontext_t *_uc)
516 {
517         mcontext_t *_mc;
518         u1         *pc;
519         u1         *npc;
520
521         _mc = &_uc->uc_mcontext;
522
523         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
524            different to the ones in <ucontext.h>. */
525
526         pc = (u1 *) _mc->gregs[REG_RIP];
527
528         npc = critical_find_restart_point(pc);
529
530         if (npc != NULL)
531                 _mc->gregs[REG_RIP] = (ptrint) npc;
532 }
533 #endif
534
535
536 /*
537  * These are local overrides for various environment variables in Emacs.
538  * Please do not remove this and leave it at the end of the file, where
539  * Emacs will automagically detect them.
540  * ---------------------------------------------------------------------
541  * Local variables:
542  * mode: c
543  * indent-tabs-mode: t
544  * c-basic-offset: 4
545  * tab-width: 4
546  * End:
547  * vim:noexpandtab:sw=4:ts=4:
548  */