aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bits/sigaction.h1
-rw-r--r--hurd/hurd/signal.h5
-rw-r--r--hurd/hurdfault.c2
-rw-r--r--hurd/hurdinit.c2
-rw-r--r--hurd/hurdsig.c6
-rw-r--r--sysdeps/mach/hurd/i386/bits/sigcontext.h4
-rw-r--r--sysdeps/mach/hurd/i386/exc2signal.c122
-rw-r--r--sysdeps/mach/hurd/i386/sigcontextinfo.h5
-rw-r--r--sysdeps/mach/hurd/i386/trampoline.c125
-rw-r--r--sysdeps/mach/hurd/kill.c2
-rw-r--r--sysdeps/mach/hurd/setitimer.c2
11 files changed, 209 insertions, 67 deletions
diff --git a/bits/sigaction.h b/bits/sigaction.h
index afcbd87107..4358dde947 100644
--- a/bits/sigaction.h
+++ b/bits/sigaction.h
@@ -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"). */
diff --git a/hurd/hurd/signal.h b/hurd/hurd/signal.h
index c11f841172..f6f91218db 100644
--- a/hurd/hurd/signal.h
+++ b/hurd/hurd/signal.h
@@ -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
diff --git a/hurd/hurdfault.c b/hurd/hurdfault.c
index fa28347418..6df1016f79 100644
--- a/hurd/hurdfault.c
+++ b/hurd/hurdfault.c
@@ -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;
}
diff --git a/hurd/hurdinit.c b/hurd/hurdinit.c
index 7faa51b352..daa47911c3 100644
--- a/hurd/hurdinit.c
+++ b/hurd/hurdinit.c
@@ -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>
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 2b778d6927..852ae7e441 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -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
diff --git a/sysdeps/mach/hurd/i386/bits/sigcontext.h b/sysdeps/mach/hurd/i386/bits/sigcontext.h
index cc4d5d62ee..28490591c1 100644
--- a/sysdeps/mach/hurd/i386/bits/sigcontext.h
+++ b/sysdeps/mach/hurd/i386/bits/sigcontext.h
@@ -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 */
diff --git a/sysdeps/mach/hurd/i386/exc2signal.c b/sysdeps/mach/hurd/i386/exc2signal.c
index a6fe164957..7a22260b63 100644
--- a/sysdeps/mach/hurd/i386/exc2signal.c
+++ b/sysdeps/mach/hurd/i386/exc2signal.c
@@ -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);
+}
diff --git a/sysdeps/mach/hurd/i386/sigcontextinfo.h b/sysdeps/mach/hurd/i386/sigcontextinfo.h
index 218a436af7..59989e9522 100644
--- a/sysdeps/mach/hurd/i386/sigcontextinfo.h
+++ b/sysdeps/mach/hurd/i386/sigcontextinfo.h
@@ -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
diff --git a/sysdeps/mach/hurd/i386/trampoline.c b/sysdeps/mach/hurd/i386/trampoline.c
index 8c7976919c..4a9cab1332 100644
--- a/sysdeps/mach/hurd/i386/trampoline.c
+++ b/sysdeps/mach/hurd/i386/trampoline.c
@@ -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)
diff --git a/sysdeps/mach/hurd/kill.c b/sysdeps/mach/hurd/kill.c
index deaa8f0da0..286fc3e2e4 100644
--- a/sysdeps/mach/hurd/kill.c
+++ b/sysdeps/mach/hurd/kill.c
@@ -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. */
diff --git a/sysdeps/mach/hurd/setitimer.c b/sysdeps/mach/hurd/setitimer.c
index b16f4ddd5d..a2b6c2aa5d 100644
--- a/sysdeps/mach/hurd/setitimer.c
+++ b/sysdeps/mach/hurd/setitimer.c
@@ -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: