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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
35 #pragma ident "%Z%%M% %I% %E% SMI"
40 * 4.3BSD signal compatibility functions
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:
46 * for (i = 0; i < NSIG; i++)
50 #include <sys/types.h>
55 #undef BUS_OBJERR /* namespace conflict */
56 #include <sys/siginfo.h>
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
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.
74 extern int _sigfillset(sigset_t
*);
75 extern int _sigemptyset(sigset_t
*);
76 extern int _sigprocmask(int, const sigset_t
*, sigset_t
*);
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))))
83 void (*_siguhandler
[NSIG
])() = { 0 };
86 * forward declarations
88 int ucbsiginterrupt(int, int);
89 int ucbsigvec(int, struct sigvec
*, struct sigvec
*);
92 int ucbsigsetmask(int);
93 static void ucbsigvechandler(int, siginfo_t
*, ucontext_t
*);
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
103 _sigvechandler(int sig
, siginfo_t
*sip
, ucontext_t
*ucp
)
105 ucbsigvechandler(sig
, sip
, ucp
);
106 return (0); /* keep the same as the original prototype */
110 ucbsigvechandler(int sig
, siginfo_t
*sip
, ucontext_t
*ucp
)
112 struct sigcontext sc
;
119 sc
.sc_onstack
= ((ucp
->uc_stack
.ss_flags
& SS_ONSTACK
) != 0);
120 sc
.sc_mask
= set2mask(&ucp
->uc_sigmask
);
123 if (sig
== SIGFPE
&& sip
!= NULL
&& SI_FROMKERNEL(sip
) &&
124 (sip
->si_code
== FPE_INTDIV
|| sip
->si_code
== FPE_INTOVF
)) {
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.)
130 ucp
->uc_mcontext
.gregs
[REG_PC
] =
131 ucp
->uc_mcontext
.gregs
[REG_nPC
];
132 ucp
->uc_mcontext
.gregs
[REG_nPC
] += 4;
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
];
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
];
142 sc
.sc_psr
= ucp
->uc_mcontext
.gregs
[REG_PSR
];
145 sc
.sc_g1
= ucp
->uc_mcontext
.gregs
[REG_G1
];
146 sc
.sc_o0
= ucp
->uc_mcontext
.gregs
[REG_O0
];
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.
156 sc
.sc_wbcnt
= (int)(sizeof (*ucp
));
157 sc
.sc_spbuf
[0] = (char *)(uintptr_t)sig
;
158 sc
.sc_spbuf
[1] = (char *)ucp
;
161 * XXX - Sorry, we can never pass the saved register windows
162 * on in the sigcontext because we use that space to save the
165 if (ucp
->uc_mcontext
.gwins
!= (gwindows_t
*)0) {
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
++)
175 ucp
->uc_mcontext
.gwins
->wbuf
[i
].rw_local
[j
];
176 for (j
= 0; j
< 8; j
++)
178 ucp
->uc_mcontext
.gwins
->wbuf
[i
].rw_in
[j
];
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.
191 if (sip
!= NULL
&& SI_FROMKERNEL(sip
)) {
196 switch (sip
->si_code
) {
198 code
= ILL_PRIVINSTR_FAULT
;
204 code
= ILL_TRAP_FAULT(sip
->si_trapno
);
207 code
= ILL_ILLINSTR_FAULT
;
217 switch (sip
->si_code
) {
219 code
= FPE_INTDIV_TRAP
;
222 code
= FPE_INTOVF_TRAP
;
225 code
= FPE_FLTDIV_TRAP
;
228 code
= FPE_FLTOVF_TRAP
;
231 code
= FPE_FLTUND_TRAP
;
234 code
= FPE_FLTINEX_TRAP
;
237 code
= FPE_FLTOPERR_TRAP
;
243 switch (sip
->si_code
) {
250 default: /* BUS_OBJERR */
251 code
= FC_MAKE_ERR(sip
->si_errno
);
257 switch (sip
->si_code
) {
265 code
= FC_MAKE_ERR(sip
->si_errno
);
276 (*_siguhandler
[sig
])(sig
, code
, &sc
, addr
);
279 ucp
->uc_stack
.ss_flags
|= SS_ONSTACK
;
281 ucp
->uc_stack
.ss_flags
&= ~SS_ONSTACK
;
282 mask2set(sc
.sc_mask
, &ucp
->uc_sigmask
);
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
;
291 ucp
->uc_mcontext
.gregs
[REG_PSR
] = sc
.sc_psr
;
293 ucp
->uc_mcontext
.gregs
[REG_G1
] = sc
.sc_g1
;
294 ucp
->uc_mcontext
.gregs
[REG_O0
] = sc
.sc_o0
;
296 if (gwinswitch
== 1) {
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
] =
306 for (j
= 0; j
< 8; j
++)
307 ucp
->uc_mcontext
.gwins
->wbuf
[i
].rw_in
[j
] =
314 if (ucp
->uc_mcontext
.fpregs
.fpu_qcnt
> 0) {
315 ucp
->uc_mcontext
.fpregs
.fpu_qcnt
--;
316 ucp
->uc_mcontext
.fpregs
.fpu_q
++;
321 (void) setcontext(ucp
);
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.
332 * It's used by 4.x applications to:
333 * 1. return from a signal handler (in __sigtramp)
335 * 3. context switch, in the old 4.x liblwp
339 __sigcleanup(struct sigcontext
*scp
)
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.
349 if (scp
->sc_wbcnt
== sizeof (*ucp
)) {
350 sig
= (int)(uintptr_t)scp
->sc_spbuf
[0];
351 ucp
= (ucontext_t
*)scp
->sc_spbuf
[1];
354 * Otherwise, use a local ucontext_t and
355 * initialize it with getcontext.
359 (void) getcontext(ucp
);
362 if (scp
->sc_onstack
) {
363 ucp
->uc_stack
.ss_flags
|= SS_ONSTACK
;
365 ucp
->uc_stack
.ss_flags
&= ~SS_ONSTACK
;
366 mask2set(scp
->sc_mask
, &ucp
->uc_sigmask
);
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
;
374 ucp
->uc_mcontext
.gregs
[REG_PSR
] = scp
->sc_psr
;
376 ucp
->uc_mcontext
.gregs
[REG_G1
] = scp
->sc_g1
;
377 ucp
->uc_mcontext
.gregs
[REG_O0
] = scp
->sc_o0
;
380 if (ucp
->uc_mcontext
.fpregs
.fpu_qcnt
> 0) {
381 ucp
->uc_mcontext
.fpregs
.fpu_qcnt
--;
382 ucp
->uc_mcontext
.fpregs
.fpu_q
++;
385 (void) setcontext(ucp
);
391 _sigsetmask(int mask
)
393 return (ucbsigsetmask(mask
));
397 ucbsigsetmask(int mask
)
402 (void) _sigprocmask(0, (sigset_t
*)0, &nset
);
403 mask2set(mask
, &nset
);
404 (void) _sigprocmask(SIG_SETMASK
, &nset
, &oset
);
405 return (set2mask(&oset
));
411 return (ucbsigblock(mask
));
415 ucbsigblock(int mask
)
420 (void) _sigprocmask(0, (sigset_t
*)0, &nset
);
421 mask2set(mask
, &nset
);
422 (void) _sigprocmask(SIG_BLOCK
, &nset
, &oset
);
423 return (set2mask(&oset
));
429 return (ucbsigpause(mask
));
433 ucbsigpause(int mask
)
438 (void) _sigprocmask(0, (sigset_t
*)0, &set
);
440 mask2set(mask
, &set
);
441 ret
= sigsuspend(&set
);
442 (void) _sigprocmask(SIG_SETMASK
, &oset
, (sigset_t
*)0);
447 _sigvec(int sig
, struct sigvec
*nvec
, struct sigvec
*ovec
)
449 return (ucbsigvec(sig
, nvec
, ovec
));
453 ucbsigvec(int sig
, struct sigvec
*nvec
, struct sigvec
*ovec
)
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 *);
461 if (sig
<= 0 || sig
>= NSIG
) {
466 if ((long)ovec
== -1L || (long)nvec
== -1L) {
471 ohandler
= _siguhandler
[sig
];
474 (void) _sigaction(sig
, (struct sigaction
*)0, &nact
);
475 nhandler
= nvec
->sv_handler
;
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.
483 if ((void (*)(int))nhandler
!= SIG_DFL
&&
484 (void (*)(int))nhandler
!= SIG_IGN
) {
485 _siguhandler
[sig
] = nhandler
;
486 nact
.sa_handler
= (void (*)(int))ucbsigvechandler
;
488 nact
.sa_handler
= (void (*)(int))nhandler
;
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
;
502 nactp
= (struct sigaction
*)0;
504 if (_sigaction(sig
, nactp
, &oact
) < 0) {
505 _siguhandler
[sig
] = ohandler
;
510 if (oact
.sa_handler
== SIG_DFL
|| oact
.sa_handler
== SIG_IGN
)
512 (void (*) (int, int, struct sigcontext
*, char *))
515 ovec
->sv_handler
= ohandler
;
516 ovec
->sv_mask
= set2mask(&oact
.sa_mask
);
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
;
530 _sigstack(struct sigstack
*nss
, struct sigstack
*oss
)
532 struct sigaltstack nalt
;
533 struct sigaltstack oalt
;
534 struct sigaltstack
*naltp
;
538 * XXX: assumes stack growth is down (like sparc)
540 nalt
.ss_sp
= nss
->ss_sp
- SIGSTKSZ
;
541 nalt
.ss_size
= SIGSTKSZ
;
545 naltp
= (struct sigaltstack
*)0;
547 if (sigaltstack(naltp
, &oalt
) < 0)
552 * XXX: assumes stack growth is down (like sparc)
554 oss
->ss_sp
= oalt
.ss_sp
+ oalt
.ss_size
;
555 oss
->ss_onstack
= ((oalt
.ss_flags
& SS_ONSTACK
) != 0);
562 ucbsignal(int s
, void (*a
)(int)))(int)
566 static int mask
[NSIG
];
567 static int flags
[NSIG
];
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)
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)
581 return ((void (*) (int)) osv
.sv_handler
);
585 usignal(int s
, void (*a
) (int)))(int)
587 return (ucbsignal(s
, a
));
591 * Set signal state to prevent restart of system calls
592 * after an instance of the indicated signal.
596 _siginterrupt(int sig
, int flag
)
598 return (ucbsiginterrupt(sig
, flag
));
602 ucbsiginterrupt(int sig
, int flag
)
607 if ((ret
= ucbsigvec(sig
, 0, &sv
)) < 0)
610 sv
.sv_flags
|= SV_INTERRUPT
;
612 sv
.sv_flags
&= ~SV_INTERRUPT
;
613 return (ucbsigvec(sig
, &sv
, 0));