hurd: implement SA_SIGINFO signal handlers.

SA_SIGINFO is actually just another way of expressing what we were
already passing over with struct sigcontext. This just introduces the
SIGINFO interface and fixes the posix values when that interface is
requested by the application.
This commit is contained in:
Jeremie Koenig 2020-12-21 01:41:55 +01:00 committed by Samuel Thibault
parent 407765e9f2
commit d865ff74ba
11 changed files with 209 additions and 67 deletions

View File

@ -65,6 +65,7 @@ struct sigaction
# define SA_RESETHAND 0x0004 /* Reset to SIG_DFL on entry to handler. */
#endif
#define SA_NOCLDSTOP 0x0008 /* Don't send SIGCHLD when children stop. */
#define SA_SIGINFO 0x0040 /* Signal handler with SA_SIGINFO args */
#ifdef __USE_MISC
# define SA_INTERRUPT 0 /* Historical no-op ("not SA_RESTART"). */

View File

@ -288,6 +288,11 @@ extern int _hurd_raise_signal (struct hurd_sigstate *ss, int signo,
extern void _hurd_exception2signal (struct hurd_signal_detail *detail,
int *signo);
/* Translate a Mach exception into a signal with a legacy sigcode. */
extern void _hurd_exception2signal_legacy (struct hurd_signal_detail *detail,
int *signo);
/* Make the thread described by SS take the signal described by SIGNO and
DETAIL. If the process is traced, this will in fact stop with a SIGNO

View File

@ -70,7 +70,7 @@ _hurdsig_fault_catch_exception_raise (mach_port_t port,
codes into a signal number and subcode. */
_hurd_exception2signal (&d, &signo);
return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.code)
return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.exc_subcode)
? 0 : EGREGIOUS;
}

View File

@ -205,7 +205,7 @@ _hurd_new_proc_init (char **argv,
/* This process is "traced", meaning it should stop on signals or exec.
We are all set up now to handle signals. Stop ourselves, to inform
our parent (presumably a debugger) that the exec has completed. */
__msg_sig_post (_hurd_msgport, SIGTRAP, 0, __mach_task_self ());
__msg_sig_post (_hurd_msgport, SIGTRAP, TRAP_TRACE, __mach_task_self ());
}
#include <shlib-compat.h>

View File

