]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
A first cut at amd64 signal frame build/unbuild, from Tom Hughes.
authorJulian Seward <jseward@acm.org>
Thu, 24 Mar 2005 17:48:02 +0000 (17:48 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 24 Mar 2005 17:48:02 +0000 (17:48 +0000)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3424

coregrind/amd64/helpers.S
coregrind/amd64/signals.c

index 4543e23f1f0934d63524616722d415d62d413ea1..fa1d63d7b79f6fbcc78e62a21c382605109c94e2 100644 (file)
 */
 .global VG_(trampoline_code_start)
 .global VG_(trampoline_code_length)
-.global VG_(tramp_sigreturn_offset)
+.global VG_(tramp_rt_sigreturn_offset)
 .global VG_(tramp_syscall_offset)
        
 VG_(trampoline_code_start):
-sigreturn_start:
-        /* This is a very specific sequence which GDB uses to
-           recognize signal handler frames. */
-        popq    %rax
-        movq    $__NR_rt_sigreturn, %rax
-        syscall
-        ud2
-
 rt_sigreturn_start:
         /* Likewise for rt signal frames */
         movq    $__NR_rt_sigreturn, %rax
@@ -71,8 +63,8 @@ tramp_code_end:
 .data
 VG_(trampoline_code_length):
        .long tramp_code_end - VG_(trampoline_code_start)
-VG_(tramp_sigreturn_offset):
-       .long sigreturn_start - VG_(trampoline_code_start)
+VG_(tramp_rt_sigreturn_offset):
+       .long rt_sigreturn_start - VG_(trampoline_code_start)
 VG_(tramp_syscall_offset):
        .long syscall_start - VG_(trampoline_code_start)
 .text
index 012434ff9a90fba9de0ef522a35f64efe95625a2..0d1f584c386730b37f37f9aa19223bf9ea93dca9 100644 (file)
 
 #include "libvex_guest_amd64.h"
 
+
+/* This module creates and removes signal frames for signal deliveries
+   on amd64-linux.
+
+   FIXME: Note that this file is in the wrong place.  It is marked as
+   amd64 specific, but in fact it is specific to both amd64 and linux.
+   There is nothing that ensures that (eg) amd64-netbsd will have the
+   same signal frame layout as Linux.
+
+   Note also, this file contains kernel-specific knowledge in the
+   form of 'struct rt_sigframe'.  How does that relate to the vki
+   kernel interface stuff?
+
+   A 'struct rtsigframe' is pushed onto the client's stack.  This
+   contains a subsidiary vki_ucontext.  That holds the vcpu's state
+   across the signal, so that the sighandler can mess with the vcpu
+   state if it really wants.
+
+   FIXME: sigcontexting is basically broken for the moment.  When
+   delivering a signal, the integer registers and %rflags are
+   correctly written into the sigcontext, however the FP and SSE state
+   is not.  When returning from a signal, only the integer registers
+   are restored from the sigcontext; the rest of the CPU state is
+   restored to what it was before the signal.
+
+   This will be fixed.
+*/
+
+
 /*------------------------------------------------------------*/
-/*--- Signal frame                                         ---*/
+/*--- Signal frame layouts                                 ---*/
 /*------------------------------------------------------------*/
 
 // A structure in which to save the application's registers
 // during the execution of signal handlers.
 
-#if 0
-typedef
-   struct {
-      /* There are two different stack frame formats, depending on
-        whether the client set the SA_SIGINFO flag for the handler.
-        This structure is put onto the client's stack as part of
-        signal delivery, and therefore appears as the signal
-        handler's arguments.
-
-        The first two words are common for both frame formats -
-        they're the return address and the signal number. */
-
-      /* Sig handler's (bogus) return address */
-      Addr retaddr;
-      /* The arg to the sig handler.  We need to inspect this after
-         the handler returns, but it's unreasonable to assume that the
-         handler won't change it.  So we keep a second copy of it in
-         sigNo_private. */
-      Int  sigNo;
-
-      /* This is where the two frames start differing. */
-      union {
-        struct {               /* set SA_SIGINFO */
-           /* ptr to siginfo_t. */
-           Addr psigInfo;
-
-           /* ptr to ucontext */
-           Addr puContext;
-        } sigInfo;
-        struct vki_sigcontext sigContext; /* did not set SA_SIGINFO */
-      } handlerArgs;
-
-      /* The rest are private fields which the handler is unaware of. */
-
-      /* Sanity check word. */
-      UInt magicPI;
-      /* pointed to by psigInfo */
-      vki_siginfo_t sigInfo;
-      /* pointed to by puContext */
-      struct vki_ucontext uContext;
-
-      /* Safely-saved version of sigNo, as described above. */
-      Int  sigNo_private;
-
-      /* Saved processor state. */
-      VexGuestX86State vex;
-      VexGuestX86State vex_shadow;
-
-      /* saved signal mask to be restored when handler returns */
-      vki_sigset_t     mask;
-
-      /* Scheduler-private stuff: what was the thread's status prior to
-         delivering this signal? */
-      ThreadStatus status;
-      void* /*pthread_mutex_t* */ associated_mx;
-      void* /*pthread_cond_t* */ associated_cv;
-
-      /* Sanity check word.  Is the highest-addressed word; do not
-         move!*/
-      UInt magicE;
-   }
-   VgSigFrame;
-#endif
+// In theory, so long as we get the arguments to the handler function
+// right, it doesn't matter what the exact layout of the rest of the
+// frame is.  Unfortunately, things like gcc's exception unwinding
+// make assumptions about the locations of various parts of the frame,
+// so we need to duplicate it exactly.
+
+/* Valgrind-specific parts of the signal frame */
+struct vg_sigframe
+{
+   /* Sanity check word. */
+   UInt magicPI;
+
+   UInt handlerflags;  /* flags for signal handler */
+
+
+   /* Safely-saved version of sigNo, as described above. */
+   Int  sigNo_private;
+
+   /* XXX This is wrong.  Surely we should store the shadow values
+      into the shadow memory behind the actual values? */
+   VexGuestAMD64State vex_shadow;
+
+   /* HACK ALERT */
+   VexGuestAMD64State vex;
+   /* end HACK ALERT */
+
+   /* saved signal mask to be restored when handler returns */
+   vki_sigset_t        mask;
+
+   /* Sanity check word.  Is the highest-addressed word; do not
+      move!*/
+   UInt magicE;
+};
+
+struct rt_sigframe
+{
+   /* Sig handler's return address */
+   Addr retaddr;
+
+   /* ucontext */
+   struct vki_ucontext uContext;
+
+   /* siginfo */
+   vki_siginfo_t sigInfo;
+   struct _vki_fpstate fpstate;
+
+   struct vg_sigframe vg;
+};
+
+
+//:: /*------------------------------------------------------------*/
+//:: /*--- Signal operations                                    ---*/
+//:: /*------------------------------------------------------------*/
+//:: 
+//:: /* 
+//::    Great gobs of FP state conversion taken wholesale from
+//::    linux/arch/i386/kernel/i387.c
+//::  */
+//:: 
+//:: /*
+//::  * FXSR floating point environment conversions.
+//::  */
+//:: #define X86_FXSR_MAGIC            0x0000
+//:: 
+//:: /*
+//::  * FPU tag word conversions.
+//::  */
+//:: 
+//:: static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
+//:: {
+//::    unsigned int tmp; /* to avoid 16 bit prefixes in the code */
+//::  
+//::    /* Transform each pair of bits into 01 (valid) or 00 (empty) */
+//::    tmp = ~twd;
+//::    tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
+//::    /* and move the valid bits to the lower byte. */
+//::    tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
+//::    tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
+//::    tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
+//::    return tmp;
+//:: }
+//:: 
+//:: static unsigned long twd_fxsr_to_i387( const struct i387_fxsave_struct *fxsave )
+//:: {
+//::    struct _vki_fpxreg *st = NULL;
+//::    unsigned long twd = (unsigned long) fxsave->twd;
+//::    unsigned long tag;
+//::    unsigned long ret = 0xffff0000u;
+//::    int i;
+//:: 
+//:: #define FPREG_ADDR(f, n)  ((char *)&(f)->st_space + (n) * 16);
+//:: 
+//::    for ( i = 0 ; i < 8 ; i++ ) {
+//::       if ( twd & 0x1 ) {
+//::    st = (struct _vki_fpxreg *) FPREG_ADDR( fxsave, i );
+//:: 
+//::    switch ( st->exponent & 0x7fff ) {
+//::    case 0x7fff:
+//::       tag = 2;            /* Special */
+//::       break;
+//::    case 0x0000:
+//::       if ( !st->significand[0] &&
+//::            !st->significand[1] &&
+//::            !st->significand[2] &&
+//::            !st->significand[3] ) {
+//::          tag = 1; /* Zero */
+//::       } else {
+//::          tag = 2; /* Special */
+//::       }
+//::       break;
+//::    default:
+//::       if ( st->significand[3] & 0x8000 ) {
+//::          tag = 0; /* Valid */
+//::       } else {
+//::          tag = 2; /* Special */
+//::       }
+//::       break;
+//::    }
+//::       } else {
+//::    tag = 3;                       /* Empty */
+//::       }
+//::       ret |= (tag << (2 * i));
+//::       twd = twd >> 1;
+//::    }
+//::    return ret;
+//:: }
+//:: 
+//:: static void convert_fxsr_to_user( struct _vki_fpstate *buf,
+//::                             const struct i387_fxsave_struct *fxsave )
+//:: {
+//::    unsigned long env[7];
+//::    struct _vki_fpreg *to;
+//::    struct _vki_fpxreg *from;
+//::    int i;
+//:: 
+//::    env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul;
+//::    env[1] = (unsigned long)fxsave->swd | 0xffff0000ul;
+//::    env[2] = twd_fxsr_to_i387(fxsave);
+//::    env[3] = fxsave->fip;
+//::    env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
+//::    env[5] = fxsave->foo;
+//::    env[6] = fxsave->fos;
+//::    
+//::    VG_(memcpy)(buf, env, 7 * sizeof(unsigned long));
+//:: 
+//::    to = &buf->_st[0];
+//::    from = (struct _vki_fpxreg *) &fxsave->st_space[0];
+//::    for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+//::       unsigned long __user *t = (unsigned long __user *)to;
+//::       unsigned long *f = (unsigned long *)from;
+//:: 
+//::       t[0] = f[0];
+//::       t[1] = f[1];
+//::       to->exponent = from->exponent;
+//::    }
+//:: }
+//:: 
+//:: static void convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
+//::                               const struct _vki_fpstate *buf )
+//:: {
+//::    unsigned long env[7];
+//::    struct _vki_fpxreg *to;
+//::    const struct _vki_fpreg *from;
+//::    int i;
+//::   
+//::    VG_(memcpy)(env, buf, 7 * sizeof(long));
+//:: 
+//::    fxsave->cwd = (unsigned short)(env[0] & 0xffff);
+//::    fxsave->swd = (unsigned short)(env[1] & 0xffff);
+//::    fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
+//::    fxsave->fip = env[3];
+//::    fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16);
+//::    fxsave->fcs = (env[4] & 0xffff);
+//::    fxsave->foo = env[5];
+//::    fxsave->fos = env[6];
+//:: 
+//::    to = (struct _vki_fpxreg *) &fxsave->st_space[0];
+//::    from = &buf->_st[0];
+//::    for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+//::       unsigned long *t = (unsigned long *)to;
+//::       unsigned long __user *f = (unsigned long __user *)from;
+//:: 
+//::       t[0] = f[0];
+//::       t[1] = f[1];
+//::       to->exponent = from->exponent;
+//::    }
+//:: }
+//:: 
+//:: static inline void save_i387_fsave( arch_thread_t *regs, struct _vki_fpstate *buf )
+//:: {
+//::    struct i387_fsave_struct *fs = &regs->m_sse.fsave;
+//:: 
+//::    fs->status = fs->swd;
+//::    VG_(memcpy)(buf, fs, sizeof(*fs));
+//:: }
+//:: 
+//:: static void save_i387_fxsave( arch_thread_t *regs, struct _vki_fpstate *buf )
+//:: {
+//::    const struct i387_fxsave_struct *fx = &regs->m_sse.fxsave;
+//::    convert_fxsr_to_user( buf, fx );
+//:: 
+//::    buf->status = fx->swd;
+//::    buf->magic = X86_FXSR_MAGIC;
+//::    VG_(memcpy)(buf->_fxsr_env, fx, sizeof(struct i387_fxsave_struct));
+//:: }
+//:: 
+//:: static void save_i387( arch_thread_t *regs, struct _vki_fpstate *buf )
+//:: {
+//::    if ( VG_(have_ssestate) )
+//::       save_i387_fxsave( regs, buf );
+//::    else
+//::       save_i387_fsave( regs, buf );
+//:: }
+//:: 
+//:: static inline void restore_i387_fsave( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
+//:: {
+//::    VG_(memcpy)( &regs->m_sse.fsave, buf, sizeof(struct i387_fsave_struct) );
+//:: }
+//:: 
+//:: static void restore_i387_fxsave( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
+//:: {
+//::    VG_(memcpy)(&regs->m_sse.fxsave, &buf->_fxsr_env[0], 
+//::          sizeof(struct i387_fxsave_struct) );
+//::    /* mxcsr reserved bits must be masked to zero for security reasons */
+//::    regs->m_sse.fxsave.mxcsr &= 0xffbf;
+//::    convert_fxsr_from_user( &regs->m_sse.fxsave, buf );
+//:: }
+//:: 
+//:: static void restore_i387( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
+//:: {
+//::    if ( VG_(have_ssestate) ) {
+//::       restore_i387_fxsave( regs, buf );
+//::    } else {
+//::       restore_i387_fsave( regs, buf );
+//::    }
+//:: }
+
 
 /*------------------------------------------------------------*/
-/*--- Signal operations                                    ---*/
+/*--- Creating signal frames                               ---*/
 /*------------------------------------------------------------*/
 
-#if 0
-/* Make up a plausible-looking thread state from the thread's current state */
-static void synth_ucontext(ThreadId tid, const vki_siginfo_t *si, 
-                          const vki_sigset_t *set, struct vki_ucontext *uc)
+/* Create a plausible-looking sigcontext from the thread's
+   Vex guest state.  NOTE: does not fill in the FP or SSE
+   bits of sigcontext at the moment.
+*/
+static 
+void synth_ucontext(ThreadId tid, const vki_siginfo_t *si, 
+                    const vki_sigset_t *set, 
+                    struct vki_ucontext *uc, struct _vki_fpstate *fpstate)
 {
    ThreadState *tst = VG_(get_ThreadState)(tid);
    struct vki_sigcontext *sc = &uc->uc_mcontext;
@@ -121,193 +328,348 @@ static void synth_ucontext(ThreadId tid, const vki_siginfo_t *si,
    uc->uc_link = 0;
    uc->uc_sigmask = *set;
    uc->uc_stack = tst->altstack;
-
-#define SC2(reg,REG)  sc->reg = tst->arch.vex.guest_##REG
-   SC2(gs,GS);
-   SC2(fs,FS);
-   SC2(es,ES);
-   SC2(ds,DS);
-
-   SC2(edi,EDI);
-   SC2(esi,ESI);
-   SC2(ebp,EBP);
-   SC2(esp,ESP);
-   SC2(ebx,EBX);
-   SC2(edx,EDX);
-   SC2(ecx,ECX);
-   SC2(eax,EAX);
-
-   SC2(eip,EIP);
-   SC2(cs,CS);
-   sc->eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
-   SC2(ss,SS);
-   /* XXX esp_at_signal */
-   /* XXX trapno */
+   sc->fpstate = fpstate;
+
+   // FIXME: save_i387(&tst->arch, fpstate);
+
+#  define SC2(reg,REG)  sc->reg = tst->arch.vex.guest_##REG
+   SC2(r8,R8);
+   SC2(r9,R9);
+   SC2(r10,R10);
+   SC2(r11,R11);
+   SC2(r12,R12);
+   SC2(r13,R13);
+   SC2(r14,R14);
+   SC2(r15,R15);
+   SC2(rdi,RDI);
+   SC2(rsi,RSI);
+   SC2(rbp,RBP);
+   SC2(rbx,RBX);
+   SC2(rdx,RDX);
+   SC2(rax,RAX);
+   SC2(rcx,RCX);
+   SC2(rsp,RSP);
+
+   SC2(rip,RIP);
+   sc->eflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex);
+   // FIXME: SC2(cs,CS);
+   // FIXME: SC2(gs,GS);
+   // FIXME: SC2(fs,FS);
    /* XXX err */
-#undef SC2
+   /* XXX trapno */
+#  undef SC2
 
-   sc->cr2 = (UInt)si->_sifields._sigfault._addr;
+   sc->cr2 = (UWord)si->_sifields._sigfault._addr;
 }
 
-#define SET_SIGNAL_ESP(zztid, zzval) \
+
+#define SET_SIGNAL_RSP(zztid, zzval) \
    SET_THREAD_REG(zztid, zzval, STACK_PTR, post_reg_write, \
                   Vg_CoreSignal, zztid, O_STACK_PTR, sizeof(Addr))
-#endif
 
-void VGA_(push_signal_frame)(ThreadId tid, Addr esp_top_of_frame,
-                             const vki_siginfo_t *siginfo,
-                             void *handler, UInt flags,
-                             const vki_sigset_t *mask,
-                             void* restorer)
-{
-   I_die_here;
-#if 0
-   Addr                esp;
-   ThreadState* tst;
-   VgSigFrame*  frame;
-   Int         sigNo = siginfo->si_signo;
 
-   esp = esp_top_of_frame;
-   esp -= sizeof(VgSigFrame);
-   frame = (VgSigFrame*)esp;
+/* Extend the stack segment downwards if needed so as to ensure the
+   new signal frames are mapped to something.  Return a Bool
+   indicating whether or not the operation was successful.
+*/
+static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
+{
+   ThreadId tid = tst->tid;
+   Segment *stackseg = NULL;
+
+   if (VG_(extend_stack)(addr, tst->stack_size)) {
+      stackseg = VG_(find_segment)(addr);
+      if (0 && stackseg)
+        VG_(printf)("frame=%p seg=%p-%p\n",
+                    addr, stackseg->addr, stackseg->addr+stackseg->len);
+   }
 
-   tst = & VG_(threads)[tid];
+   if (stackseg == NULL 
+       || (stackseg->prot & (VKI_PROT_READ|VKI_PROT_WRITE)) == 0) {
+      VG_(message)(
+         Vg_UserMsg,
+         "Can't extend stack to %p during signal delivery for thread %d:",
+         addr, tid);
+      if (stackseg == NULL)
+         VG_(message)(Vg_UserMsg, "  no stack segment");
+      else
+         VG_(message)(Vg_UserMsg, "  too small or bad protection modes");
+
+      /* set SIGSEGV to default handler */
+      VG_(set_default_handler)(VKI_SIGSEGV);
+      VG_(synth_fault_mapping)(tid, addr);
+
+      /* The whole process should be about to die, since the default
+        action of SIGSEGV to kill the whole process. */
+      return False;
+   }
 
    /* For tracking memory events, indicate the entire frame has been
-    * allocated, but pretend that only the first four words are written */
-   VG_TRACK( new_mem_stack_signal, (Addr)frame, sizeof(VgSigFrame) );
-
-   /* Assert that the frame is placed correctly. */
-   vg_assert( (sizeof(VgSigFrame) & 0x3) == 0 );
-   vg_assert( ((Char*)(&frame->magicE)) + sizeof(UInt) 
-              == ((Char*)(esp_top_of_frame)) );
-
-   /* retaddr, sigNo, psigInfo, puContext fields are to be written */
-   VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame", 
-                            (Addr)frame, offsetof(VgSigFrame, handlerArgs) );
-   frame->retaddr    = (UInt)VG_(client_trampoline_code)+VG_(tramp_sigreturn_offset);
-   frame->sigNo      = sigNo;
+      allocated. */
+   VG_TRACK( new_mem_stack_signal, addr, size );
+
+   return True;
+}
+
+
+/* Build the Valgrind-specific part of a signal frame. */
+
+static void build_vg_sigframe(struct vg_sigframe *frame,
+                             ThreadState *tst,
+                             const vki_sigset_t *mask,
+                             UInt flags,
+                             Int sigNo)
+{
    frame->sigNo_private = sigNo;
-   VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
-             (Addr)frame, offsetof(VgSigFrame, handlerArgs) );
-
-   if (flags & VKI_SA_SIGINFO) {
-      /* if the client asked for a siginfo delivery, then build the stack that way */
-      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)", 
-               (Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigInfo) );
-      frame->handlerArgs.sigInfo.psigInfo   = (Addr)&frame->sigInfo;
-      frame->handlerArgs.sigInfo.puContext = (Addr)&frame->uContext;
-      VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
-                (Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigInfo) );
-
-      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)", 
-               (Addr)&frame->sigInfo, sizeof(frame->sigInfo) );
-      VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t));
-      VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 
-                (Addr)&frame->sigInfo, sizeof(frame->sigInfo) );
-
-      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)", 
-               (Addr)&frame->uContext, sizeof(frame->uContext) );
-      synth_ucontext(tid, siginfo, mask, &frame->uContext);
-      VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 
-                (Addr)&frame->uContext, sizeof(frame->uContext) );
-   } else {
-      struct vki_ucontext uc;
-
-      /* otherwise just put the sigcontext there */
-
-      synth_ucontext(tid, siginfo, mask, &uc);
-
-      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (sigcontext)", 
-               (Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigContext) );
-      VG_(memcpy)(&frame->handlerArgs.sigContext, &uc.uc_mcontext, 
-                 sizeof(struct vki_sigcontext));
-      VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
-                (Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigContext) );
-      
-      frame->handlerArgs.sigContext.oldmask = tst->sig_mask.sig[0];
+   frame->magicPI       = 0x31415927;
+   frame->vex_shadow    = tst->arch.vex_shadow;
+   /* HACK ALERT */
+   frame->vex           = tst->arch.vex;
+   /* end HACK ALERT */
+   frame->mask          = tst->sig_mask;
+   frame->handlerflags  = flags;
+   frame->magicE        = 0x27182818;
+}
+
+
+static Addr build_rt_sigframe(ThreadState *tst,
+                             Addr rsp_top_of_frame,
+                             const vki_siginfo_t *siginfo,
+                             void *handler, UInt flags,
+                             const vki_sigset_t *mask,
+                             void *restorer)
+{
+   struct rt_sigframe *frame;
+   Addr rsp = rsp_top_of_frame;
+   Int sigNo = siginfo->si_signo;
+
+   rsp -= sizeof(*frame);
+   rsp = ROUNDDN(rsp, 16);
+   frame = (struct rt_sigframe *)rsp;
+
+   if (!extend(tst, rsp, sizeof(*frame)))
+      return rsp_top_of_frame;
+
+   /* retaddr, siginfo, uContext fields are to be written */
+   VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "rt signal handler frame", 
+            rsp, offsetof(struct rt_sigframe, vg) );
+
+   if (flags & VKI_SA_RESTORER)
+      frame->retaddr = (Addr)restorer;
+   else {
+      frame->retaddr 
+         = (UInt)VG_(client_trampoline_code)+VG_(tramp_rt_sigreturn_offset);
    }
 
