Back to index

glibc  2.9
trampoline.c
Go to the documentation of this file.
00001 /* Set thread_state for sighandler, and sigcontext to recover.  HPPA version.
00002    Copyright (C) 1995, 1997, 1998, 2005 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <hurd/signal.h>
00021 #include <thread_state.h>
00022 #include <assert.h>
00023 #include <errno.h>
00024 #include "hurdfault.h"
00025 
00026 
00027 struct mach_msg_trap_regargs
00028   {
00029     /* These first four arguments are in registers 26..23.  */
00030     mach_msg_size_t rcv_size;      /* arg3 */
00031     mach_msg_size_t send_size;     /* arg2 */
00032     mach_msg_option_t option;      /* arg1 */
00033     mach_msg_header_t *msg; /* arg0 */
00034   };
00035 
00036 struct sigcontext *
00037 _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
00038                      int signo, long int sigcode,
00039                      volatile int rpc_wait,
00040                      struct machine_thread_all_state *state)
00041 {
00042   __label__ trampoline, rpc_wait_trampoline;
00043   void *volatile sigsp;
00044   struct sigcontext *scp;
00045 
00046   if (ss->context)
00047     {
00048       /* We have a previous sigcontext that sigreturn was about
00049         to restore when another signal arrived.  We will just base
00050         our setup on that.  */
00051       if (_hurdsig_catch_fault (SIGSEGV))
00052        assert (_hurdsig_fault_sigcode >= (long int) ss->context &&
00053               _hurdsig_fault_sigcode < (long int) (ss->context + 1));
00054       else
00055        {
00056          memcpy (&state->basic, &ss->context->sc_parisc_thread_state,
00057                 sizeof (state->basic));
00058          state->set = (1 << PARISC_THREAD_STATE);
00059          assert (! rpc_wait);
00060          /* The intr_port slot was cleared before sigreturn sent us the
00061             sig_post that made us notice this pending signal, so
00062             _hurd_internal_post_signal wouldn't do interrupt_operation.
00063             After we return, our caller will set SCP->sc_intr_port (in the
00064             new context) from SS->intr_port and clear SS->intr_port.  Now
00065             that we are restoring this old context recorded by sigreturn,
00066             we want to restore its intr_port too; so store it in
00067             SS->intr_port now, so it will end up in SCP->sc_intr_port
00068             later.  */
00069          ss->intr_port = ss->context->sc_intr_port;
00070        }
00071       /* If the sigreturn context was bogus, just ignore it.  */
00072       ss->context = NULL;
00073     }
00074   else if (! machine_get_basic_state (ss->thread, state))
00075     return NULL;
00076 
00077   if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
00078       !(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK)))
00079     {
00080       sigsp = ss->sigaltstack.ss_sp + ss->sigaltstack.ss_size;
00081       ss->sigaltstack.ss_flags |= SS_ONSTACK;
00082       /* XXX need to set up base of new stack for
00083         per-thread variables, cthreads.  */
00084     }
00085   else
00086     sigsp = (char *) state->basic.uesp;
00087 
00088   /* Push the signal context on the stack.  */
00089   sigsp -= sizeof (*scp);
00090   scp = sigsp;
00091 
00092   if (_hurdsig_catch_fault (SIGSEGV))
00093     {
00094       assert (_hurdsig_fault_sigcode >= (long int) scp &&
00095              _hurdsig_fault_sigcode <= (long int) (scp + 1));
00096       /* We got a fault trying to write the stack frame.
00097         We cannot set up the signal handler.
00098         Returning NULL tells our caller, who will nuke us with a SIGILL.  */
00099       return NULL;
00100     }
00101   else
00102     {
00103       int ok;
00104 
00105       /* Set up the sigcontext from the current state of the thread.  */
00106 
00107       scp->sc_onstack = ss->sigaltstack.ss_flags & SS_ONSTACK ? 1 : 0;
00108 
00109       /* struct sigcontext is laid out so that starting at sc_regs mimics a
00110         struct parisc_thread_state.  */
00111       memcpy (&scp->sc_parisc_thread_state,
00112              &state->basic, sizeof (state->basic));
00113 
00114       _hurdsig_end_catch_fault ();
00115 
00116       if (! ok)
00117        return NULL;
00118     }
00119 
00120   /* Modify the thread state to call the trampoline code on the new stack.  */
00121   if (rpc_wait)
00122     {
00123       /* The signalee thread was blocked in a mach_msg_trap system call,
00124         still waiting for a reply.  We will have it run the special
00125         trampoline code which retries the message receive before running
00126         the signal handler.
00127 
00128         To do this we change the OPTION argument on its stack to enable only
00129         message reception, since the request message has already been
00130         sent.  */
00131 
00132       struct mach_msg_trap_regargs *args = (void *) &state->basic.r23;
00133 
00134       if (_hurdsig_catch_fault (SIGSEGV))
00135        {
00136          assert (_hurdsig_fault_sigcode >= (long int) args &&
00137                 _hurdsig_fault_sigcode < (long int) (args + 1));
00138          /* Faulted accessing ARGS.  Bomb.  */
00139          return NULL;
00140        }
00141 
00142       assert (args->option & MACH_RCV_MSG);
00143       /* Disable the message-send, since it has already completed.  The
00144         calls we retry need only wait to receive the reply message.  */
00145       args->option &= ~MACH_SEND_MSG;
00146 
00147       /* Limit the time to receive the reply message, in case the server
00148         claimed that `interrupt_operation' succeeded but in fact the RPC
00149         is hung.  */
00150       args->option |= MACH_RCV_TIMEOUT;
00151       args->timeout = _hurd_interrupted_rpc_timeout;
00152 
00153       _hurdsig_end_catch_fault ();
00154 
00155       MACHINE_THREAD_STATE_SET_PC (&state->basic, &&rpc_wait_trampoline);
00156       /* The reply-receiving trampoline code runs initially on the original
00157         user stack.  We pass it the signal stack pointer in %r5.  */
00158       state->basic.r5 = (int) sigsp;
00159       /* After doing the message receive, the trampoline code will need to
00160         update the %r28 value to be restored by sigreturn.  To simplify
00161         the assembly code, we pass the address of its slot in SCP to the
00162         trampoline code in %r4.  */
00163       state->basic.r4 = (unsigned int) &scp->sc_regs[27];
00164       /* Set up the arguments for the handler function in callee-saved
00165         registers that we will move to the argument registers after
00166         mach_msg_trap returns.  */
00167       state->basic.r6 = signo;
00168       state->basic.r7 = sigcode;
00169       state->basic.r8 = (unsigned int) scp;
00170     }
00171   else
00172     {
00173       MACHINE_THREAD_STATE_SET_PC (&state->basic, &&trampoline);
00174       state->basic.r20 = (unsigned int) sigsp;
00175       /* Set up the arguments for the handler function.  */
00176       state->basic.r26 = signo;
00177       state->basic.r25 = sigcode;
00178       state->basic.r24 = (unsigned int) scp;
00179     }
00180 
00181   /* We pass the handler function to the trampoline code in %r9.  */
00182   state->basic.r9 = (unsigned int) handler;
00183   /* For convenience, we pass the address of __sigreturn in %r10.  */
00184   state->basic.r10 = (unsigned int) &__sigreturn;
00185   /* The extra copy of SCP for the __sigreturn arg goes in %r8.  */
00186   state->basic.r10 = (unsigned int) scp;
00187 
00188   return scp;
00189 
00190   /* The trampoline code follows.  This is not actually executed as part of
00191      this function, it is just convenient to write it that way.  */
00192 
00193  rpc_wait_trampoline:
00194   /* This is the entry point when we have an RPC reply message to receive
00195      before running the handler.  The MACH_MSG_SEND bit has already been
00196      cleared in the OPTION argument on our stack.  The interrupted user
00197      stack pointer has not been changed, so the system call can find its
00198      arguments; the signal stack pointer is in %ebx.  For our convenience,
00199      %ecx points to the sc_eax member of the sigcontext.  */
00200   asm volatile
00201     (/* Retry the interrupted mach_msg system call.  */
00202      "ldil L%0xC0000000,%r1\nble 4(%sr7,%r1)\n"
00203      "ldi -25, %r22\n"             /* mach_msg_trap */
00204      /* When the sigcontext was saved, %r28 was MACH_RCV_INTERRUPTED.  But
00205        now the message receive has completed and the original caller of
00206        the RPC (i.e. the code running when the signal arrived) needs to
00207        see the final return value of the message receive in %r28.  So
00208        store the new %r28 value into the sc_regs[27] member of the sigcontext
00209        (whose address is in %r4 to make this code simpler).  */
00210      "stw (%r4), %r28\n"
00211      /* Switch to the signal stack.  */
00212      "copy %r5, %r30\n"
00213      /* Copy the handler arguments to the argument registers.  */
00214      "copy %r6, %r26\n"
00215      "copy %r7, %r25\n"
00216      "copy %r8, %r24\n"
00217      );
00218 
00219  trampoline:
00220   /* Entry point for running the handler normally.  The arguments to the
00221      handler function are already in the argument registers.  */
00222   asm volatile
00223     ("bv (%r9); nop"        /* Call the handler function.  */
00224      "bv (%r10)\n"          /* Call __sigreturn (SCP); never returns.  */
00225      "copy %r8, %r26"              /* Set up arg in delay slot.  */
00226      : : "i" (&__sigreturn));
00227 
00228   /* NOTREACHED */
00229   return NULL;
00230 }