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: Ngie Cooper <yaneurabeya (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 #if defined(__mips__)
     37 struct kernel_sigaction {
     38 	unsigned int sa_flags;
     39 	__sighandler_t k_sa_handler;
     40 	sigset_t sa_mask;
     41 };
     42 #else
     43 struct kernel_sigaction {
     44 	__sighandler_t k_sa_handler;
     45 	unsigned long sa_flags;
     46 	void (*sa_restorer) (void);
     47 	sigset_t sa_mask;
     48 };
     49 #endif
     50 
     51 /* This macro marks if (struct sigaction) has .sa_restorer member */
     52 #if !defined(__ia64__) && !defined(__alpha__) && !defined(__hppa__) && !defined(__mips__)
     53 # define HAVE_SA_RESTORER
     54 #endif
     55 
     56 #ifdef __x86_64__
     57 
     58 /*
     59  * From asm/signal.h -- this value isn't exported anywhere outside of glibc and
     60  * asm/signal.h and is only required for the rt_sig* function family because
     61  * sigaction(2), et all, appends this if necessary to
     62  * (struct sigaction).sa_flags. HEH.
     63  *
     64  * I do #undef though, just in case...
     65  *
     66  * Also, from .../arch/x86/kernel/signal.c:448 for v2.6.30 (something or
     67  * other):
     68  *
     69  * x86-64 should always use SA_RESTORER.
     70  *
     71  * -- thus SA_RESTORER must always be defined along with
     72  * (struct sigaction).sa_restorer for this architecture.
     73  */
     74 #undef SA_RESTORER
     75 #define SA_RESTORER     0x04000000
     76 
     77 void (*restore_rt)(void);
     78 
     79 static void handler_h(int signal)
     80 {
     81 	return;
     82 }
     83 
     84 /* Setup an initial signal handler for signal number = sig for x86_64. */
     85 static inline int sig_initial(int sig)
     86 {
     87 	int ret_code = -1;
     88 	struct sigaction act, oact;
     89 
     90 	act.sa_handler = handler_h;
     91 	act.sa_flags = 0;
     92 	/* Clear out the signal set. */
     93 	if (sigemptyset(&act.sa_mask) < 0) {
     94 		/* Add the signal to the mask set. */
     95 	} else if (sigaddset(&act.sa_mask, sig) < 0) {
     96 		/* Set act.sa_restorer via syscall(2) */
     97 	} else if (sigaction(sig, &act, &oact) < 0) {
     98 		/* Copy oact.sa_restorer via syscall(2) */
     99 	} else if (sigaction(sig, &act, &oact) < 0) {
    100 		/* And voila -- we just tricked the kernel into giving us our
    101 		 * restorer function! */
    102 	} else {
    103 		restore_rt = oact.sa_restorer;
    104 		ret_code = 0;
    105 	}
    106 
    107 	return ret_code;
    108 }
    109 
    110 #endif /* __x86_64__ */
    111 
    112 #ifdef __sparc__
    113 # if defined __arch64__ || defined __sparcv9
    114 
    115 /*
    116  * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c
    117  */
    118 
    119 extern char *__rt_sig_stub;
    120 
    121 static void __attribute__((used)) __rt_sigreturn_stub(void)
    122 {
    123 	__asm__ ("__rt_sig_stub: mov %0, %%g1\n\t"
    124 		"ta  0x6d\n\t"
    125 		: /* no outputs */
    126 		: "i" (__NR_rt_sigreturn));
    127 }
    128 
    129 # else /* sparc32 */
    130 
    131 /*
    132  * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c
    133  */
    134 
    135 extern char *__rt_sig_stub, *__sig_stub;
    136 
    137 static void __attribute__((used)) __rt_sigreturn_stub(void)
    138 {
    139 	__asm__ ("__rt_sig_stub: mov %0, %%g1\n\t"
    140 		"ta  0x10\n\t"
    141 		: /* no outputs */
    142 		: "i" (__NR_rt_sigreturn));
    143 }
    144 
    145 static void __attribute__((used)) __sigreturn_stub(void)
    146 {
    147 	__asm__ ("__sig_stub: mov %0, %%g1\n\t"
    148 		"ta  0x10\n\t"
    149 		: /* no outputs */
    150 		: "i" (__NR_sigreturn));
    151 }
    152 
    153 # endif
    154 #endif /* __sparc__ */
    155 
    156 #ifdef __arc__
    157 
    158 #undef SA_RESTORER
    159 #define SA_RESTORER     0x04000000
    160 
    161 /*
    162  * based on uClibc/libc/sysdeps/linux/arc/sigaction.c
    163  */
    164 static void
    165 __attribute__ ((optimize("Os"))) __attribute__((used)) restore_rt(void)
    166 {
    167 	__asm__ (
    168 		"mov r8, %0	\n\t"
    169 #ifdef __ARCHS__
    170 		"trap_s	0	\n\t"
    171 #else
    172 		"trap0	\n\t"
    173 #endif
    174 		: /* no outputs */
    175 		: "i" (__NR_rt_sigreturn)
    176 		: "r8");
    177 }
    178 #endif
    179 
    180 /* This is a wrapper for __NR_rt_sigaction syscall.
    181  * act/oact values of INVAL_SA_PTR is used to pass
    182  * an invalid pointer to syscall(__NR_rt_sigaction)
    183  *
    184  * Based on glibc/sysdeps/unix/sysv/linux/{...}/sigaction.c
    185  */
    186 
    187 static int ltp_rt_sigaction(int signum, const struct sigaction *act,
    188 			struct sigaction *oact, size_t sigsetsize)
    189 {
    190 	int ret;
    191 	struct kernel_sigaction kact, koact;
    192 	struct kernel_sigaction *kact_p = NULL;
    193 	struct kernel_sigaction *koact_p = NULL;
    194 
    195 	if (act == INVAL_SA_PTR) {
    196 		kact_p = INVAL_SA_PTR;
    197 	} else if (act) {
    198 		kact.k_sa_handler = act->sa_handler;
    199 		memcpy(&kact.sa_mask, &act->sa_mask, sizeof(sigset_t));
    200 		kact.sa_flags = act->sa_flags;
    201 #ifndef __mips__
    202 		kact.sa_restorer = NULL;
    203 #endif
    204 		kact_p = &kact;
    205 	}
    206 
    207 	if (oact == INVAL_SA_PTR)
    208 		koact_p = INVAL_SA_PTR;
    209 	else if (oact)
    210 		koact_p = &koact;
    211 
    212 #ifdef __x86_64__
    213 	sig_initial(signum);
    214 #endif
    215 
    216 #if defined __x86_64__ || defined __arc__
    217 	kact.sa_flags |= SA_RESTORER;
    218 	kact.sa_restorer = restore_rt;
    219 #endif
    220 
    221 #ifdef __sparc__
    222 	unsigned long stub = 0;
    223 # if defined __arch64__ || defined __sparcv9
    224 	stub = ((unsigned long) &__rt_sig_stub) - 8;
    225 # else /* sparc32 */
    226 	if ((kact.sa_flags & SA_SIGINFO) != 0)
    227 		stub = ((unsigned long) &__rt_sig_stub) - 8;
    228 	else
    229 		stub = ((unsigned long) &__sig_stub) - 8;
    230 # endif
    231 #endif
    232 
    233 
    234 #ifdef __sparc__
    235 	ret = ltp_syscall(__NR_rt_sigaction, signum,
    236 			kact_p, koact_p,
    237 			stub, sigsetsize);
    238 #else
    239 	ret = ltp_syscall(__NR_rt_sigaction, signum,
    240 			kact_p, koact_p,
    241 			sigsetsize);
    242 #endif
    243 
    244 	if (ret >= 0) {
    245 		if (oact && (oact != INVAL_SA_PTR)) {
    246 			oact->sa_handler = koact.k_sa_handler;
    247 			memcpy(&oact->sa_mask, &koact.sa_mask,
    248 				sizeof(sigset_t));
    249 			oact->sa_flags = koact.sa_flags;
    250 #ifdef HAVE_SA_RESTORER
    251 			oact->sa_restorer = koact.sa_restorer;
    252 #endif
    253 		}
    254 	}
    255 
    256 	return ret;
    257 }
    258 
    259 #endif /* LTP_RT_SIGACTION_H */
    260