mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-11 05:40:06 +00:00
247 lines
6.4 KiB
C
247 lines
6.4 KiB
C
/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with the GNU C Library; see the file COPYING.LIB. If
|
|
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
|
Cambridge, MA 02139, USA. */
|
|
|
|
#include <ansidecl.h>
|
|
|
|
#ifndef __GNUC__
|
|
#error This file uses GNU C extensions; you must compile with GCC.
|
|
#endif
|
|
|
|
/* Get the definition of `struct sigcontext'. */
|
|
#define KERNEL
|
|
#define sigvec sun_sigvec
|
|
#define sigstack sun_sigstack
|
|
#define sigcontext sun_sigcontext
|
|
#include "/usr/include/sys/signal.h"
|
|
#undef sigvec
|
|
#undef sigstack
|
|
#undef sigcontext
|
|
#undef NSIG
|
|
#undef SIGABRT
|
|
#undef SIGCLD
|
|
#undef SV_ONSTACK
|
|
#undef SV_RESETHAND
|
|
#undef SV_INTERRUPT
|
|
#undef SA_ONSTACK
|
|
#undef SA_NOCLDSTOP
|
|
#undef SIG_ERR
|
|
#undef SIG_DFL
|
|
#undef SIG_IGN
|
|
#undef sigmask
|
|
#undef SIG_BLOCK
|
|
#undef SIG_UNBLOCK
|
|
#undef SIG_SETMASK
|
|
|
|
#include <signal.h>
|
|
#include <stddef.h>
|
|
#include <errno.h>
|
|
|
|
/* Defined in __sigvec.S. */
|
|
extern int EXFUN(__raw_sigvec, (int sig, CONST struct sigvec *vec,
|
|
struct sigvec *ovec));
|
|
|
|
/* User-specified signal handlers. */
|
|
#define mytramp 1
|
|
#ifdef mytramp
|
|
static __sighandler_t handlers[NSIG];
|
|
#else
|
|
#define handlers _sigfunc
|
|
extern __sighandler_t _sigfunc[];
|
|
#endif
|
|
|
|
#if mytramp
|
|
|
|
/* Handler for all signals that are handled by a user-specified function.
|
|
Saves and restores the general regs %g2-%g7, the %y register, and
|
|
all the FPU regs (including %fsr), around calling the user's handler. */
|
|
static void
|
|
DEFUN(trampoline, (sig), int sig)
|
|
{
|
|
/* We use `double' and `long long int' so `std' (store doubleword) insns,
|
|
which might be faster than single-word stores, will be generated. */
|
|
register double f0 asm("%f0");
|
|
register double f2 asm("%f2");
|
|
register double f4 asm("%f4");
|
|
register double f6 asm("%f6");
|
|
register double f8 asm("%f8");
|
|
register double f10 asm("%f10");
|
|
register double f12 asm("%f12");
|
|
register double f14 asm("%f14");
|
|
register double f16 asm("%f16");
|
|
register double f18 asm("%f18");
|
|
register double f20 asm("%f20");
|
|
register double f22 asm("%f22");
|
|
register double f24 asm("%f24");
|
|
register double f26 asm("%f26");
|
|
register double f28 asm("%f28");
|
|
register double f30 asm("%f30");
|
|
register long long int g2 asm("%g2");
|
|
register long long int g4 asm("%g4");
|
|
register long long int g6 asm("%g6");
|
|
register int *fp asm("%fp");
|
|
|
|
int code;
|
|
register struct sigcontext *context asm("%i0"); /* See end of fn. */
|
|
PTR addr;
|
|
int y;
|
|
double fpsave[16];
|
|
int fsr;
|
|
int savefpu;
|
|
long long int glsave[3];
|
|
|
|
/* SIG isn't really passed as an arg.
|
|
The args to the signal handler are at fp[16..19]. */
|
|
sig = fp[16];
|
|
code = fp[17];
|
|
context = (struct sigcontext *) fp[18];
|
|
addr = (PTR) fp[19];
|
|
|
|
/* Save the Y register. */
|
|
asm("rd %%y, %0" : "=r" (y));
|
|
|
|
/* Save the FPU regs if the FPU enable bit is set in the PSR,
|
|
and the signal isn't an FP exception. */
|
|
savefpu = (context->sc_psr & 0x1000) && sig != SIGFPE;
|
|
if (savefpu)
|
|
{
|
|
fpsave[0] = f0;
|
|
fpsave[1] = f2;
|
|
fpsave[2] = f4;
|
|
fpsave[3] = f6;
|
|
fpsave[4] = f8;
|
|
fpsave[5] = f10;
|
|
fpsave[6] = f12;
|
|
fpsave[7] = f14;
|
|
fpsave[8] = f16;
|
|
fpsave[9] = f18;
|
|
fpsave[10] = f20;
|
|
fpsave[11] = f22;
|
|
fpsave[12] = f24;
|
|
fpsave[13] = f26;
|
|
fpsave[14] = f28;
|
|
fpsave[15] = f30;
|
|
|
|
/* Force it into a stack slot so the asm won't barf. Sigh. */
|
|
(void) &fsr;
|
|
asm("st %%fsr, %0" : "=m" (fsr));
|
|
}
|
|
|
|
/* Save the global registers (except for %g1, which is a scratch reg). */
|
|
glsave[0] = g2;
|
|
glsave[1] = g4;
|
|
glsave[2] = g6;
|
|
|
|
/* Call the user's handler. */
|
|
(*((void EXFUN((*), (int sig, int code, struct sigcontext *context,
|
|
PTR addr))) handlers[sig]))
|
|
(sig, code, context, addr);
|
|
|
|
/* Restore the Y register. */
|
|
asm("mov %0, %%y" : : "r" (y));
|
|
|
|
if (savefpu)
|
|
{
|
|
/* Restore the FPU regs. */
|
|
f0 = fpsave[0];
|
|
f2 = fpsave[1];
|
|
f4 = fpsave[2];
|
|
f6 = fpsave[3];
|
|
f8 = fpsave[4];
|
|
f10 = fpsave[5];
|
|
f12 = fpsave[6];
|
|
f14 = fpsave[7];
|
|
f16 = fpsave[8];
|
|
f18 = fpsave[9];
|
|
f20 = fpsave[10];
|
|
f22 = fpsave[11];
|
|
f24 = fpsave[12];
|
|
f26 = fpsave[13];
|
|
f28 = fpsave[14];
|
|
f30 = fpsave[15];
|
|
|
|
asm("ld %0, %%fsr" : : "m" (fsr));
|
|
}
|
|
|
|
/* Restore the globals. */
|
|
g2 = glsave[0];
|
|
g4 = glsave[1];
|
|
g6 = glsave[2];
|
|
|
|
/* Unwind a frame, and do a "sigcleanup" system call.
|
|
The system call apparently does a return.
|
|
I don't know what it's for. Ask Sun. */
|
|
asm("restore %%g0, 139, %%g1\n"
|
|
"ta 0\n"
|
|
"mov %0, %0" /* Useless insn that will never be executed, */
|
|
/* here to make the compiler happy. */
|
|
: /* No outputs. */ :
|
|
/* CONTEXT is bound to %i0. We reference it as an input here to make
|
|
sure the compiler considers it live at this point, and preserves
|
|
the value in that register. The restore makes %i0 become %o0, the
|
|
argument to the system call. */
|
|
"r" (context));
|
|
}
|
|
#endif
|
|
|
|
int
|
|
DEFUN(__sigvec, (sig, vec, ovec),
|
|
int sig AND CONST struct sigvec *vec AND struct sigvec *ovec)
|
|
{
|
|
#ifndef mytramp
|
|
extern void _sigtramp (int);
|
|
#define trampoline _sigtramp
|
|
#endif
|
|
struct sigvec myvec;
|
|
int mask;
|
|
__sighandler_t ohandler;
|
|
|
|
if (sig <= 0 || sig >= NSIG)
|
|
{
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
mask = __sigblock(sigmask(sig));
|
|
|
|
ohandler = handlers[sig];
|
|
|
|
if (vec != NULL &&
|
|
vec->sv_handler != SIG_IGN && vec->sv_handler != SIG_DFL)
|
|
{
|
|
handlers[sig] = vec->sv_handler;
|
|
myvec = *vec;
|
|
myvec.sv_handler = trampoline;
|
|
vec = &myvec;
|
|
}
|
|
|
|
if (__raw_sigvec(sig, vec, ovec) < 0)
|
|
{
|
|
int save = errno;
|
|
(void) __sigsetmask(mask);
|
|
errno = save;
|
|
return -1;
|
|
}
|
|
|
|
if (ovec != NULL && ovec->sv_handler == trampoline)
|
|
ovec->sv_handler = ohandler;
|
|
|
|
(void) __sigsetmask(mask);
|
|
|
|
return 0;
|
|
}
|