mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			221 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
| // s390-signal.h - Catch runtime signals and turn them into exceptions
 | |
| // on an s390 based Linux system.
 | |
| 
 | |
| /* Copyright (C) 2002  Free Software Foundation
 | |
| 
 | |
|    This file is part of libgcj.
 | |
| 
 | |
| This software is copyrighted work licensed under the terms of the
 | |
| Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
 | |
| details.  */
 | |
| 
 | |
| 
 | |
| #ifndef JAVA_SIGNAL_H
 | |
| #define JAVA_SIGNAL_H 1
 | |
| 
 | |
| #include <signal.h>
 | |
| #include <sys/syscall.h>
 | |
| #include <ucontext.h>
 | |
| #include <limits.h>
 | |
| 
 | |
| #define HANDLE_SEGV 1
 | |
| #define HANDLE_FPE 1
 | |
| 
 | |
| #define SIGNAL_HANDLER(_name)	\
 | |
| static void _name (int, siginfo_t *_si __attribute__((unused)), \
 | |
| 		   ucontext_t *_uc __attribute__((unused)))
 | |
| 
 | |
| /* We no longer need to fiddle with the PSW address in the signal handler;
 | |
|    this is now all handled correctly in MD_FALLBACK_FRAME_STATE_FOR.  */
 | |
| #define MAKE_THROW_FRAME(_exception)
 | |
| 
 | |
| 
 | |
| /* According to the JVM spec, "if the dividend is the negative integer 
 | |
|    of the smallest magnitude and the divisor is -1, then overflow occurs 
 | |
|    and the result is equal to the dividend.  Despite the overflow, no 
 | |
|    exception occurs".
 | |
| 
 | |
|    We handle this by inspecting the instruction which generated the signal,
 | |
|    and if dividend and divisor are as above, we simply return from the signal
 | |
|    handler.  This causes execution to continue after the instruction.  
 | |
|    Before returning, we the set result registers as expected.  */
 | |
| 
 | |
| #define HANDLE_DIVIDE_OVERFLOW						\
 | |
| do									\
 | |
