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#pragma ident	"%Z%%M%	%I%	%E% SMI"
36
37/*LINTLIBRARY*/
38
39/*
40 * 4.3BSD signal compatibility functions
41 *
42 * the implementation interprets signal masks equal to -1 as "all of the
43 * signals in the signal set", thereby allowing signals with numbers
44 * above 32 to be blocked when referenced in code such as:
45 *
46 *	for (i = 0; i < NSIG; i++)
47 *		mask |= sigmask(i)
48 */
49
50#include <sys/types.h>
51#include <ucontext.h>
52#include <signal.h>
53#include <errno.h>
54
55#undef	BUS_OBJERR	/* namespace conflict */
56#include <sys/siginfo.h>
57#include "libc.h"
58
59#pragma weak sigvechandler = _sigvechandler
60#pragma weak sigsetmask = _sigsetmask
61#pragma weak sigblock = _sigblock
62#pragma weak sigpause = usigpause
63#pragma weak sigvec = _sigvec
64#pragma weak sigstack = _sigstack
65#pragma weak signal = usignal
66#pragma weak siginterrupt = _siginterrupt
67
68/*
69 * DO NOT remove the _ from these 3 functions or the subsequent
70 * calls to them below.  The non _ versions of these functions
71 * are the wrong functions to call.  This is BCP.  Extra
72 * care should be taken when modifying this code.
73 */
74extern int _sigfillset(sigset_t *);
75extern int _sigemptyset(sigset_t *);
76extern int _sigprocmask(int, const sigset_t *, sigset_t *);
77
78#define	set2mask(setp) ((setp)->__sigbits[0])
79#define	mask2set(mask, setp) \
80	((mask) == -1 ? _sigfillset(setp) : \
81	    ((void) _sigemptyset(setp), (((setp)->__sigbits[0]) = (int)(mask))))
82
83void (*_siguhandler[NSIG])() = { 0 };
84
85/*
86 * forward declarations
87 */
88int ucbsiginterrupt(int, int);
89int ucbsigvec(int, struct sigvec *, struct sigvec *);
90int ucbsigpause(int);
91int ucbsigblock(int);
92int ucbsigsetmask(int);
93static void ucbsigvechandler(int, siginfo_t *, ucontext_t *);
94
95/*
96 * sigvechandler is the real signal handler installed for all
97 * signals handled in the 4.3BSD compatibility interface - it translates
98 * SVR4 signal hander arguments into 4.3BSD signal handler arguments
99 * and then calls the real handler
100 */
101
102int
103_sigvechandler(int sig, siginfo_t *sip, ucontext_t *ucp)
104{
105	ucbsigvechandler(sig, sip, ucp);
106	return (0);	/* keep the same as the original prototype */
107}
108
109static void
110ucbsigvechandler(int sig, siginfo_t *sip, ucontext_t *ucp)
111{
112	struct sigcontext sc;
113	int code;
114	char *addr;
115#ifdef NEVER
116	int gwinswitch = 0;
117#endif
118
119	sc.sc_onstack = ((ucp->uc_stack.ss_flags & SS_ONSTACK) != 0);
120	sc.sc_mask = set2mask(&ucp->uc_sigmask);
121
122#if defined(__sparc)
123	if (sig == SIGFPE && sip != NULL && SI_FROMKERNEL(sip) &&
124	    (sip->si_code == FPE_INTDIV || sip->si_code == FPE_INTOVF)) {
125		/*
126		 * Hack to emulate the 4.x kernel behavior of incrementing
127		 * the PC on integer divide by zero and integer overflow
128		 * on sparc machines.  (5.x does not increment the PC.)
129		 */
130		ucp->uc_mcontext.gregs[REG_PC] =
131		    ucp->uc_mcontext.gregs[REG_nPC];
132		ucp->uc_mcontext.gregs[REG_nPC] += 4;
133	}
134	sc.sc_sp = ucp->uc_mcontext.gregs[REG_SP];
135	sc.sc_pc = ucp->uc_mcontext.gregs[REG_PC];
136	sc.sc_npc = ucp->uc_mcontext.gregs[REG_nPC];
137
138	/* XX64 There is no REG_PSR for sparcv9, we map in REG_CCR for now */
139#if defined(__sparcv9)
140	sc.sc_psr = ucp->uc_mcontext.gregs[REG_CCR];
141#else
142	sc.sc_psr = ucp->uc_mcontext.gregs[REG_PSR];
143#endif
144
145	sc.sc_g1 = ucp->uc_mcontext.gregs[REG_G1];
146	sc.sc_o0 = ucp->uc_mcontext.gregs[REG_O0];
147
148	/*
149	 * XXX - What a kludge!
150	 * Store a pointer to the original ucontext_t in the sigcontext
151	 * so that it's available to the sigcleanup call that needs to
152	 * return from the signal handler.  Otherwise, vital information
153	 * (e.g., the "out" registers) that's only saved in the
154	 * ucontext_t isn't available to sigcleanup.
155	 */
156	sc.sc_wbcnt = (int)(sizeof (*ucp));
157	sc.sc_spbuf[0] = (char *)(uintptr_t)sig;
158	sc.sc_spbuf[1] = (char *)ucp;
159#ifdef NEVER
160	/*
161	 * XXX - Sorry, we can never pass the saved register windows
162	 * on in the sigcontext because we use that space to save the
163	 * ucontext_t.
164	 */
165	if (ucp->uc_mcontext.gwins != (gwindows_t *)0) {
166		int i, j;
167
168		gwinswitch = 1;
169		sc.sc_wbcnt = ucp->uc_mcontext.gwins->wbcnt;
170		/* XXX - should use bcopy to move this in bulk */
171		for (i = 0; i < ucp->uc_mcontext.gwins; i++) {
172			sc.sc_spbuf[i] = ucp->uc_mcontext.gwins->spbuf[i];
173			for (j = 0; j < 8; j++)
174				sc.sc_wbuf[i][j] =
175				    ucp->uc_mcontext.gwins->wbuf[i].rw_local[j];
176			for (j = 0; j < 8; j++)
177				sc.sc_wbuf[i][j+8] =
178				    ucp->uc_mcontext.gwins->wbuf[i].rw_in[j];
179		}
180	}
181#endif
182#endif
183
184	/*
185	 * Translate signal codes from new to old.
186	 * /usr/include/sys/siginfo.h contains new codes.
187	 * /usr/ucbinclude/sys/signal.h contains old codes.
188	 */
189	code = 0;
190	addr = SIG_NOADDR;
191	if (sip != NULL && SI_FROMKERNEL(sip)) {
192		addr = sip->si_addr;
193
194		switch (sig) {
195		case SIGILL:
196			switch (sip->si_code) {
197			case ILL_PRVOPC:
198				code = ILL_PRIVINSTR_FAULT;
199				break;
200			case ILL_BADSTK:
201				code = ILL_STACK;
202				break;
203			case ILL_ILLTRP:
204				code = ILL_TRAP_FAULT(sip->si_trapno);
205				break;
206			default:
207				code = ILL_ILLINSTR_FAULT;
208				break;
209			}
210			break;
211
212		case SIGEMT:
213			code = EMT_TAG;
214			break;
215
216		case SIGFPE:
217			switch (sip->si_code) {
218			case FPE_INTDIV:
219				code = FPE_INTDIV_TRAP;
220				break;
221			case FPE_INTOVF:
222				code = FPE_INTOVF_TRAP;
223				break;
224			case FPE_FLTDIV:
225				code = FPE_FLTDIV_TRAP;
226				break;
227			case FPE_FLTOVF:
228				code = FPE_FLTOVF_TRAP;
229				break;
230			case FPE_FLTUND:
231				code = FPE_FLTUND_TRAP;
232				break;
233			case FPE_FLTRES:
234				code = FPE_FLTINEX_TRAP;
235				break;
236			default:
237				code = FPE_FLTOPERR_TRAP;
238				break;
239			}
240			break;
241
242		case SIGBUS:
243			switch (sip->si_code) {
244			case BUS_ADRALN:
245				code = BUS_ALIGN;
246				break;
247			case BUS_ADRERR:
248				code = BUS_HWERR;
249				break;
250			default:	/* BUS_OBJERR */
251				code = FC_MAKE_ERR(sip->si_errno);
252				break;
253			}
254			break;
255
256		case SIGSEGV:
257			switch (sip->si_code) {
258			case SEGV_MAPERR:
259				code = SEGV_NOMAP;
260				break;
261			case SEGV_ACCERR:
262				code = SEGV_PROT;
263				break;
264			default:
265				code = FC_MAKE_ERR(sip->si_errno);
266				break;
267			}
268			break;
269
270		default:
271			addr = SIG_NOADDR;
272			break;
273		}
274	}
275
276	(*_siguhandler[sig])(sig, code, &sc, addr);
277
278	if (sc.sc_onstack)
279		ucp->uc_stack.ss_flags |= SS_ONSTACK;
280	else
281		ucp->uc_stack.ss_flags &= ~SS_ONSTACK;
282	mask2set(sc.sc_mask, &ucp->uc_sigmask);
283
284#if defined(__sparc)
285	ucp->uc_mcontext.gregs[REG_SP] = sc.sc_sp;
286	ucp->uc_mcontext.gregs[REG_PC] = sc.sc_pc;
287	ucp->uc_mcontext.gregs[REG_nPC] = sc.sc_npc;
288#if defined(__sparcv9)
289	ucp->uc_mcontext.gregs[REG_CCR] = sc.sc_psr;
290#else
291	ucp->uc_mcontext.gregs[REG_PSR] = sc.sc_psr;
292#endif
293	ucp->uc_mcontext.gregs[REG_G1] = sc.sc_g1;
294	ucp->uc_mcontext.gregs[REG_O0] = sc.sc_o0;
295#ifdef NEVER
296	if (gwinswitch == 1) {
297		int i, j;
298
299		ucp->uc_mcontext.gwins->wbcnt = sc.sc_wbcnt;
300		/* XXX - should use bcopy to move this in bulk */
301		for (i = 0; i < sc.sc_wbcnt; i++) {
302			ucp->uc_mcontext.gwins->spbuf[i] = sc.sc_spbuf[i];
303			for (j = 0; j < 8; j++)
304				ucp->uc_mcontext.gwins->wbuf[i].rw_local[j] =
305				    sc.sc_wbuf[i][j];
306			for (j = 0; j < 8; j++)
307				ucp->uc_mcontext.gwins->wbuf[i].rw_in[j] =
308				    sc.sc_wbuf[i][j+8];
309		}
310	}
311#endif
312
313	if (sig == SIGFPE) {
314		if (ucp->uc_mcontext.fpregs.fpu_qcnt > 0) {
315			ucp->uc_mcontext.fpregs.fpu_qcnt--;
316			ucp->uc_mcontext.fpregs.fpu_q++;
317		}
318	}
319#endif
320
321	(void) setcontext(ucp);
322}
323
324#if defined(__sparc)
325/*
326 * Emulate the special sigcleanup trap.
327 * This is only used by statically linked 4.x applications
328 * and thus is only called by the static BCP support.
329 * It lives here because of its close relationship with
330 * the ucbsigvechandler code above.
331 *
332 * It's used by 4.x applications to:
333 *	1. return from a signal handler (in __sigtramp)
334 *	2. [sig]longjmp
335 *	3. context switch, in the old 4.x liblwp
336 */
337
338void
339__sigcleanup(struct sigcontext *scp)
340{
341	ucontext_t uc, *ucp;
342	int sig;
343
344	/*
345	 * If there's a pointer to a ucontext_t hiding in the sigcontext,
346	 * we *must* use that to return, since it contains important data
347	 * such as the original "out" registers when the signal occurred.
348	 */
349	if (scp->sc_wbcnt == sizeof (*ucp)) {
350		sig = (int)(uintptr_t)scp->sc_spbuf[0];
351		ucp = (ucontext_t *)scp->sc_spbuf[1];
352	} else {
353		/*
354		 * Otherwise, use a local ucontext_t and
355		 * initialize it with getcontext.
356		 */
357		sig = 0;
358		ucp = &uc;
359		(void) getcontext(ucp);
360	}
361
362	if (scp->sc_onstack) {
363		ucp->uc_stack.ss_flags |= SS_ONSTACK;
364	} else
365		ucp->uc_stack.ss_flags &= ~SS_ONSTACK;
366	mask2set(scp->sc_mask, &ucp->uc_sigmask);
367
368	ucp->uc_mcontext.gregs[REG_SP] = scp->sc_sp;
369	ucp->uc_mcontext.gregs[REG_PC] = scp->sc_pc;
370	ucp->uc_mcontext.gregs[REG_nPC] = scp->sc_npc;
371#if defined(__sparcv9)
372	ucp->uc_mcontext.gregs[REG_CCR] = scp->sc_psr;
373#else
374	ucp->uc_mcontext.gregs[REG_PSR] = scp->sc_psr;
375#endif
376	ucp->uc_mcontext.gregs[REG_G1] = scp->sc_g1;
377	ucp->uc_mcontext.gregs[REG_O0] = scp->sc_o0;
378
379	if (sig == SIGFPE) {
380		if (ucp->uc_mcontext.fpregs.fpu_qcnt > 0) {
381			ucp->uc_mcontext.fpregs.fpu_qcnt--;
382			ucp->uc_mcontext.fpregs.fpu_q++;
383		}
384	}
385	(void) setcontext(ucp);
386	/* NOTREACHED */
387}
388#endif
389
390int
391_sigsetmask(int mask)
392{
393	return (ucbsigsetmask(mask));
394}
395
396int
397ucbsigsetmask(int mask)
398{
399	sigset_t oset;
400	sigset_t nset;
401
402	(void) _sigprocmask(0, (sigset_t *)0, &nset);
403	mask2set(mask, &nset);
404	(void) _sigprocmask(SIG_SETMASK, &nset, &oset);
405	return (set2mask(&oset));
406}
407
408int
409_sigblock(int mask)
410{
411	return (ucbsigblock(mask));
412}
413
414int
415ucbsigblock(int mask)
416{
417	sigset_t oset;
418	sigset_t nset;
419
420	(void) _sigprocmask(0, (sigset_t *)0, &nset);
421	mask2set(mask, &nset);
422	(void) _sigprocmask(SIG_BLOCK, &nset, &oset);
423	return (set2mask(&oset));
424}
425
426int
427usigpause(int mask)
428{
429	return (ucbsigpause(mask));
430}
431
432int
433ucbsigpause(int mask)
434{
435	sigset_t set, oset;
436	int ret;
437
438	(void) _sigprocmask(0, (sigset_t *)0, &set);
439	oset = set;
440	mask2set(mask, &set);
441	ret = sigsuspend(&set);
442	(void) _sigprocmask(SIG_SETMASK, &oset, (sigset_t *)0);
443	return (ret);
444}
445
446int
447_sigvec(int sig, struct sigvec *nvec, struct sigvec *ovec)
448{
449	return (ucbsigvec(sig, nvec, ovec));
450}
451
452int
453ucbsigvec(int sig, struct sigvec *nvec, struct sigvec *ovec)
454{
455	struct sigaction nact;
456	struct sigaction oact;
457	struct sigaction *nactp;
458	void (*ohandler)(int, int, struct sigcontext *, char *);
459	void (*nhandler)(int, int, struct sigcontext *, char *);
460
461	if (sig <= 0 || sig >= NSIG) {
462		errno = EINVAL;
463		return (-1);
464	}
465
466	if ((long)ovec == -1L || (long)nvec == -1L) {
467		errno = EFAULT;
468		return (-1);
469	}
470
471	ohandler = _siguhandler[sig];
472
473	if (nvec) {
474		(void) _sigaction(sig, (struct sigaction *)0, &nact);
475		nhandler = nvec->sv_handler;
476		/*
477		 * To be compatible with the behavior of SunOS 4.x:
478		 * If the new signal handler is SIG_IGN or SIG_DFL,
479		 * do not change the signal's entry in the handler array.
480		 * This allows a child of vfork(2) to set signal handlers
481		 * to SIG_IGN or SIG_DFL without affecting the parent.
482		 */
483		if ((void (*)(int))nhandler != SIG_DFL &&
484		    (void (*)(int))nhandler != SIG_IGN) {
485			_siguhandler[sig] = nhandler;
486			nact.sa_handler = (void (*)(int))ucbsigvechandler;
487		} else {
488			nact.sa_handler = (void (*)(int))nhandler;
489		}
490		mask2set(nvec->sv_mask, &nact.sa_mask);
491		if (sig == SIGKILL || sig == SIGSTOP)
492			nact.sa_handler = SIG_DFL;
493		nact.sa_flags = SA_SIGINFO;
494		if (!(nvec->sv_flags & SV_INTERRUPT))
495			nact.sa_flags |= SA_RESTART;
496		if (nvec->sv_flags & SV_RESETHAND)
497			nact.sa_flags |= SA_RESETHAND;
498		if (nvec->sv_flags & SV_ONSTACK)
499			nact.sa_flags |= SA_ONSTACK;
500		nactp = &nact;
501	} else
502		nactp = (struct sigaction *)0;
503
504	if (_sigaction(sig, nactp, &oact) < 0) {
505		_siguhandler[sig] = ohandler;
506		return (-1);
507	}
508
509	if (ovec) {
510		if (oact.sa_handler == SIG_DFL || oact.sa_handler == SIG_IGN)
511			ovec->sv_handler =
512			    (void (*) (int, int, struct sigcontext *, char *))
513			    oact.sa_handler;
514		else
515			ovec->sv_handler = ohandler;
516		ovec->sv_mask = set2mask(&oact.sa_mask);
517		ovec->sv_flags = 0;
518		if (oact.sa_flags & SA_ONSTACK)
519			ovec->sv_flags |= SV_ONSTACK;
520		if (oact.sa_flags & SA_RESETHAND)
521			ovec->sv_flags |= SV_RESETHAND;
522		if (!(oact.sa_flags & SA_RESTART))
523			ovec->sv_flags |= SV_INTERRUPT;
524	}
525
526	return (0);
527}
528
529int
530_sigstack(struct sigstack *nss, struct sigstack *oss)
531{
532	struct sigaltstack nalt;
533	struct sigaltstack oalt;
534	struct sigaltstack *naltp;
535
536	if (nss) {
537		/*
538		 * XXX: assumes stack growth is down (like sparc)
539		 */
540		nalt.ss_sp = nss->ss_sp - SIGSTKSZ;
541		nalt.ss_size = SIGSTKSZ;
542		nalt.ss_flags = 0;
543		naltp = &nalt;
544	} else
545		naltp = (struct sigaltstack *)0;
546
547	if (sigaltstack(naltp, &oalt) < 0)
548		return (-1);
549
550	if (oss) {
551		/*
552		 * XXX: assumes stack growth is down (like sparc)
553		 */
554		oss->ss_sp = oalt.ss_sp + oalt.ss_size;
555		oss->ss_onstack = ((oalt.ss_flags & SS_ONSTACK) != 0);
556	}
557
558	return (0);
559}
560
561void (*
562ucbsignal(int s, void (*a)(int)))(int)
563{
564	struct sigvec osv;
565	struct sigvec nsv;
566	static int mask[NSIG];
567	static int flags[NSIG];
568
569	nsv.sv_handler = (void (*) (int, int, struct sigcontext *, char *)) a;
570	nsv.sv_mask = mask[s];
571	nsv.sv_flags = flags[s];
572	if (ucbsigvec(s, &nsv, &osv) < 0)
573		return (SIG_ERR);
574	if (nsv.sv_mask != osv.sv_mask || nsv.sv_flags != osv.sv_flags) {
575		mask[s] = nsv.sv_mask = osv.sv_mask;
576		flags[s] = nsv.sv_flags =
577		    osv.sv_flags & ~(SV_RESETHAND|SV_INTERRUPT);
578		if (ucbsigvec(s, &nsv, (struct sigvec *)0) < 0)
579			return (SIG_ERR);
580	}
581	return ((void (*) (int)) osv.sv_handler);
582}
583
584void (*
585usignal(int s, void (*a) (int)))(int)
586{
587	return (ucbsignal(s, a));
588}
589
590/*
591 * Set signal state to prevent restart of system calls
592 * after an instance of the indicated signal.
593 */
594
595int
596_siginterrupt(int sig, int flag)
597{
598	return (ucbsiginterrupt(sig, flag));
599}
600
601int
602ucbsiginterrupt(int sig, int flag)
603{
604	struct sigvec sv;
605	int ret;
606
607	if ((ret = ucbsigvec(sig, 0, &sv)) < 0)
608		return (ret);
609	if (flag)
610		sv.sv_flags |= SV_INTERRUPT;
611	else
612		sv.sv_flags &= ~SV_INTERRUPT;
613	return (ucbsigvec(sig, &sv, 0));
614}
615