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 #ifdef TST_TEST_H__ 181 # define TST_SYSCALL tst_syscall 182 #else 183 # define TST_SYSCALL ltp_syscall 184 #endif 185 186 /* This is a wrapper for __NR_rt_sigaction syscall. 187 * act/oact values of INVAL_SA_PTR is used to pass 188 * an invalid pointer to syscall(__NR_rt_sigaction) 189 * 190 * Based on glibc/sysdeps/unix/sysv/linux/{...}/sigaction.c 191 */ 192 193 static int ltp_rt_sigaction(int signum, const struct sigaction *act, 194 struct sigaction *oact, size_t sigsetsize) 195 { 196 int ret; 197 struct kernel_sigaction kact, koact; 198 struct kernel_sigaction *kact_p = NULL; 199 struct kernel_sigaction *koact_p = NULL; 200 201 if (act == INVAL_SA_PTR) { 202 kact_p = INVAL_SA_PTR; 203 } else if (act) { 204 kact.k_sa_handler = act->sa_handler; 205 memcpy(&kact.sa_mask, &act->sa_mask, sizeof(sigset_t)); 206 kact.sa_flags = act->sa_flags; 207 #ifndef __mips__ 208 kact.sa_restorer = NULL; 209 #endif 210 kact_p = &kact; 211 } 212 213 if (oact == INVAL_SA_PTR) 214 koact_p = INVAL_SA_PTR; 215 else if (oact) 216 koact_p = &koact; 217 218 #ifdef __x86_64__ 219 sig_initial(signum); 220 #endif 221 222 #if defined __x86_64__ || defined __arc__ 223 kact.sa_flags |= SA_RESTORER; 224 kact.sa_restorer = restore_rt; 225 #endif 226 227 #ifdef __sparc__ 228 unsigned long stub = 0; 229 # if defined __arch64__ || defined __sparcv9 230 stub = ((unsigned long) &__rt_sig_stub) - 8; 231 # else /* sparc32 */ 232 if ((kact.sa_flags & SA_SIGINFO) != 0) 233 stub = ((unsigned long) &__rt_sig_stub) - 8; 234 else 235 stub = ((unsigned long) &__sig_stub) - 8; 236 # endif 237 #endif 238 239 240 #ifdef __sparc__ 241 ret = TST_SYSCALL(__NR_rt_sigaction, signum, 242 kact_p, koact_p, 243 stub, sigsetsize); 244 #else 245 ret = TST_SYSCALL(__NR_rt_sigaction, signum, 246 kact_p, koact_p, 247 sigsetsize); 248 #endif 249 250 if (ret >= 0) { 251 if (oact && (oact != INVAL_SA_PTR)) { 252 oact->sa_handler = koact.k_sa_handler; 253 memcpy(&oact->sa_mask, &koact.sa_mask, 254 sizeof(sigset_t)); 255 oact->sa_flags = koact.sa_flags; 256 #ifdef HAVE_SA_RESTORER 257 oact->sa_restorer = koact.sa_restorer; 258 #endif 259 } 260 } 261 262 return ret; 263 } 264 265 #endif /* LTP_RT_SIGACTION_H */ 266