xref: /illumos-gate/usr/src/ucblib/libucb/i386/sys/signal.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 /*
36  * 4.3BSD signal compatibility functions
37  *
38  * the implementation interprets signal masks equal to -1 as "all of the
39  * signals in the signal set", thereby allowing signals with numbers
40  * above 32 to be blocked when referenced in code such as:
41  *
42  *	for (i = 0; i < NSIG; i++)
43  *		mask |= sigmask(i)
44  */
45 
46 #pragma ident	"%Z%%M%	%I%	%E% SMI"
47 
48 #include <sys/types.h>
49 #include <ucontext.h>
50 #include <signal.h>
51 #include <errno.h>
52 
53 #undef	BUS_OBJERR	/* namespace conflict */
54 #include <sys/siginfo.h>
55 #include "libc.h"
56 
57 #pragma weak sigvechandler = _sigvechandler
58 #pragma weak sigsetmask = _sigsetmask
59 #pragma weak sigblock = _sigblock
60 #pragma weak sigpause = usigpause
61 #pragma weak sigvec = _sigvec
62 #pragma weak sigstack = _sigstack
63 #pragma weak signal = usignal
64 #pragma weak siginterrupt = _siginterrupt
65 
66 #define	set2mask(setp) ((setp)->__sigbits[0])
67 #define	mask2set(mask, setp) \
68 	((mask) == -1 ? sigfillset(setp) : \
69 	    (sigemptyset(setp), (((setp)->__sigbits[0]) = (int)(mask))))
70 
71 void (*_siguhandler[NSIG])() = { 0 };
72 
73 /* forward declarations */
74 int ucbsigsetmask(int);
75 int ucbsigblock(int);
76 int ucbsigvec(int, struct sigvec *, struct sigvec *);
77 int ucbsigpause(int);
78 int ucbsiginterrupt(int, int);
79 
80 /*
81  * sigvechandler is the real signal handler installed for all
82  * signals handled in the 4.3BSD compatibility interface - it translates
83  * SVR4 signal hander arguments into 4.3BSD signal handler arguments
84  * and then calls the real handler
85  */
86 
87 void
88 _sigvechandler(int sig, siginfo_t *sip, ucontext_t *ucp)
89 {
90 	static void ucbsigvechandler();
91 
92 	ucbsigvechandler(sig, sip, ucp);
93 }
94 
95 static void
96 ucbsigvechandler(int sig, siginfo_t *sip, ucontext_t *ucp)
97 {
98 	struct sigcontext sc;
99 	int code;
100 	char *addr;
101 	int i, j;
102 	int gwinswitch = 0;
103 
104 	sc.sc_onstack = ((ucp->uc_stack.ss_flags & SS_ONSTACK) != 0);
105 	sc.sc_mask = set2mask(&ucp->uc_sigmask);
106 
107 #if defined(__amd64)
108 	sc.sc_sp = (long)ucp->uc_mcontext.gregs[REG_RSP];
109 	sc.sc_pc = (long)ucp->uc_mcontext.gregs[REG_RIP];
110 	sc.sc_ps = (long)ucp->uc_mcontext.gregs[REG_RFL];
111 	sc.sc_r0 = (long)ucp->uc_mcontext.gregs[REG_RAX];
112 	sc.sc_r1 = (long)ucp->uc_mcontext.gregs[REG_RDX];
113 #else
114 	sc.sc_sp = (int)ucp->uc_mcontext.gregs[UESP];
115 	sc.sc_pc = (int)ucp->uc_mcontext.gregs[EIP];
116 	sc.sc_ps = (int)ucp->uc_mcontext.gregs[EFL];
117 	sc.sc_r0 = (int)ucp->uc_mcontext.gregs[EAX];
118 	sc.sc_r1 = (int)ucp->uc_mcontext.gregs[EDX];
119 #endif
120 
121 	/*
122 	 * Translate signal codes from new to old.
123 	 * /usr/include/sys/siginfo.h contains new codes.
124 	 * /usr/ucbinclude/sys/signal.h contains old codes.
125 	 */
126 	code = 0;
127 	addr = SIG_NOADDR;
128 	if (sip != NULL && SI_FROMKERNEL(sip)) {
129 		addr = sip->si_addr;
130 
131 		switch (sig) {
132 		case SIGILL:
133 		case SIGFPE:
134 			code = ILL_ILLINSTR_FAULT;
135 			break;
136 
137 		case SIGBUS:
138 			switch (sip->si_code) {
139 			case BUS_ADRALN:
140 				code = BUS_ALIGN;
141 				break;
142 			case BUS_ADRERR:
143 				code = BUS_HWERR;
144 				break;
145 			default:	/* BUS_OBJERR */
146 				code = FC_MAKE_ERR(sip->si_errno);
147 				break;
148 			}
149 			break;
150 
151 		case SIGSEGV:
152 			switch (sip->si_code) {
153 			case SEGV_MAPERR:
154 				code = SEGV_NOMAP;
155 				break;
156 			case SEGV_ACCERR:
157 				code = SEGV_PROT;
158 				break;
159 			default:
160 				code = FC_MAKE_ERR(sip->si_errno);
161 				break;
162 			}
163 			break;
164 
165 		default:
166 			addr = SIG_NOADDR;
167 			break;
168 		}
169 	}
170 
171 	(*_siguhandler[sig])(sig, code, &sc, addr);
172 
173 	if (sc.sc_onstack)
174 		ucp->uc_stack.ss_flags |= SS_ONSTACK;
175 	else
176 		ucp->uc_stack.ss_flags &= ~SS_ONSTACK;
177 	mask2set(sc.sc_mask, &ucp->uc_sigmask);
178 
179 #if defined(__amd64)
180 	ucp->uc_mcontext.gregs[REG_RSP] = (long)sc.sc_sp;
181 	ucp->uc_mcontext.gregs[REG_RIP] = (long)sc.sc_pc;
182 	ucp->uc_mcontext.gregs[REG_RFL] = (long)sc.sc_ps;
183 	ucp->uc_mcontext.gregs[REG_RAX] = (long)sc.sc_r0;
184 	ucp->uc_mcontext.gregs[REG_RDX] = (long)sc.sc_r1;
185 #else
186 	ucp->uc_mcontext.gregs[UESP] = (int)sc.sc_sp;
187 	ucp->uc_mcontext.gregs[EIP] = (int)sc.sc_pc;
188 	ucp->uc_mcontext.gregs[EFL] = (int)sc.sc_ps;
189 	ucp->uc_mcontext.gregs[EAX] = (int)sc.sc_r0;
190 	ucp->uc_mcontext.gregs[EDX] = (int)sc.sc_r1;
191 #endif
192 
193 	setcontext(ucp);
194 }
195 
196 int
197 _sigsetmask(int mask)
198 {
199 	return (ucbsigsetmask(mask));
200 }
201 
202 int
203 ucbsigsetmask(int mask)
204 {
205 	sigset_t oset;
206 	sigset_t nset;
207 
208 	(void) sigprocmask(0, (sigset_t *)0, &nset);
209 	mask2set(mask, &nset);
210 	(void) sigprocmask(SIG_SETMASK, &nset, &oset);
211 	return (set2mask(&oset));
212 }
213 
214 int
215 _sigblock(int mask)
216 {
217 	return (ucbsigblock(mask));
218 }
219 
220 int
221 ucbsigblock(int mask)
222 {
223 	sigset_t oset;
224 	sigset_t nset;
225 
226 	(void) sigprocmask(0, (sigset_t *)0, &nset);
227 	mask2set(mask, &nset);
228 	(void) sigprocmask(SIG_BLOCK, &nset, &oset);
229 	return (set2mask(&oset));
230 }
231 
232 int
233 usigpause(int mask)
234 {
235 	return (ucbsigpause(mask));
236 }
237 
238 int
239 ucbsigpause(int mask)
240 {
241 	sigset_t set, oset;
242 	int ret;
243 
244 	(void) sigprocmask(0, (sigset_t *)0, &set);
245 	oset = set;
246 	mask2set(mask, &set);
247 	ret = sigsuspend(&set);
248 	(void) sigprocmask(SIG_SETMASK, &oset, (sigset_t *)0);
249 	return (ret);
250 }
251 
252 int
253 _sigvec(int sig, struct sigvec *nvec, struct sigvec *ovec)
254 {
255 	return (ucbsigvec(sig, nvec, ovec));
256 }
257 
258 int
259 ucbsigvec(int sig, struct sigvec *nvec, struct sigvec *ovec)
260 {
261 	struct sigaction nact;
262 	struct sigaction oact;
263 	struct sigaction *nactp;
264 	void (*ohandler)(), (*nhandler)();
265 
266 	if (sig <= 0 || sig >= NSIG) {
267 		errno = EINVAL;
268 		return (-1);
269 	}
270 
271 	if ((intptr_t)ovec == -1 || (intptr_t)nvec == -1) {
272 		errno = EFAULT;
273 		return (-1);
274 	}
275 
276 	ohandler = _siguhandler[sig];
277 
278 	if (nvec) {
279 		_sigaction(sig, (struct sigaction *)0, &nact);
280 		nhandler = nvec->sv_handler;
281 		/*
282 		 * To be compatible with the behavior of SunOS 4.x:
283 		 * If the new signal handler is SIG_IGN or SIG_DFL,
284 		 * do not change the signal's entry in the handler array.
285 		 * This allows a child of vfork(2) to set signal handlers
286 		 * to SIG_IGN or SIG_DFL without affecting the parent.
287 		 */
288 		if (nhandler != SIG_DFL && nhandler != SIG_IGN) {
289 			_siguhandler[sig] = nhandler;
290 			nact.sa_handler = (void (*)())ucbsigvechandler;
291 		} else {
292 			nact.sa_handler = nhandler;
293 		}
294 		mask2set(nvec->sv_mask, &nact.sa_mask);
295 		if (sig == SIGKILL || sig == SIGSTOP)
296 			nact.sa_handler = SIG_DFL;
297 		nact.sa_flags = SA_SIGINFO;
298 		if (!(nvec->sv_flags & SV_INTERRUPT))
299 			nact.sa_flags |= SA_RESTART;
300 		if (nvec->sv_flags & SV_RESETHAND)
301 			nact.sa_flags |= SA_RESETHAND;
302 		if (nvec->sv_flags & SV_ONSTACK)
303 			nact.sa_flags |= SA_ONSTACK;
304 		nactp = &nact;
305 	} else
306 		nactp = (struct sigaction *)0;
307 
308 	if (_sigaction(sig, nactp, &oact) < 0) {
309 		_siguhandler[sig] = ohandler;
310 		return (-1);
311 	}
312 
313 	if (ovec) {
314 		if (oact.sa_handler == SIG_DFL || oact.sa_handler == SIG_IGN)
315 			ovec->sv_handler = oact.sa_handler;
316 		else
317 			ovec->sv_handler = ohandler;
318 		ovec->sv_mask = set2mask(&oact.sa_mask);
319 		ovec->sv_flags = 0;
320 		if (oact.sa_flags & SA_ONSTACK)
321 			ovec->sv_flags |= SV_ONSTACK;
322 		if (oact.sa_flags & SA_RESETHAND)
323 			ovec->sv_flags |= SV_RESETHAND;
324 		if (!(oact.sa_flags & SA_RESTART))
325 			ovec->sv_flags |= SV_INTERRUPT;
326 	}
327 
328 	return (0);
329 }
330 
331 int
332 _sigstack(struct sigstack *nss, struct sigstack *oss)
333 {
334 	struct sigaltstack nalt;
335 	struct sigaltstack oalt;
336 	struct sigaltstack *naltp;
337 
338 	if (nss) {
339 		/*
340 		 * assumes stack growth is down (like sparc and x86)
341 		 */
342 		nalt.ss_sp = nss->ss_sp - SIGSTKSZ;
343 		nalt.ss_size = SIGSTKSZ;
344 		nalt.ss_flags = 0;
345 		naltp = &nalt;
346 	} else
347 		naltp = (struct sigaltstack *)0;
348 
349 	if (sigaltstack(naltp, &oalt) < 0)
350 		return (-1);
351 
352 	if (oss) {
353 		/*
354 		 * assumes stack growth is down (like sparc and x86)
355 		 */
356 		oss->ss_sp = oalt.ss_sp + oalt.ss_size;
357 		oss->ss_onstack = ((oalt.ss_flags & SS_ONSTACK) != 0);
358 	}
359 
360 	return (0);
361 }
362 
363 void (*
364 ucbsignal(int s, void (*a)()))()
365 {
366 	struct sigvec osv;
367 	struct sigvec nsv;
368 	static int mask[NSIG];
369 	static int flags[NSIG];
370 
371 	nsv.sv_handler = a;
372 	nsv.sv_mask = mask[s];
373 	nsv.sv_flags = flags[s];
374 	if (ucbsigvec(s, &nsv, &osv) < 0)
375 		return (SIG_ERR);
376 	if (nsv.sv_mask != osv.sv_mask || nsv.sv_flags != osv.sv_flags) {
377 		mask[s] = nsv.sv_mask = osv.sv_mask;
378 		flags[s] = nsv.sv_flags =
379 			osv.sv_flags & ~(SV_RESETHAND|SV_INTERRUPT);
380 		if (ucbsigvec(s, &nsv, (struct sigvec *)0) < 0)
381 			return (SIG_ERR);
382 	}
383 	return (osv.sv_handler);
384 }
385 
386 void (*
387 usignal(int s, void (*a)()))()
388 {
389 	return (ucbsignal(s, a));
390 }
391 
392 /*
393  * Set signal state to prevent restart of system calls
394  * after an instance of the indicated signal.
395  */
396 int
397 _siginterrupt(int sig, int flag)
398 {
399 	return (ucbsiginterrupt(sig, flag));
400 }
401 
402 int
403 ucbsiginterrupt(int sig, int flag)
404 {
405 	struct sigvec sv;
406 	int ret;
407 
408 	if ((ret = ucbsigvec(sig, 0, &sv)) < 0)
409 		return (ret);
410 	if (flag)
411 		sv.sv_flags |= SV_INTERRUPT;
412 	else
413 		sv.sv_flags &= ~SV_INTERRUPT;
414 	return (ucbsigvec(sig, &sv, 0));
415 }
416