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