src/vm/jit/stacktrace.c (stacktrace_print_entry): New function.
[cacao.git] / src / vm / jit / s390 / md.c
1 /* src/vm/jit/s390/md.c - machine dependent s390 Linux functions
2
3    Copyright (C) 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #define _GNU_SOURCE
27
28 #include "config.h"
29
30 #include <assert.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <ucontext.h>
34
35 #include "vm/jit/s390/md-abi.h"
36
37 #include "threads/thread.h"
38
39 #include "vm/exceptions.h"
40 #include "vm/signallocal.h"
41 #include "vm/jit/asmpart.h"
42 #include "vm/jit/abi.h"
43 #include "vm/jit/methodheader.h"
44 #include "vm/jit/methodtree.h"
45 #include "vm/jit/stacktrace.h"
46
47 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
48 #include "vmcore/options.h" /* XXX debug */
49 #include "vm/jit/disass.h" /* XXX debug */
50 #endif
51
52 #include "vm/jit/codegen-common.h"
53 #include "vm/jit/s390/codegen.h"
54 #include "vm/jit/s390/md.h"
55
56
57 /* prototypes *****************************************************************/
58
59 u1 *exceptions_handle_exception(java_object_t *xptro, u1 *xpc, u1 *pv, u1 *sp);
60
61 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
62
63 void md_dump_context(u1 *pc, mcontext_t *mc);
64
65 /* md_init *********************************************************************
66
67    Do some machine dependent initialization.
68
69 *******************************************************************************/
70
71 void md_init(void)
72 {
73 }
74
75 /* md_dump_context ************************************************************
76  
77    Logs the machine context
78   
79 *******************************************************************************/
80
81 void md_dump_context(u1 *pc, mcontext_t *mc) {
82         int i;
83         u1 *pv;
84         methodinfo *m;
85
86         union {
87                 u8 l;
88                 fpreg_t fr;
89         } freg;
90
91         log_println("Dumping context.");
92
93         log_println("Program counter: 0x%08X", pc);
94
95         pv = methodtree_find_nocheck(pc);
96
97         if (pv == NULL) {
98                 log_println("No java method found at location.");
99         } else {
100                 m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
101                 log_println(
102                         "Java method: class %s, method %s, descriptor %s.",
103                         m->class->name->text, m->name->text, m->descriptor->text
104                 );
105         }
106
107 #if defined(ENABLE_DISASSEMBLER)
108         log_println("Printing instruction at program counter:");
109         disassinstr(pc);
110 #endif
111
112         log_println("General purpose registers:");
113
114         for (i = 0; i < 16; i++) {
115                 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
116         }
117
118         log_println("Floating point registers:");
119
120         for (i = 0; i < 16; i++) {
121                 freg.fr.d = mc->fpregs.fprs[i].d;
122                 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
123         }
124
125         log_println("Dumping the current stacktrace:");
126         stacktrace_print_current();
127 }
128
129 /* md_signal_handler_sigsegv ***************************************************
130
131    NullPointerException signal handler for hardware null pointer
132    check.
133
134 *******************************************************************************/
135
136 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
137 {
138         ucontext_t     *_uc;
139         mcontext_t     *_mc;
140         u1             *pv;
141         u1             *sp;
142         u1             *ra;
143         u1             *xpc;
144         int             type;
145         intptr_t        val;
146         void           *p;
147         s4              base;
148         s4              is_null;
149
150         _uc = (ucontext_t *) _p;
151         _mc = &_uc->uc_mcontext;
152
153         xpc = (u1 *)_mc->psw.addr;
154
155         /* Check opcodes and verify it is a null pointer exception */
156
157         switch (N_RX_GET_OPC(xpc)) {
158                 case OPC_L:
159                 case OPC_ST:
160                 case OPC_CL: /* array size check on NULL array */
161                         base = N_RX_GET_BASE(xpc);
162                         if (base == 0) {
163                                 is_null = 1;
164                         } else if (_mc->gregs[base] == 0) {
165                                 is_null = 1;
166                         } else {
167                                 is_null = 0;
168                         }
169                         break;
170                 default:
171                         is_null = 0;
172                         break;
173         }
174
175         if (! is_null) {
176 #if !defined(NDEBUG)
177                 md_dump_context(xpc, _mc);
178 #endif
179                 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
180         }
181
182         pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
183         sp = (u1 *)_mc->gregs[REG_SP];
184         ra = xpc;
185         type = EXCEPTION_HARDWARE_NULLPOINTER;
186         val = 0;
187
188         /* Handle the type. */
189
190         p = signal_handle(type, val, pv, sp, ra, xpc, _p);
191
192         if (p != NULL) {
193                 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
194                 _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
195                 _mc->psw.addr              = (intptr_t) asm_handle_exception;
196         }
197         else {
198                 _mc->psw.addr              = (intptr_t) xpc;
199         }
200 }
201
202 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
203 {
204         ucontext_t     *_uc;
205         mcontext_t     *_mc;
206         u1             *xpc;
207         u1             *ra;
208         u1             *pv;
209         u1             *sp;
210         int             type;
211         intptr_t        val;
212         void           *p;
213         s4              reg;
214
215         _uc = (ucontext_t *) _p;
216         _mc = &_uc->uc_mcontext;
217         xpc = ra = siginfo->si_addr;
218
219         /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
220
221         if ((siginfo->si_code == ILL_ILLOPC) && (N_RR_GET_OPC(xpc) == OPC_ILL)) {
222
223                 /* bits 7-4 contain a register holding a value */
224                 reg = N_ILL_GET_REG(xpc);
225
226                 /* bits 3-0 designate the exception type */
227                 type = N_ILL_GET_TYPE(xpc);
228
229                 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
230                 sp = (u1 *)_mc->gregs[REG_SP];
231                 val = (ptrint)_mc->gregs[reg];
232
233                 if (EXCEPTION_HARDWARE_COMPILER == type) {
234                         /* The PV from the compiler stub is equal to the XPC. */
235
236                         pv = xpc;
237
238                         /* The return address in is REG_RA */
239
240                         ra = (u1 *)_mc->gregs[REG_RA];
241
242                         xpc = ra - 2;
243                 }
244
245                 /* Handle the type. */
246
247                 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
248
249                 if (EXCEPTION_HARDWARE_COMPILER == type) {
250                         if (NULL == p) {
251                                 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) builtin_retrieve_exception();
252                                 _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) ra - 2;
253                                 _mc->gregs[REG_PV]         = (intptr_t) md_codegen_get_pv_from_pc(ra);
254                                 _mc->psw.addr              = (intptr_t) asm_handle_exception;
255                         } else {
256                                 _mc->gregs[REG_PV]         = (intptr_t) p;
257                                 _mc->psw.addr              = (intptr_t) p;
258                         }
259                 } else {
260                         if (p != NULL) {
261                                 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
262                                 _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
263                                 _mc->psw.addr              = (intptr_t) asm_handle_exception;
264                         }
265                         else {
266                                 _mc->psw.addr              = (intptr_t) xpc;
267                         }
268                 }
269         } else {
270 #if !defined(NDEBUG)
271                 md_dump_context(xpc, _mc);
272 #endif
273                 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
274         }
275 }
276
277 /* md_signal_handler_sigfpe ****************************************************
278
279    ArithmeticException signal handler for hardware divide by zero
280    check.
281
282 *******************************************************************************/
283
284 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
285 {
286         ucontext_t     *_uc;
287         mcontext_t     *_mc;
288         u1             *pv;
289         u1             *sp;
290         u1             *ra;
291         u1             *xpc;
292         u1             *pc;
293         int             r1, r2;
294         int             type;
295         intptr_t        val;
296         void           *p;
297
298         _uc = (ucontext_t *) _p;
299         _mc = &_uc->uc_mcontext;
300
301         /* Instruction that raised signal */
302         xpc = siginfo->si_addr;
303
304         /* Check opcodes */
305
306         if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
307
308                 r1 = N_RR_GET_REG1(xpc);
309                 r2 = N_RR_GET_REG2(xpc);
310
311                 if (
312                         (_mc->gregs[r1] == 0xFFFFFFFF) &&
313                         (_mc->gregs[r1 + 1] == 0x80000000) && 
314                         (_mc->gregs[r2] == 0xFFFFFFFF)
315                 ) {
316                         /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
317                         /* next instruction */
318                         pc = (u1 *)_mc->psw.addr;
319                         /* reminder */
320                         _mc->gregs[r1] = 0;
321                         /* quotient */
322                         _mc->gregs[r1 + 1] = 0x80000000;
323                         /* continue at next instruction */
324                         _mc->psw.addr = (ptrint) pc;
325
326                         return;
327                 }
328                 else if (_mc->gregs[r2] == 0) {
329                         /* division by 0 */
330
331                         pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
332                         sp = (u1 *)_mc->gregs[REG_SP];
333                         ra = xpc;
334
335                         type = EXCEPTION_HARDWARE_ARITHMETIC;
336                         val = 0;
337
338                         /* Handle the type. */
339
340                         p = signal_handle(type, val, pv, sp, ra, xpc, _p);
341
342                         _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
343                         _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
344                         _mc->psw.addr              = (intptr_t) asm_handle_exception;
345
346                         return;
347                 }
348         }
349
350         /* Could not handle signal */
351
352 #if !defined(NDEBUG)
353         md_dump_context(xpc, _mc);
354 #endif
355         vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
356 }
357
358
359 /* md_signal_handler_sigusr2 ***************************************************
360
361    Signal handler for profiling sampling.
362
363 *******************************************************************************/
364
365 #if defined(ENABLE_THREADS)
366 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
367 {
368         threadobject *t;
369         ucontext_t   *_uc;
370         mcontext_t   *_mc;
371         u1           *pc;
372
373         t = THREADOBJECT;
374
375         _uc = (ucontext_t *) _p;
376         _mc = &_uc->uc_mcontext;
377
378         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
379            different to the ones in <ucontext.h>. */
380
381         pc = (u1 *) _mc->psw.addr;
382
383         t->pc = pc;
384 }
385 #endif
386
387
388 #if defined(ENABLE_THREADS)
389 void md_critical_section_restart(ucontext_t *_uc)
390 {
391         mcontext_t *_mc;
392         u1         *pc;
393         void       *npc;
394
395         _mc = &_uc->uc_mcontext;
396
397         pc = (u1 *)_mc->psw.addr;
398
399         npc = critical_find_restart_point(pc);
400
401         if (npc != NULL) {
402                 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
403                 _mc->psw.addr = (ptrint) npc;
404         }
405 }
406 #endif
407
408
409 /* md_jit_method_patch_address *************************************************
410
411    Gets the patch address of the currently compiled method. The offset
412    is extracted from the load instruction(s) before the jump and added
413    to the right base address (PV or REG_METHODPTR).
414
415    INVOKESTATIC/SPECIAL:
416
417 0x7748d7b2:   a7 18 ff d4                      lhi      %r1,-44  
418 (load dseg offset)
419 0x7748d7b6:   58 d1 d0 00                      l        %r13,0(%r1,%r13)
420 (load pv)
421 0x7748d7ba:   0d ed                            basr     %r14,%r13
422 (jump to pv)
423
424    INVOKEVIRTUAL:
425
426 0x7748d82a:   58 c0 20 00                      l        %r12,0(%r2)
427 (load mptr)
428 0x7748d82e:   58 d0 c0 00                      l        %r13,0(%r12)
429 (load pv from mptr)
430 0x7748d832:   0d ed                            basr     %r14,%r13
431 (jump to pv)
432
433
434    INVOKEINTERFACE:
435
436 last 2 instructions the same as in invokevirtual
437
438 *******************************************************************************/
439
440 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
441 {
442         uint8_t *pc;
443         uint8_t  base, index;
444         int32_t  offset;
445         void    *pa;                        /* patch address                      */
446
447         /* go back to the load before the call instruction */
448
449         pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
450
451         /* get the base register of the load */
452
453         base  = N_RX_GET_BASE(pc);
454         index = N_RX_GET_INDEX(pc);
455
456         /* check for the different calls */
457
458         switch (base) {
459                 case REG_PV:
460                         /* INVOKESTATIC/SPECIAL */
461
462                         switch (index) {
463                                 case R0:
464                                         /* the offset is in the load instruction */
465                                         offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
466                                         break;
467                                 case REG_ITMP1:
468                                         /* the offset is in the immediate load before the load */
469                                         offset = N_RI_GET_IMM(pc - SZ_L);
470                                         break;
471                                 default:
472                                         assert(0);
473                         }
474
475                         /* add the offset to the procedure vector */
476
477                         pa = ((uint8_t *) pv) + offset;
478                         break;
479
480                 case REG_METHODPTR:
481                         /* mptr relative */
482                         /* INVOKEVIRTUAL/INTERFACE */
483
484                         offset = N_RX_GET_DISP(pc);
485
486                         /* return NULL if no mptr was specified (used for replacement) */
487
488                         if (mptr == NULL)
489                                 return NULL;
490
491                         /* add offset to method pointer */
492                         
493                         pa = (uint8_t *)mptr + offset;
494                         break;
495
496                 default:
497                         /* catch any problems */
498                         vm_abort("md_jit_method_patch_address");
499                         break;
500         }
501
502         return pa;
503 }
504
505
506 /* md_patch_replacement_point **************************************************
507
508    Patch the given replacement point.
509
510 *******************************************************************************/
511 #if defined(ENABLE_REPLACEMENT)
512 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
513 {
514         assert(0);
515 }
516 #endif
517
518 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
519
520         uint8_t *xptr;
521         uint8_t *xpc;
522         uint8_t *sp;
523         uint8_t *pv;
524         uint8_t *ra;
525         uint8_t *handler;
526         int32_t framesize;
527         int32_t intsave;
528         int32_t fltsave;
529         int64_t *savearea;
530         int i;
531         int reg;
532         int loops = 0;
533
534         /* get registers */
535
536         xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
537         xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
538         sp = *(uint8_t **)(regs + REG_SP);
539
540
541         /* initialize number of calle saved int regs to restore to 0 */
542         out[0] = 0;
543
544         /* initialize number of calle saved flt regs to restore to 0 */
545         out[1] = 0;
546
547         do {
548
549                 ++loops;
550
551                 pv = methodtree_find(xpc);
552
553                 handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
554
555                 if (handler == NULL) {
556
557                         /* exception was not handled
558                          * get values of calee saved registers and remove stack frame 
559                          */
560
561                         /* read stuff from data segment */
562
563                         framesize = *(int32_t *)(pv + FrameSize);
564
565                         intsave = *(int32_t *)(pv + IntSave);
566                         if (intsave > out[0]) {
567                                 out[0] = intsave;
568                         }
569
570                         fltsave = *(int32_t *)(pv + FltSave);
571                         if (fltsave > out[1]) {
572                                 out[1] = fltsave;
573                         }
574
575                         /* pointer to register save area */
576
577                         savearea = (int64_t *)(sp + framesize - 8);
578
579                         /* return address */
580
581                         ra = *(uint8_t **)(sp + framesize - 8);
582
583                         /* restore saved registers */
584
585                         for (i = 0; i < intsave; ++i) {
586                                 --savearea;
587                                 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
588                                 regs[reg] = *(int32_t *)(savearea);
589                         }
590
591                         for (i = 0; i < fltsave; ++i) {
592                                 --savearea;
593                                 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
594                                 fregs[reg] = *savearea;
595                         }
596
597                         /* remove stack frame */
598
599                         sp += framesize;
600
601                         /* new xpc is call before return address */
602
603                         xpc = ra - 2;
604
605                 } else {
606                         xpc = handler;
607                 }
608         } while (handler == NULL);
609
610         /* write new values for registers */
611
612         *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
613         *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
614         *(uint8_t **)(regs + REG_SP) = sp;
615         *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
616
617         /* maybe leaf flag */
618
619         out[2] = (loops == 1);
620 }
621
622 /*
623  * These are local overrides for various environment variables in Emacs.
624  * Please do not remove this and leave it at the end of the file, where
625  * Emacs will automagically detect them.
626  * ---------------------------------------------------------------------
627  * Local variables:
628  * mode: c
629  * indent-tabs-mode: t
630  * c-basic-offset: 4
631  * tab-width: 4
632  * End:
633  * vim:noexpandtab:sw=4:ts=4:
634  */