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