xref: /third_party/ltp/include/lapi/rt_sigaction.h (revision f08c3bdf)
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__)
17struct kernel_sigaction {
18	unsigned int sa_flags;
19	void (* k_sa_handler)(int);
20	sigset_t sa_mask;
21};
22#else
23struct 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
57void (*restore_rt)(void);
58
59static void handler_h(int signal)
60{
61	return;
62}
63
64/* Setup an initial signal handler for signal number = sig for x86_64. */
65static 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
99extern char *__rt_sig_stub;
100
101static 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
115extern char *__rt_sig_stub, *__sig_stub;
116
117static 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
125static 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 */
144static 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
167static 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