-   frame->magicPI    = 0x31415927;
+   VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t));
 
-   frame->vex        = tst->arch.vex;
-   frame->vex_shadow = tst->arch.vex_shadow;
+   /* SIGILL defines addr to be the faulting address */
+   if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
+      frame->sigInfo._sifields._sigfault._addr 
+         = (void*)tst->arch.vex.guest_RIP;
 
-   frame->mask = tst->sig_mask;
+   synth_ucontext(tst->tid, siginfo, mask, &frame->uContext, &frame->fpstate);
 
-   /* If the thread is currently blocked in a syscall, we want it to
-      resume as runnable. */
-   if (tst->status == VgTs_WaitSys)
-      frame->status = VgTs_Runnable;
-   else
-      frame->status = tst->status;
-   frame->associated_mx = tst->associated_mx;
-   frame->associated_cv = tst->associated_cv;
+   VG_TRACK( post_mem_write,  Vg_CoreSignal, tst->tid, 
+             rsp, offsetof(struct rt_sigframe, vg) );
+
+   build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo);
+   
+   return rsp;
+}
+
+
+void VGA_(push_signal_frame)(ThreadId tid, Addr rsp_top_of_frame,
+                             const vki_siginfo_t *siginfo,
+                             void *handler, UInt flags,
+                             const vki_sigset_t *mask,
+                            void *restorer)
+{
+   Addr                rsp;
+   ThreadState* tst = VG_(get_ThreadState)(tid);
 
-   frame->magicE     = 0x27182818;
+   rsp = build_rt_sigframe(tst, rsp_top_of_frame, siginfo, 
+                                handler, flags, mask, restorer);
 
-   /* Ensure 'tid' and 'tst' correspond */
-   vg_assert(& VG_(threads)[tid] == tst);
    /* Set the thread so it will next run the handler. */
    /* tst->m_esp  = esp; */
-   SET_SIGNAL_ESP(tid, esp);
+   SET_SIGNAL_RSP(tid, rsp);
 
-   tst->arch.vex.guest_EIP = (Addr) handler;
+   //VG_(printf)("handler = %p\n", handler);
+   tst->arch.vex.guest_RIP = (Addr) handler;
    /* This thread needs to be marked runnable, but we leave that the
       caller to do. */
 
    if (0)
-      VG_(printf)("pushed signal frame; %%ESP now = %p, next %%EBP = %p, status=%d\n", 
-                 esp, tst->arch.vex.guest_EIP, tst->status);
-#endif
+      VG_(printf)("pushed signal frame; %%RSP now = %p, "
+                  "next %%RIP = %p, status=%d\n", 
+                 rsp, tst->arch.vex.guest_RIP, tst->status);
 }
 
