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