| {									\
 | |
|   unsigned char *_eip = (unsigned char *)				\
 | |
|     __builtin_extract_return_addr (_si->si_addr);			\
 | |
|   unsigned long *_regs = _uc->uc_mcontext.gregs;			\
 | |
|   int _r1, _r2, _d2, _x2, _b2;						\
 | |
| 									\
 | |
|   /* First, a couple of helper routines to decode instructions.  */	\
 | |
|   struct _decode 							\
 | |
|     {									\
 | |
|       /* Decode RR instruction format.  */				\
 | |
|       static inline int _is_rr (unsigned char *_eip, 			\
 | |
| 				unsigned char _op,			\
 | |
| 				int *_r1, int *_r2) 			\
 | |
|       {									\
 | |
| 	if (_eip[0] == _op)						\
 | |
| 	  {								\
 | |
| 	    *_r1 = _eip[1] >> 4;					\
 | |
| 	    *_r2 = _eip[1] & 0xf;					\
 | |
| 	    return 1;							\
 | |
| 	  }								\
 | |
| 	return 0;							\
 | |
|       }									\
 | |
| 									\
 | |
|       /* Decode RX instruction format.  */				\
 | |
|       static inline int _is_rx (unsigned char *_eip,			\
 | |
| 				unsigned char _op,			\
 | |
| 				int *_r1, int *_d2, int *_x2, int *_b2) \
 | |
|       {									\
 | |
| 	if (_eip[0] == _op)						\
 | |
| 	  {								\
 | |
| 	    *_r1 = _eip[1] >> 4;					\
 | |
| 	    *_x2 = _eip[1] & 0xf;					\
 | |
| 	    *_b2 = _eip[2] >> 4;					\
 | |
| 	    *_d2 = ((_eip[2] & 0xf) << 8) + _eip[3];			\
 | |
| 	    return 1;							\
 | |
| 	  }								\
 | |
| 	return 0;							\
 | |
|       }									\
 | |
| 									\
 | |
|       /* Decode RRE instruction format.  */				\
 | |
|       static inline int _is_rre (unsigned char *_eip,			\
 | |
| 				 unsigned char _op1, unsigned char _op2,\
 | |
| 				 int *_r1, int *_r2)			\
 | |
|       {									\
 | |
| 	if (_eip[0] == _op1 && _eip[1] == _op2)				\
 | |
| 	  {								\
 | |
| 	    *_r1 = _eip[3] >> 4;					\
 | |
| 	    *_r2 = _eip[3] & 0xf;					\
 | |
| 	    return 1;							\
 | |
| 	  }								\
 | |
| 	return 0;							\
 | |
|       }									\
 | |
| 									\
 | |
|       /* Decode RXY instruction format.  */				\
 | |
|       static inline int _is_rxy (unsigned char *_eip,			\
 | |
| 				 unsigned char _op1, unsigned char _op2,\
 | |
| 				 int *_r1, int *_d2, int *_x2, int *_b2)\
 | |
|       {									\
 | |
| 	if (_eip[0] == _op1 && _eip[5] == _op2)				\
 | |
| 	  {								\
 | |
| 	    *_r1 = _eip[1] >> 4;					\
 | |
| 	    *_x2 = _eip[1] & 0xf;					\
 | |
| 	    *_b2 = _eip[2] >> 4;					\
 | |
| 	    *_d2 = ((_eip[2] & 0xf) << 8) + _eip[3] + (_eip[4] << 12);	\
 | |
| 	    /* We have a 20-bit signed displacement.  */		\
 | |
| 	    *_d2 = (*_d2 ^ 0x80000) - 0x80000;				\
 | |
| 	    return 1;							\
 | |
| 	  }								\
 | |
| 	return 0;							\
 | |
|       }									\
 | |
| 									\
 | |
|       /* Compute effective address.  */					\
 | |
|       static inline unsigned long _eff (unsigned long *_regs,		\
 | |
| 					long _d, int _x, int _b)	\
 | |
|       {									\
 | |
| 	return _d + (_x? _regs[_x] : 0) + (_b? _regs[_b] : 0);		\
 | |
|       }									\
 | |
|     };									\
 | |
| 									\
 | |
| 									\
 | |
|   /* DR r1,r2 */							\
 | |
|   if (_decode::_is_rr (_eip, 0x1d, &_r1, &_r2)				\
 | |
|       && (int) _regs[_r1] == -1 && (int) _regs[_r1+1] == INT_MIN	\
 | |
|       && (int) _regs[_r2] == -1)					\
 | |
|     {									\
 | |
|       _regs[_r1] &= ~0xffffffff;					\
 | |
|       return;								\
 | |
|     }									\
 | |
|  									\
 | |
|   /* D r1,d2(x2,b2) */							\
 | |
|   if (_decode::_is_rx (_eip, 0x5d, &_r1, &_d2, &_x2, &_b2)		\
 | |
|       && (int) _regs[_r1] == -1 && (int) _regs[_r1+1] == INT_MIN	\
 | |
|       && *(int *) _decode::_eff (_regs, _d2, _x2, _b2) == -1)		\
 | |
|     {									\
 | |
|       _regs[_r1] &= ~0xffffffff;					\
 | |
|       return;								\
 | |
|     }									\
 | |
| 									\
 | |
|   /* DSGR r1,r2 */							\
 | |
|   if (_decode::_is_rre (_eip, 0xb9, 0x0d, &_r1, &_r2)			\
 | |
|       && (long) _regs[_r1+1] == LONG_MIN				\
 | |
|       && (long) _regs[_r2] == -1L)					\
 | |
|     {									\
 | |
|       _regs[_r1] = 0;							\
 | |
|       return;								\
 | |
|     }									\
 | |
| 									\
 | |
|   /* DSGFR r1,r2 */							\
 | |
|   if (_decode::_is_rre (_eip, 0xb9, 0x1d, &_r1, &_r2)			\
 | |
|       && (long) _regs[_r1+1] == LONG_MIN				\
 | |
|       && (int) _regs[_r2] == -1)					\
 | |
|     {									\
 | |
|       _regs[_r1] = 0;							\
 | |
|       return;								\
 | |
|     }									\
 | |
| 									\
 | |
|   /* DSG r1,d2(x2,b2) */						\
 | |
|   if (_decode::_is_rxy (_eip, 0xe3, 0x0d, &_r1, &_d2, &_x2, &_b2)	\
 | |
|       && (long) _regs[_r1+1] == LONG_MIN				\
 | |
|       && *(long *) _decode::_eff (_regs, _d2, _x2, _b2) == -1L)		\
 | |
|     {									\
 | |
|       _regs[_r1] = 0;							\
 | |
|       return;								\
 | |
|     }									\
 | |
| 									\
 | |
|   /* DSGF r1,d2(x2,b2) */						\
 | |
|   if (_decode::_is_rxy (_eip, 0xe3, 0x1d, &_r1, &_d2, &_x2, &_b2)	\
 | |
|       && (long) _regs[_r1+1] == LONG_MIN				\
 | |
|       && *(int *) _decode::_eff (_regs, _d2, _x2, _b2) == -1)		\
 | |
|     {									\
 | |
|       _regs[_r1] = 0;							\
 | |
|       return;								\
 | |
|     }									\
 | |
| 									\
 | |
| }									\
 | |
| while (0)
 | |
| 
 | |
| /* For an explanation why we cannot simply use sigaction to
 | |
|    install the handlers, see i386-signal.h.  */
 | |
| 
 | |
| /* We use old_kernel_sigaction here because we're calling the kernel
 | |
|    directly rather than via glibc.  The sigaction structure that the
 | |
|    syscall uses is a different shape from the one in userland and not
 | |
|    visible to us in a header file so we define it here.  */
 | |
| 
 | |
| struct old_s390_kernel_sigaction {
 | |
| 	void (*k_sa_handler) (int, siginfo_t *, ucontext_t *);
 | |
| 	unsigned long k_sa_mask;
 | |
| 	unsigned long k_sa_flags;
 | |
| 	void (*sa_restorer) (void);
 | |
| };
 | |
| 
 | |
| #define INIT_SEGV					\
 | |
| do							\
 | |
|   {							\
 | |
|     struct old_s390_kernel_sigaction kact;		\
 | |
|     kact.k_sa_handler = catch_segv;			\
 | |
|     kact.k_sa_mask = 0;					\
 | |
|     kact.k_sa_flags = SA_SIGINFO;			\
 | |
|     syscall (SYS_sigaction, SIGSEGV, &kact, NULL);	\
 | |
|   }							\
 | |
| while (0)  
 | |
| 
 | |
| #define INIT_FPE						\
 | |
| do								\
 | |
|   {								\
 | |
|     struct old_s390_kernel_sigaction kact;			\
 | |
|     kact.k_sa_handler = catch_fpe;				\
 | |
|     kact.k_sa_mask = 0;						\
 | |
|     kact.k_sa_flags = SA_SIGINFO;				\
 | |
|     syscall (SYS_sigaction, SIGFPE, &kact, NULL);		\
 | |
|   }								\
 | |
| while (0)  
 | |
| 
 | |
| #endif /* JAVA_SIGNAL_H */
 | |
| 
 |