Back to index

glibc  2.9
trampoline.c File Reference
#include <hurd/signal.h>
#include <hurd/userlink.h>
#include <thread_state.h>
#include <assert.h>
#include <errno.h>
#include "hurdfault.h"
#include <intr-msg.h>

Go to the source code of this file.


struct sigcontext_hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler, int signo, struct hurd_signal_detail *detail, volatile int rpc_wait, struct machine_thread_all_state *state)
 asm ("trampoline_load_registers:\n""lwz 17,68(3)\n""lwz 4,16(3)\n""lwz 5,20(3)\n""lwz 6,24(3)\n""lwz 7,28(3)\n""lwz 8,32(3)\n""lwz 9,36(3)\n""lwz 10,40(3)\n""lwz 11,44(3)\n""lwz 12,48(3)\n""lwz 13,52(3)\n""lwz 14,56(3)\n""lwz 15,60(3)\n""lwz 16,64(3)\n""mr 3,17\n""blr\n")
 asm ("rpc_wait_trampoline:\n")
 asm ("bl trampoline_load_registers\n""li 0, -25\n""sc\n""stw 3, 0(10)\n""mr 3,11\n""mr 4,12\n""mr 5,13\n")
 asm ("trampoline:\n")
 asm ("bl trampoline_load_registers\n""bctrl\n""mtctr 15\n""mr 3,16\n""bctr\n")

Function Documentation

struct sigcontext* _hurd_setup_sighandler ( struct hurd_sigstate ss,
__sighandler_t  handler,
int  signo,
struct hurd_signal_detail detail,
volatile int  rpc_wait,
struct machine_thread_all_state state 
) [read]