@ -735,7 +735,7 @@ post_signal (struct hurd_sigstate *ss,
{ /* PE cannot be null. */
do
{
if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->code))
if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->exc_subcode))
{
if (pe->preemptor)
{
@ -1379,7 +1379,7 @@ _S_msg_sig_post (mach_port_t me,
if (err = signal_allowed (signo, refport))
return err;
d.code = sigcode;
d.code = d.exc_subcode = sigcode;
d.exc = 0;
/* Post the signal to a global receiver thread (or mark it pending in
@ -1408,7 +1408,7 @@ _S_msg_sig_post_untraced (mach_port_t me,
if (err = signal_allowed (signo, refport))
return err;
d.code = sigcode;
d.code = d.exc_subcode = sigcode;
d.exc = 0;
/* Post the signal to the designated signal-receiving thread. This will

View File

@ -97,6 +97,10 @@ struct sigcontext
#define sc_ps sc_efl
/* The deprecated sigcode values below are passed as an extra, non-portable
argument to regular signal handlers. You should use SA_SIGINFO handlers
instead, which use the standard POSIX signal codes. */
/* Codes for SIGFPE. */
#define FPE_INTOVF_TRAP 0x1 /* integer overflow */
#define FPE_INTDIV_FAULT 0x2 /* integer divide by zero */

View File

@ -23,8 +23,8 @@
/* Translate the Mach exception codes, as received in an `exception_raise' RPC,
into a signal number and signal subcode. */
void
_hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
static void
exception2signal (struct hurd_signal_detail *detail, int *signo, int posix)
{
detail->error = 0;
@ -36,44 +36,62 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
break;
case EXC_BAD_ACCESS:
if (detail->exc_code == KERN_INVALID_ADDRESS
|| detail->exc_code == KERN_PROTECTION_FAILURE
|| detail->exc_code == KERN_WRITE_PROTECTION_FAILURE)
*signo = SIGSEGV;
else
*signo = SIGBUS;
detail->code = detail->exc_subcode;
switch (detail->exc_code)
{
case KERN_INVALID_ADDRESS:
case KERN_MEMORY_FAILURE:
*signo = SIGSEGV;
detail->code = posix ? SEGV_MAPERR : detail->exc_subcode;
break;
case KERN_PROTECTION_FAILURE:
case KERN_WRITE_PROTECTION_FAILURE:
*signo = SIGSEGV;
detail->code = posix ? SEGV_ACCERR : detail->exc_subcode;
break;
default:
*signo = SIGBUS;
detail->code = posix ? BUS_ADRERR : detail->exc_subcode;
break;
}
detail->error = detail->exc_code;
break;
case EXC_BAD_INSTRUCTION:
*signo = SIGILL;
if (detail->exc_code == EXC_I386_INVOP)
detail->code = ILL_INVOPR_FAULT;
else if (detail->exc_code == EXC_I386_STKFLT)
detail->code = ILL_STACK_FAULT;
else
detail->code = 0;
switch (detail->exc_code)
{
case EXC_I386_INVOP:
detail->code = posix ? ILL_ILLOPC : ILL_INVOPR_FAULT;
break;
case EXC_I386_STKFLT:
detail->code = posix ? ILL_BADSTK : ILL_STACK_FAULT;
break;
default:
detail->code = 0;
break;
}
break;
case EXC_ARITHMETIC:
*signo = SIGFPE;
switch (detail->exc_code)
{
case EXC_I386_DIV: /* integer divide by zero */
*signo = SIGFPE;
detail->code = FPE_INTDIV_FAULT;
detail->code = posix ? FPE_INTDIV : FPE_INTDIV_FAULT;
break;
case EXC_I386_INTO: /* integer overflow */
*signo = SIGFPE;
detail->code = FPE_INTOVF_TRAP;
detail->code = posix ? FPE_INTOVF : FPE_INTOVF_TRAP;
break;
/* These aren't anywhere documented or used in Mach 3.0. */
case EXC_I386_NOEXT:
case EXC_I386_EXTOVR:
default:
*signo = SIGFPE;
detail->code = 0;
break;
@ -82,51 +100,43 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
Give an error code corresponding to the first bit set. */
if (detail->exc_subcode & FPS_IE)
{
*signo = SIGILL;
detail->code = ILL_FPEOPR_FAULT;
/* NB: We used to send SIGILL here but we can't distinguish
POSIX vs. legacy with respect to what signal we send. */
detail->code = posix ? FPE_FLTINV : 0 /*ILL_FPEOPR_FAULT*/;
}
else if (detail->exc_subcode & FPS_DE)
{
*signo = SIGFPE;
detail->code = FPE_FLTDNR_FAULT;
detail->code = posix ? FPE_FLTUND : FPE_FLTDNR_FAULT;
}
else if (detail->exc_subcode & FPS_ZE)
{
*signo = SIGFPE;
detail->code = FPE_FLTDIV_FAULT;
detail->code = posix ? FPE_FLTDIV : FPE_FLTDIV_FAULT;
}
else if (detail->exc_subcode & FPS_OE)
{
*signo = SIGFPE;
detail->code = FPE_FLTOVF_FAULT;
detail->code = posix ? FPE_FLTOVF : FPE_FLTOVF_FAULT;
}
else if (detail->exc_subcode & FPS_UE)
{
*signo = SIGFPE;
detail->code = FPE_FLTUND_FAULT;
detail->code = posix ? FPE_FLTUND : FPE_FLTUND_FAULT;
}
else if (detail->exc_subcode & FPS_PE)
{
*signo = SIGFPE;
detail->code = FPE_FLTINX_FAULT;
detail->code = posix ? FPE_FLTRES : FPE_FLTINX_FAULT;
}
else
{
*signo = SIGFPE;
detail->code = 0;
}
break;
/* These two can only be arithmetic exceptions if we
are in V86 mode, which sounds like emulation to me.
(See Mach 3.0 i386/trap.c.) */
are in V86 mode. (See Mach 3.0 i386/trap.c.) */
case EXC_I386_EMERR:
*signo = SIGFPE;
detail->code = FPE_EMERR_FAULT;
detail->code = posix ? 0 : FPE_EMERR_FAULT;
break;
case EXC_I386_BOUND:
*signo = SIGFPE;
detail->code = FPE_EMBND_FAULT;
detail->code = posix ? FPE_FLTSUB : FPE_EMBND_FAULT;
break;
}
break;
@ -143,7 +153,7 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
if (detail->exc_code == EXC_I386_BOUND)
{
*signo = SIGFPE;
detail->code = FPE_SUBRNG_FAULT;
detail->code = posix ? FPE_FLTSUB : FPE_SUBRNG_FAULT;
}
else
{
@ -154,13 +164,33 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
case EXC_BREAKPOINT:
*signo = SIGTRAP;
if (detail->exc_code == EXC_I386_SGL)
detail->code = DBG_SINGLE_TRAP;
else if (detail->exc_code == EXC_I386_BPT)
detail->code = DBG_BRKPNT_FAULT;
else
detail->code = 0;
switch (detail->exc_code)
{
case EXC_I386_SGL:
detail->code = posix ? TRAP_BRKPT : DBG_SINGLE_TRAP;
break;
case EXC_I386_BPT:
detail->code = posix ? TRAP_BRKPT : DBG_BRKPNT_FAULT;
break;
default:
detail->code = 0;
break;
}
break;
}
}
libc_hidden_def (_hurd_exception2signal)
void
_hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
{
exception2signal (detail, signo, 1);
}
void
_hurd_exception2signal_legacy (struct hurd_signal_detail *detail, int *signo)
{
exception2signal (detail, signo, 0);
}

View File

@ -18,11 +18,10 @@
#ifndef _SIGCONTEXTINFO_H
#define _SIGCONTEXTINFO_H
#define SIGCONTEXT struct sigcontext
static inline uintptr_t
sigcontext_get_pc (struct sigcontext ctx)
sigcontext_get_pc (struct ucontext_t *ctx)
{
return ctx.sc_eip;
return ctx->uc_mcontext.gregs[REG_EIP];
}
#endif

View File

@ -19,13 +19,66 @@
#include <hurd/signal.h>
#include <hurd/userlink.h>
#include <thread_state.h>
#include <mach/exception.h>
#include <mach/machine/eflags.h>
#include <assert.h>
#include <errno.h>
#include "hurdfault.h"
#include <intr-msg.h>
#include <sys/ucontext.h>
/* Fill in a siginfo_t structure for SA_SIGINFO-enabled handlers. */
static void fill_siginfo (siginfo_t *si, int signo,
const struct hurd_signal_detail *detail,
const struct machine_thread_all_state *state)
{
si->si_signo = signo;
si->si_errno = detail->error;
si->si_code = detail->code;
/* XXX We would need a protocol change for sig_post to include
* this information. */
si->si_pid = -1;
si->si_uid = -1;
/* Address of the faulting instruction or memory access. */
if (detail->exc == EXC_BAD_ACCESS)
si->si_addr = (void *) detail->exc_subcode;
else
si->si_addr = (void *) state->basic.eip;
/* XXX On SIGCHLD, this should be the exit status of the child
* process. We would need a protocol change for the proc server
* to send this information along with the signal. */
si->si_status = 0;
si->si_band = 0; /* SIGPOLL is not supported yet. */
si->si_value.sival_int = 0; /* sigqueue() is not supported yet. */
}
/* Fill in a ucontext_t structure SA_SIGINFO-enabled handlers. */
static void fill_ucontext (ucontext_t *uc, const struct sigcontext *sc)
{
uc->uc_flags = 0;
uc->uc_link = NULL;
uc->uc_sigmask = sc->sc_mask;
uc->uc_stack.ss_sp = (__ptr_t) sc->sc_esp;
uc->uc_stack.ss_size = 0;
uc->uc_stack.ss_flags = 0;
/* Registers. */
memcpy (&uc->uc_mcontext.gregs[REG_GS], &sc->sc_gs,
(REG_TRAPNO - REG_GS) * sizeof (int));
uc->uc_mcontext.gregs[REG_TRAPNO] = 0;
uc->uc_mcontext.gregs[REG_ERR] = 0;
memcpy (&uc->uc_mcontext.gregs[REG_EIP], &sc->sc_eip,
(NGREG - REG_EIP) * sizeof (int));
/* XXX FPU state. */
memset (&uc->uc_mcontext.fpregs, 0, sizeof (fpregset_t));
}
struct sigcontext *
_hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
int signo, struct hurd_signal_detail *detail,
@ -43,15 +96,38 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
struct
{
int signo;
long int sigcode;
struct sigcontext *scp; /* Points to ctx, below. */
union
{
/* Extra arguments for traditional signal handlers */
struct
{
long int sigcode;
struct sigcontext *scp; /* Points to ctx, below. */
} legacy;
/* Extra arguments for SA_SIGINFO handlers */
struct
{
siginfo_t *siginfop; /* Points to siginfo, below. */
ucontext_t *uctxp; /* Points to uctx, below. */
} posix;
};
void *sigreturn_addr;
void *sigreturn_returns_here;
struct sigcontext *return_scp; /* Same; arg to sigreturn. */
/* NB: sigreturn assumes link is next to ctx. */
struct sigcontext ctx;
struct hurd_userlink link;
ucontext_t ucontext;
siginfo_t siginfo;
} *stackframe;
/* sigaction for preemptors */
static const struct sigaction legacy_sigaction = {
.sa_flags = SA_RESTART
};
if (ss->context)
{
/* We have a previous sigcontext that sigreturn was about
@ -94,9 +170,13 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
the SP on sigreturn. */
state->basic.uesp = state->basic.ecx;
/* XXX what if handler != action->handler (for instance, if a signal
* preemptor took over) ? */
action = & _hurd_sigstate_actions (ss) [signo];
if ( (action->sa_flags & SA_SIGINFO)
&& handler != (__sighandler_t) action->sa_sigaction
|| !(action->sa_flags & SA_SIGINFO)
&& handler != action->sa_handler)
/* A signal preemptor took over, use legacy semantic. */
action = &legacy_sigaction;
if ((action->sa_flags & SA_ONSTACK)
&& !(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK)))
@ -140,15 +220,9 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
= &stackframe->link.thread.next;
ss->active_resources = &stackframe->link;
/* Set up the arguments for the signal handler. */
stackframe->signo = signo;
stackframe->sigcode = detail->code;
stackframe->scp = stackframe->return_scp = scp = &stackframe->ctx;
stackframe->sigreturn_addr = &__sigreturn;
stackframe->sigreturn_returns_here = firewall; /* Crash on return. */
/* Set up the sigcontext from the current state of the thread. */
scp = &stackframe->ctx;
scp->sc_onstack = ss->sigaltstack.ss_flags & SS_ONSTACK ? 1 : 0;
/* struct sigcontext is laid out so that starting at sc_gs mimics a
@ -162,6 +236,35 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
&state->fpu, &scp->sc_i386_float_state,
sizeof (state->fpu));
/* Set up the arguments for the signal handler. */
stackframe->signo = signo;
if (action->sa_flags & SA_SIGINFO)
{
stackframe->posix.siginfop = &stackframe->siginfo;
stackframe->posix.uctxp = &stackframe->ucontext;
fill_siginfo (&stackframe->siginfo, signo, detail, state);
fill_ucontext (&stackframe->ucontext, scp);
}
else
{
if (detail->exc)
{
int nsigno;
_hurd_exception2signal_legacy (detail, &nsigno);
assert (nsigno == signo);
}
else
detail->code = 0;
stackframe->legacy.sigcode = detail->code;
stackframe->legacy.scp = &stackframe->ctx;
}
/* Set up the bottom of the stack. */
stackframe->sigreturn_addr = &__sigreturn;
stackframe->sigreturn_returns_here = firewall; /* Crash on return. */
stackframe->return_scp = &stackframe->ctx;
_hurdsig_end_catch_fault ();
if (! ok)

View File

@ -64,7 +64,7 @@ __kill (pid_t pid, int sig)
{
if (msgport != MACH_PORT_NULL)
/* Send a signal message to his message port. */
return __msg_sig_post (msgport, sig, 0, refport);
return __msg_sig_post (msgport, sig, SI_USER, refport);
/* The process has no message port. Perhaps try direct
frobnication of the task. */

View File

@ -105,7 +105,7 @@ timer_thread (void)
__msg_sig_post_request (_hurd_msgport,
_hurd_itimer_port,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
SIGALRM, 0, __mach_task_self ());
SIGALRM, SI_TIMER, __mach_task_self ());
break;
case MACH_RCV_INTERRUPTED: