about summary refs log tree commit diff
path: root/sysdeps/mach/hurd/i386/trampoline.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mach/hurd/i386/trampoline.c')
-rw-r--r--sysdeps/mach/hurd/i386/trampoline.c125
1 files changed, 114 insertions, 11 deletions
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)