-Int VGA_(pop_signal_frame)(ThreadId tid)
+
+/*------------------------------------------------------------*/
+/*--- Destroying signal frames                             ---*/
+/*------------------------------------------------------------*/
+
+/* Return False and don't do anything, just set the client to take a
+   segfault, if it looks like the frame is corrupted. */
+static 
+Bool restore_vg_sigframe ( ThreadState *tst, 
+                           struct vg_sigframe *frame, Int *sigNo )
 {
-   I_die_here;
-#if 0
-   Addr          esp;
-   VgSigFrame*   frame;
-   ThreadState*  tst;
+   if (frame->magicPI != 0x31415927 ||
+       frame->magicE  != 0x27182818) {
+      VG_(message)(Vg_UserMsg, "Thread %d return signal frame "
+                               "corrupted.  Killing process.",
+                  tst->tid);
+      VG_(set_default_handler)(VKI_SIGSEGV);
+      VG_(synth_fault)(tst->tid);
+      *sigNo = VKI_SIGSEGV;
+      return False;
+   }
+   tst->sig_mask        = frame->mask;
+   tst->tmp_sig_mask    = frame->mask;
+   tst->arch.vex_shadow = frame->vex_shadow;
+   /* HACK ALERT */
+   tst->arch.vex        = frame->vex;
+   /* end HACK ALERT */
+   *sigNo               = frame->sigNo_private;
+   return True;
+}
 
