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@cn.fujitsu.com>
25 * Author: Ngie Cooper <yaneurabeya@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 void (* k_sa_handler)(int);
40 sigset_t sa_mask;
41 };
42 #else
43 struct kernel_sigaction {
44 void (* k_sa_handler)(int);
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
handler_h(int signal)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. */
sig_initial(int sig)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
__rt_sigreturn_stub(void)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
__rt_sigreturn_stub(void)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
__sigreturn_stub(void)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
restore_rt(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
ltp_rt_sigaction(int signum,const struct sigaction * act,struct sigaction * oact,size_t sigsetsize)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