Definition at line 30 of file trampoline.c.

  void trampoline (void);
  void rpc_wait_trampoline (void);
  void *volatile sigsp;
  struct sigcontext *scp;

  if (ss->context)
      /* We have a previous sigcontext that sigreturn was about
        to restore when another signal arrived.  We will just base
        our setup on that.  */
      if (! _hurdsig_catch_memory_fault (ss->context))
         memcpy (&state->basic, &ss->context->sc_ppc_thread_state,
                sizeof (state->basic));
         memcpy (&state->exc, &ss->context->sc_ppc_exc_state,
                sizeof (state->exc));
         memcpy (&state->fpu, &ss->context->sc_ppc_float_state,
                sizeof (state->fpu));
         state->set = (1 << PPC_THREAD_STATE) | (1 << PPC_EXCEPTION_STATE)
           | (1 << PPC_FLOAT_STATE);

  if (! machine_get_basic_state (ss->thread, state))
    return NULL;

  if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
      !(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK)))
      sigsp = ss->sigaltstack.ss_sp + ss->sigaltstack.ss_size;
      ss->sigaltstack.ss_flags |= SS_ONSTACK;
      /* XXX need to set up base of new stack for
        per-thread variables, cthreads.  */
    sigsp = (char *) state->basic.SP;

  /* Set up the sigcontext structure on the stack.  This is all the stack
     needs, since the args are passed in registers (below).  */
  sigsp -= sizeof (*scp);
  scp = sigsp;
  sigsp -= 16;  /* Reserve some space for a stack frame.  */

  if (_hurdsig_catch_memory_fault (scp))
      /* We got a fault trying to write the stack frame.
        We cannot set up the signal handler.
        Returning NULL tells our caller, who will nuke us with a SIGILL.  */
      return NULL;
      int ok;

      /* Set up the sigcontext from the current state of the thread.  */

      scp->sc_onstack = ss->sigaltstack.ss_flags & SS_ONSTACK ? 1 : 0;

      /* struct sigcontext is laid out so that starting at sc_srr0
        mimics a struct ppc_thread_state.  */
      memcpy (&scp->sc_ppc_thread_state,
             &state->basic, sizeof (state->basic));

      /* struct sigcontext is laid out so that starting at sc_dar
        mimics a struct ppc_exc_state.  */
      ok = machine_get_state (ss->thread, state, PPC_EXCEPTION_STATE,
                            &state->exc, &scp->sc_ppc_exc_state,
                            sizeof (state->exc));

      /* struct sigcontext is laid out so that starting at sc_fprs[0]
        mimics a struct ppc_float_state.  */
      if (ok)
       ok = machine_get_state (ss->thread, state, PPC_FLOAT_STATE,
                            &state->fpu, &scp->sc_ppc_float_state,
                            sizeof (state->fpu));

      _hurdsig_end_catch_fault ();

      if (!ok)
       return NULL;

  /* Modify the thread state to call the trampoline code on the new stack.  */
  if (rpc_wait)
      /* The signalee thread was blocked in a mach_msg_trap system call,
        still waiting for a reply.  We will have it run the special
        trampoline code which retries the message receive before running
        the signal handler.

        To do this we change the OPTION argument in its registers to
        enable only message reception, since the request message has
        already been sent.  */

      /* The system call arguments are stored in consecutive registers
        starting with r3.  */
      struct mach_msg_trap_args *args = (void *) &state->basic.r3;

      if (_hurdsig_catch_memory_fault (args))
         /* Faulted accessing ARGS.  Bomb.  */
         return NULL;

      assert (args->option & MACH_RCV_MSG);
      /* Disable the message-send, since it has already completed.  The
        calls we retry need only wait to receive the reply message.  */
      args->option &= ~MACH_SEND_MSG;

      /* Limit the time to receive the reply message, in case the server
        claimed that `interrupt_operation' succeeded but in fact the RPC
        is hung.  */
      args->option |= MACH_RCV_TIMEOUT;
      args->timeout = _hurd_interrupted_rpc_timeout;

      _hurdsig_end_catch_fault ();

      state->basic.PC = (int) rpc_wait_trampoline;
      /* After doing the message receive, the trampoline code will need to
        update the r3 value to be restored by sigreturn.  To simplify
        the assembly code, we pass the address of its slot in SCP to the
        trampoline code in r10.  */
      state->basic.r10 = (long int) &scp->sc_gprs[3];
      /* We must preserve the mach_msg_trap args in r3..r9.
        Pass the handler args to the trampoline code in r11..r13.  */
      state->basic.r11 = signo;
      state->basic.r12 = detail->code;
      state->basic.r13 = (int) scp;
      state->basic.PC = (int) trampoline;
      state->basic.r3 = signo;
      state->basic.r4 = detail->code;
      state->basic.r5 = (int) scp;

  state->basic.r1 = (int) sigsp;  /* r1 is the stack pointer.  */

  /* We pass the handler function to the trampoline code in ctr.  */
  state->basic.ctr = (int) handler;
  /* In r15, we store the address of __sigreturn itself,
     for the trampoline code to use.  */
  state->basic.r15 = (int) &__sigreturn;
  /* In r16, we save the SCP value to pass to __sigreturn
     after the handler returns.  */
  state->basic.r16 = (int) scp;

  /* In r3, we store a pointer to the registers in STATE so that the
     trampoline code can load the registers from that.  For some reason,
     thread_set_state doesn't set all registers.  */
  state->basic.r17 = state->basic.r3;  /* Store the real r3 in r17.  */
  state->basic.r3 = (int) &state->basic.r0;

  return scp;

Here is the call graph for this function:

Here is the caller graph for this function:

asm ( "trampoline_load_registers:\n""lwz  17,
68(3)\n""lwz  4,
16(3)\n""lwz  5,
20(3)\n""lwz  6,
24(3)\n""lwz  7,
28(3)\n""lwz  8,
32(3)\n""lwz  9,
36(3)\n""lwz  10,
40(3)\n""lwz  11,
44(3)\n""lwz  12,
48(3)\n""lwz  13,
52(3)\n""lwz  14,
56(3)\n""lwz  15,
60(3)\n""lwz  16,
64(3)\n""mr  3,
asm ( "rpc_wait_trampoline:\n"  )
asm ( "bl trampoline_load_registers\n""li  0,
-25\n""sc\n""stw  3,
0(10)\n""mr  3,
11\n""mr  4,
12\n""mr  5,
asm ( "trampoline:\n"  )
asm ( "bl trampoline_load_registers\n""bctrl\n""mtctr 15\n""mr  3,