-   vg_assert(VG_(is_valid_tid)(tid));
-   tst = & VG_(threads)[tid];
+static 
+void restore_sigcontext( ThreadState *tst, 
+                         struct vki_sigcontext *sc, 
+                         struct _vki_fpstate *fpstate )
+{
+   tst->arch.vex.guest_RAX     = sc->rax;
+   tst->arch.vex.guest_RCX     = sc->rcx;
+   tst->arch.vex.guest_RDX     = sc->rdx;
+   tst->arch.vex.guest_RBX     = sc->rbx;
+   tst->arch.vex.guest_RBP     = sc->rbp; 
+   tst->arch.vex.guest_RSP     = sc->rsp;
+   tst->arch.vex.guest_RSI     = sc->rsi;
+   tst->arch.vex.guest_RDI     = sc->rdi;
+   tst->arch.vex.guest_R8      = sc->r8;
+   tst->arch.vex.guest_R9      = sc->r9;
+   tst->arch.vex.guest_R10     = sc->r10;
+   tst->arch.vex.guest_R11     = sc->r11;
+   tst->arch.vex.guest_R12     = sc->r12;
+   tst->arch.vex.guest_R13     = sc->r13;
+   tst->arch.vex.guest_R14     = sc->r14;
+   tst->arch.vex.guest_R15     = sc->r15;
+//::    tst->arch.vex.guest_rflags  = sc->rflags;
+//::    tst->arch.vex.guest_RIP     = sc->rip;
+
+//::    tst->arch.vex.guest_CS      = sc->cs; 
+//::    tst->arch.vex.guest_FS      = sc->fs;
+//::    tst->arch.vex.guest_GS      = sc->gs;
+
+//::    restore_i387(&tst->arch, fpstate);
+}
 
