1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2009 Cisco Systems, Inc. All Rights Reserved.
4 * Copyright (c) 2009 FUJITSU LIMITED. All Rights Reserved.
5 * Author: Liu Bo <liubo2009@cn.fujitsu.com>
6 * Author: Ngie Cooper <yaneurabeya@gmail.com>
7 */
8
9 #ifndef LAPI_RT_SIGACTION_H__
10 #define LAPI_RT_SIGACTION_H__
11
12 #include "ltp_signal.h"
13
14 #define INVAL_SA_PTR ((void *)-1)
15
16 #if defined(__mips__)
17 struct kernel_sigaction {
18 unsigned int sa_flags;
19 void (* k_sa_handler)(int);
20 sigset_t sa_mask;
21 };
22 #else
23 struct kernel_sigaction {
24 void (* k_sa_handler)(int);
25 unsigned long sa_flags;
26 void (*sa_restorer) (void);
27 sigset_t sa_mask;
28 };
29 #endif
30
31 /* This macro marks if (struct sigaction) has .sa_restorer member */
32 #if !defined(__ia64__) && !defined(__alpha__) && !defined(__hppa__) && !defined(__mips__)
33 # define HAVE_SA_RESTORER
34 #endif
35
36 #ifdef __x86_64__
37
38 /*
39 * From asm/signal.h -- this value isn't exported anywhere outside of glibc and
40 * asm/signal.h and is only required for the rt_sig* function family because
41 * sigaction(2), et all, appends this if necessary to
42 * (struct sigaction).sa_flags. HEH.
43 *
44 * I do #undef though, just in case...
45 *
46 * Also, from .../arch/x86/kernel/signal.c:448 for v2.6.30 (something or
47 * other):
48 *
49 * x86-64 should always use SA_RESTORER.
50 *
51 * -- thus SA_RESTORER must always be defined along with
52 * (struct sigaction).sa_restorer for this architecture.
53 */
54 #undef SA_RESTORER
55 #define SA_RESTORER 0x04000000
56
57 void (*restore_rt)(void);
58
handler_h(int signal)59 static void handler_h(int signal)
60 {
61 return;
62 }
63
64 /* Setup an initial signal handler for signal number = sig for x86_64. */
sig_initial(int sig)65 static inline int sig_initial(int sig)
66 {
67 int ret_code = -1;
68 struct sigaction act, oact;
69
70 act.sa_handler = handler_h;
71 act.sa_flags = 0;
72 /* Clear out the signal set. */
73 if (sigemptyset(&act.sa_mask) < 0) {
74 /* Add the signal to the mask set. */
75 } else if (sigaddset(&act.sa_mask, sig) < 0) {
76 /* Set act.sa_restorer via syscall(2) */
77 } else if (sigaction(sig, &act, &oact) < 0) {
78 /* Copy oact.sa_restorer via syscall(2) */
79 } else if (sigaction(sig, &act, &oact) < 0) {
80 /* And voila -- we just tricked the kernel into giving us our
81 * restorer function! */
82 } else {
83 restore_rt = oact.sa_restorer;
84 ret_code = 0;
85 }
86
87 return ret_code;
88 }
89
90 #endif /* __x86_64__ */
91
92 #ifdef __sparc__
93 # if defined __arch64__ || defined __sparcv9
94
95 /*
96 * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c
97 */
98
99 extern char *__rt_sig_stub;
100
__rt_sigreturn_stub(void)101 static void __attribute__((used)) __rt_sigreturn_stub(void)
102 {
103 __asm__ ("__rt_sig_stub: mov %0, %%g1\n\t"
104 "ta 0x6d\n\t"
105 : /* no outputs */
106 : "i" (__NR_rt_sigreturn));
107 }
108
109 # else /* sparc32 */
110
111 /*
112 * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c
113 */
114
115 extern char *__rt_sig_stub, *__sig_stub;
116
__rt_sigreturn_stub(void)117 static void __attribute__((used)) __rt_sigreturn_stub(void)
118 {
119 __asm__ ("__rt_sig_stub: mov %0, %%g1\n\t"
120 "ta 0x10\n\t"
121 : /* no outputs */
122 : "i" (__NR_rt_sigreturn));
123 }
124
__sigreturn_stub(void)125 static void __attribute__((used)) __sigreturn_stub(void)
126 {
127 __asm__ ("__sig_stub: mov %0, %%g1\n\t"
128 "ta 0x10\n\t"
129 : /* no outputs */
130 : "i" (__NR_sigreturn));
131 }
132
133 # endif
134 #endif /* __sparc__ */
135
136 #ifdef __arc__
137
138 #undef SA_RESTORER
139 #define SA_RESTORER 0x04000000
140
141 /*
142 * based on uClibc/libc/sysdeps/linux/arc/sigaction.c
143 */
144 static void
restore_rt(void)145 __attribute__ ((optimize("Os"))) __attribute__((used)) restore_rt(void)
146 {
147 __asm__ (
148 "mov r8, %0 \n\t"
149 #ifdef __ARCHS__
150 "trap_s 0 \n\t"
151 #else
152 "trap0 \n\t"
153 #endif
154 : /* no outputs */
155 : "i" (__NR_rt_sigreturn)
156 : "r8");
157 }
158 #endif
159
160 /* This is a wrapper for __NR_rt_sigaction syscall.
161 * act/oact values of INVAL_SA_PTR is used to pass
162 * an invalid pointer to syscall(__NR_rt_sigaction)
163 *
164 * Based on glibc/sysdeps/unix/sysv/linux/{...}/sigaction.c
165 */
166
ltp_rt_sigaction(int signum,const struct sigaction * act,struct sigaction * oact,size_t sigsetsize)167 static int ltp_rt_sigaction(int signum, const struct sigaction *act,
168 struct sigaction *oact, size_t sigsetsize)
169 {
170 int ret;
171 struct kernel_sigaction kact, koact;
172 struct kernel_sigaction *kact_p = NULL;
173 struct kernel_sigaction *koact_p = NULL;
174
175 if (act == INVAL_SA_PTR) {
176 kact_p = INVAL_SA_PTR;
177 } else if (act) {
178 kact.k_sa_handler = act->sa_handler;
179 memcpy(&kact.sa_mask, &act->sa_mask, sizeof(sigset_t));
180 kact.sa_flags = act->sa_flags;
181 #ifndef __mips__
182 kact.sa_restorer = NULL;
183 #endif
184 kact_p = &kact;
185 }
186
187 if (oact == INVAL_SA_PTR)
188 koact_p = INVAL_SA_PTR;
189 else if (oact)
190 koact_p = &koact;
191
192 #ifdef __x86_64__
193 sig_initial(signum);
194 #endif
195
196 #if defined __x86_64__ || defined __arc__
197 kact.sa_flags |= SA_RESTORER;
198 kact.sa_restorer = restore_rt;
199 #endif
200
201 #ifdef __sparc__
202 unsigned long stub = 0;
203 # if defined __arch64__ || defined __sparcv9
204 stub = ((unsigned long) &__rt_sig_stub) - 8;
205 # else /* sparc32 */
206 if ((kact.sa_flags & SA_SIGINFO) != 0)
207 stub = ((unsigned long) &__rt_sig_stub) - 8;
208 else
209 stub = ((unsigned long) &__sig_stub) - 8;
210 # endif
211 #endif
212
213
214 #ifdef __sparc__
215 ret = tst_syscall(__NR_rt_sigaction, signum,
216 kact_p, koact_p,
217 stub, sigsetsize);
218 #else
219 ret = tst_syscall(__NR_rt_sigaction, signum,
220 kact_p, koact_p,
221 sigsetsize);
222 #endif
223
224 if (ret >= 0) {
225 if (oact && (oact != INVAL_SA_PTR)) {
226 oact->sa_handler = koact.k_sa_handler;
227 memcpy(&oact->sa_mask, &koact.sa_mask,
228 sizeof(sigset_t));
229 oact->sa_flags = koact.sa_flags;
230 #ifdef HAVE_SA_RESTORER
231 oact->sa_restorer = koact.sa_restorer;
232 #endif
233 }
234 }
235
236 return ret;
237 }
238
239 #endif /* LAPI_RT_SIGACTION_H__ */
240