Home | History | Annotate | Download | only in lapi
      1 /*
      2  * Copyright (c) 2009 Cisco Systems, Inc.  All Rights Reserved.
      3  * Copyright (c) 2009 FUJITSU LIMITED.  All Rights Reserved.
      4  *
      5  * This program is free software; you can redistribute it and/or modify it
      6  * under the terms of version 2 of the GNU General Public License as
      7  * published by the Free Software Foundation.
      8  *
      9  * This program is distributed in the hope that it would be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     12  *
     13  * Further, this software is distributed without any warranty that it is
     14  * free of the rightful claim of any third person regarding infringement
     15  * or the like.  Any license provided herein, whether implied or
     16  * otherwise, applies only to this software file.  Patent licenses, if
     17  * any, provided herein do not apply to combinations of this program with
     18  * other software, or any other product whatsoever.
     19  *
     20  * You should have received a copy of the GNU General Public License along
     21  * with this program; if not, write the Free Software Foundation, Inc.,
     22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     23  *
     24  * Author: Liu Bo <liubo2009 (at) cn.fujitsu.com>
     25  * Author: Garrett Cooper <yanegomi (at) gmail.com>
     26  *
     27  */
     28 
     29 #ifndef LTP_RT_SIGACTION_H
     30 #define LTP_RT_SIGACTION_H
     31 
     32 #include "ltp_signal.h"
     33 
     34 #define INVAL_SA_PTR ((void *)-1)
     35 
     36 struct kernel_sigaction {
     37 	__sighandler_t k_sa_handler;
     38 	unsigned long sa_flags;
     39 	void (*sa_restorer) (void);
     40 	sigset_t sa_mask;
     41 };
     42 
     43 /* This macro marks if (struct sigaction) has .sa_restorer member */
     44 #if !defined(__ia64__) && !defined(__alpha__) && !defined(__hppa__)
     45 # define HAVE_SA_RESTORER
     46 #endif
     47 
     48 #ifdef __x86_64__
     49 
     50 /*
     51  * From asm/signal.h -- this value isn't exported anywhere outside of glibc and
     52  * asm/signal.h and is only required for the rt_sig* function family because
     53  * sigaction(2), et all, appends this if necessary to
     54  * (struct sigaction).sa_flags. HEH.
     55  *
     56  * I do #undef though, just in case...
     57  *
     58  * Also, from .../arch/x86/kernel/signal.c:448 for v2.6.30 (something or
     59  * other):
     60  *
     61  * x86-64 should always use SA_RESTORER.
     62  *
     63  * -- thus SA_RESTORER must always be defined along with
     64  * (struct sigaction).sa_restorer for this architecture.
     65  */
     66 #undef SA_RESTORER
     67 #define SA_RESTORER     0x04000000
     68 
     69 void (*restore_rt)(void);
     70 
     71 static void handler_h(int signal)
     72 {
     73 	return;
     74 }
     75 
     76 /* Setup an initial signal handler for signal number = sig for x86_64. */
     77 static inline int sig_initial(int sig)
     78 {
     79 	int ret_code = -1;
     80 	struct sigaction act, oact;
     81 
     82 	act.sa_handler = handler_h;
     83 	act.sa_flags = 0;
     84 	/* Clear out the signal set. */
     85 	if (sigemptyset(&act.sa_mask) < 0) {
     86 		/* Add the signal to the mask set. */
     87 	} else if (sigaddset(&act.sa_mask, sig) < 0) {
     88 		/* Set act.sa_restorer via syscall(2) */
     89 	} else if (sigaction(sig, &act, &oact) < 0) {
     90 		/* Copy oact.sa_restorer via syscall(2) */
     91 	} else if (sigaction(sig, &act, &oact) < 0) {
     92 		/* And voila -- we just tricked the kernel into giving us our
     93 		 * restorer function! */
     94 	} else {
     95 		restore_rt = oact.sa_restorer;
     96 		ret_code = 0;
     97 	}
     98 
     99 	return ret_code;
    100 }
    101 
    102 #endif /* __x86_64__ */
    103 
    104 #ifdef __sparc__
    105 # if defined __arch64__ || defined __sparcv9
    106 
    107 /*
    108  * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c
    109  */
    110 
    111 extern char *__rt_sig_stub;
    112 
    113 static void __attribute__((used)) __rt_sigreturn_stub(void)
    114 {
    115 	__asm__ ("__rt_sig_stub: mov %0, %%g1\n\t"
    116 		"ta  0x6d\n\t"
    117 		: /* no outputs */
    118 		: "i" (__NR_rt_sigreturn));
    119 }
    120 
    121 # else /* sparc32 */
    122 
    123 /*
    124  * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c
    125  */
    126 
    127 extern char *__rt_sig_stub, *__sig_stub;
    128 
    129 static void __attribute__((used)) __rt_sigreturn_stub(void)
    130 {
    131 	__asm__ ("__rt_sig_stub: mov %0, %%g1\n\t"
    132 		"ta  0x10\n\t"
    133 		: /* no outputs */
    134 		: "i" (__NR_rt_sigreturn));
    135 }
    136 
    137 static void __attribute__((used)) __sigreturn_stub(void)
    138 {
    139 	__asm__ ("__sig_stub: mov %0, %%g1\n\t"
    140 		"ta  0x10\n\t"
    141 		: /* no outputs */
    142 		: "i" (__NR_sigreturn));
    143 }
    144 
    145 # endif
    146 #endif /* __sparc__ */
    147 
    148 #ifdef __arc__
    149 
    150 #undef SA_RESTORER
    151 #define SA_RESTORER     0x04000000
    152 
    153 /*
    154  * based on uClibc/libc/sysdeps/linux/arc/sigaction.c
    155  */
    156 static void
    157 __attribute__ ((optimize("Os"))) __attribute__((used)) restore_rt(void)
    158 {
    159 	__asm__ (
    160 		"mov r8, %0	\n\t"
    161 #ifdef __ARCHS__
    162 		"trap_s	0	\n\t"
    163 #else
    164 		"trap0	\n\t"
    165 #endif
    166 		: /* no outputs */
    167 		: "i" (__NR_rt_sigreturn)
    168 		: "r8");
    169 }
    170 #endif
    171 
    172 /* This is a wrapper for __NR_rt_sigaction syscall.
    173  * act/oact values of INVAL_SA_PTR is used to pass
    174  * an invalid pointer to syscall(__NR_rt_sigaction)
    175  *
    176  * Based on glibc/sysdeps/unix/sysv/linux/{...}/sigaction.c
    177  */
    178 
    179 static int ltp_rt_sigaction(int signum, const struct sigaction *act,
    180 			struct sigaction *oact, size_t sigsetsize)
    181 {
    182 	int ret;
    183 	struct kernel_sigaction kact, koact;
    184 	struct kernel_sigaction *kact_p = NULL;
    185 	struct kernel_sigaction *koact_p = NULL;
    186 
    187 	if (act == INVAL_SA_PTR) {
    188 		kact_p = INVAL_SA_PTR;
    189 	} else if (act) {
    190 		kact.k_sa_handler = act->sa_handler;
    191 		memcpy(&kact.sa_mask, &act->sa_mask, sizeof(sigset_t));
    192 		kact.sa_flags = act->sa_flags;
    193 		kact.sa_restorer = NULL;
    194 
    195 		kact_p = &kact;
    196 	}
    197 
    198 	if (oact == INVAL_SA_PTR)
    199 		koact_p = INVAL_SA_PTR;
    200 	else if (oact)
    201 		koact_p = &koact;
    202 
    203 #ifdef __x86_64__
    204 	sig_initial(signum);
    205 #endif
    206 
    207 #if defined __x86_64__ || defined __arc__
    208 	kact.sa_flags |= SA_RESTORER;
    209 	kact.sa_restorer = restore_rt;
    210 #endif
    211 
    212 #ifdef __sparc__
    213 	unsigned long stub = 0;
    214 # if defined __arch64__ || defined __sparcv9
    215 	stub = ((unsigned long) &__rt_sig_stub) - 8;
    216 # else /* sparc32 */
    217 	if ((kact.sa_flags & SA_SIGINFO) != 0)
    218 		stub = ((unsigned long) &__rt_sig_stub) - 8;
    219 	else
    220 		stub = ((unsigned long) &__sig_stub) - 8;
    221 # endif
    222 #endif
    223 
    224 
    225 #ifdef __sparc__
    226 	ret = ltp_syscall(__NR_rt_sigaction, signum,
    227 			kact_p, koact_p,
    228 			stub, sigsetsize);
    229 #else
    230 	ret = ltp_syscall(__NR_rt_sigaction, signum,
    231 			kact_p, koact_p,
    232 			sigsetsize);
    233 #endif
    234 
    235 	if (ret >= 0) {
    236 		if (oact && (oact != INVAL_SA_PTR)) {
    237 			oact->sa_handler = koact.k_sa_handler;
    238 			memcpy(&oact->sa_mask, &koact.sa_mask,
    239 				sizeof(sigset_t));
    240 			oact->sa_flags = koact.sa_flags;
    241 #ifdef HAVE_SA_RESTORER
    242 			oact->sa_restorer = koact.sa_restorer;
    243 #endif
    244 		}
    245 	}
    246 
    247 	return ret;
    248 }
    249 
    250 #endif /* LTP_RT_SIGACTION_H */
    251