-   /* Correctly reestablish the frame base address. */
-   esp   = tst->arch.vex.guest_ESP;
-   frame = (VgSigFrame*)
-              (esp -4 /* because the handler's RET pops the RA */
-                  +20 /* because signalreturn_bogusRA pushes 5 words */);
 
-   vg_assert(frame->magicPI == 0x31415927);
-   vg_assert(frame->magicE  == 0x27182818);
-   if (VG_(clo_trace_signals))
-      VG_(message)(Vg_DebugMsg, 
-         "vg_pop_signal_frame (thread %d): valid magic; EIP=%p", tid, frame->vex.guest_EIP);
+static 
+SizeT restore_rt_sigframe ( ThreadState *tst, 
+                            struct rt_sigframe *frame, Int *sigNo )
+{
+   if (restore_vg_sigframe(tst, &frame->vg, sigNo))
+      restore_sigcontext(tst, &frame->uContext.uc_mcontext, &frame->fpstate);
 
-   /* Mark the frame structure as nonaccessible. */
-   VG_TRACK( die_mem_stack_signal, (Addr)frame, sizeof(VgSigFrame) );
+   return sizeof(*frame);
+}
 
-   /* restore machine state */
-   tst->arch.vex        = frame->vex;
-   tst->arch.vex_shadow = frame->vex_shadow;
 
