• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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