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: Garrett Cooper <yanegomi@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
handler_h(int signal)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. */
sig_initial(int sig)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
__rt_sigreturn_stub(void)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
__rt_sigreturn_stub(void)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
__sigreturn_stub(void)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
restore_rt(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
ltp_rt_sigaction(int signum,const struct sigaction * act,struct sigaction * oact,size_t sigsetsize)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