-   /* And restore the thread's status to what it was before the signal
-      was delivered. */
-   tst->status    = frame->status;
+void VGA_(signal_return)(ThreadId tid, Bool isRT)
+{
+   Addr          rsp;
+   ThreadState*  tst;
+   SizeT        size;
+   Int          sigNo;
+
+   vg_assert(isRT);
+
+   tst = VG_(get_ThreadState)(tid);
+
+   /* Correctly reestablish the frame base address. */
+   rsp   = tst->arch.vex.guest_RSP;
+
+   size = restore_rt_sigframe(tst, (struct rt_sigframe *)rsp, &sigNo);
 
-   tst->associated_mx = frame->associated_mx;
-   tst->associated_cv = frame->associated_cv;
+   VG_TRACK( die_mem_stack_signal, rsp, size );
 
-   tst->sig_mask  = frame->mask;
+   if (VG_(clo_trace_signals))
+      VG_(message)(
+         Vg_DebugMsg, 
+         "vg_pop_signal_frame (thread %d): isRT=%d valid magic; RIP=%p", 
+         tid, isRT, tst->arch.vex.guest_RIP);
 
-   /* don't use the copy exposed to the handler; it might have changed
-      it. */
-   return frame->sigNo_private; 
-#endif
+   /* tell the tools */
+   VG_TRACK( post_deliver_signal, tid, sigNo );
 }
 
-/*--------------------------------------------------------------------*/
-/*--- end                                                          ---*/
-/*--------------------------------------------------------------------*/
+//:: /*------------------------------------------------------------*/
+//:: /*--- Making coredumps                                     ---*/
+//:: /*------------------------------------------------------------*/
+//:: 
+//:: void VGA_(fill_elfregs_from_tst)(struct vki_user_regs_struct* regs, 
+//::                                  const arch_thread_t* arch)
+//:: {
+//::    regs->rflags = arch->m_rflags;
+//::    regs->rsp    = arch->m_rsp;
+//::    regs->rip    = arch->m_rip;
+//::
+//::    regs->rbx    = arch->m_rbx;
+//::    regs->rcx    = arch->m_rcx;
+//::    regs->rdx    = arch->m_rdx;
+//::    regs->rsi    = arch->m_rsi;
+//::    regs->rdi    = arch->m_rdi;
+//::    regs->rbp    = arch->m_rbp;
+//::    regs->rax    = arch->m_rax;
+//::    regs->r8     = arch->m_r8;
+//::    regs->r9     = arch->m_r9;
+//::    regs->r10    = arch->m_r10;
+//::    regs->r11    = arch->m_r11;
+//::    regs->r12    = arch->m_r12;
+//::    regs->r13    = arch->m_r13;
+//::    regs->r14    = arch->m_r14;
+//::    regs->r15    = arch->m_r15;
+//:: 
+//::    regs->cs     = arch->m_cs;
+//::    regs->fs     = arch->m_fs;
+//::    regs->gs     = arch->m_gs;
+//:: }
+//:: 
+//:: static void fill_fpu(vki_elf_fpregset_t *fpu, const Char *from)
+//:: {
+//::    if (VG_(have_ssestate)) {
+//::       UShort *to;
+//::       Int i;
+//:: 
+//::       /* This is what the kernel does */
+//::       VG_(memcpy)(fpu, from, 7*sizeof(long));
+//::    
+//::       to = (UShort *)&fpu->st_space[0];
+//::       from += 18 * sizeof(UShort);
+//:: 
+//::       for (i = 0; i < 8; i++, to += 5, from += 8) 
+//::    VG_(memcpy)(to, from, 5*sizeof(UShort));
+//::    } else
+//::       VG_(memcpy)(fpu, from, sizeof(*fpu));
+//:: }
+//:: 
+//:: void VGA_(fill_elffpregs_from_tst)( vki_elf_fpregset_t* fpu,
+//::                                     const arch_thread_t* arch)
+//:: {
+//::    fill_fpu(fpu, (const Char *)&arch->m_sse);
+//:: }
+//:: 
+//:: void VGA_(fill_elffpxregs_from_tst) ( vki_elf_fpxregset_t* xfpu,
+//::                                       const arch_thread_t* arch )
+//:: {
+//::    VG_(memcpy)(xfpu, arch->m_sse.state, sizeof(*xfpu));
+//:: }
+//:: 
+//:: /*--------------------------------------------------------------------*/
+//:: /*--- end                                                          ---*/
+//:: /*--------------------------------------------------------------------*/