Arch-abstraction:
- add file for x86-specific signal stuff.  Should have gone in with the last
  commit, whoops.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2715 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/x86/signal.c b/coregrind/x86/signal.c
new file mode 100644
index 0000000..da1f8b7
--- /dev/null
+++ b/coregrind/x86/signal.c
@@ -0,0 +1,440 @@
+
+/*--------------------------------------------------------------------*/
+/*--- x86 signals, etc.                                   signal.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, an extensible x86 protected-mode
+   emulator for monitoring program execution on x86-Unixes.
+
+   Copyright (C) 2000-2004 Nicholas Nethercote
+      njn25@cam.ac.uk
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "core.h"
+
+/*------------------------------------------------------------*/
+/*--- Signal frame                                         ---*/
+/*------------------------------------------------------------*/
+
+// A structure in which to save the application's registers
+// during the execution of signal handlers.
+
+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_ksiginfo_t sigInfo;
+      /* pointed to by puContext */
+      struct vki_ucontext uContext;
+
+      /* Safely-saved version of sigNo, as described above. */
+      Int  sigNo_private;
+      /* Saved processor state. */
+      UInt m_sse[VG_SIZE_OF_SSESTATE_W];
+
+      UInt m_eax;
+      UInt m_ecx;
+      UInt m_edx;
+      UInt m_ebx;
+      UInt m_ebp;
+      UInt m_esp;
+      UInt m_esi;
+      UInt m_edi;
+      UInt m_eflags;
+      Addr m_eip;
+
+      UInt sh_eax;
+      UInt sh_ebx;
+      UInt sh_ecx;
+      UInt sh_edx;
+      UInt sh_esi;
+      UInt sh_edi;
+      UInt sh_ebp;
+      UInt sh_esp;
+      UInt sh_eflags;
+
+      /* saved signal mask to be restored when handler returns */
+      vki_ksigset_t	mask;
+
+      /* Scheduler-private stuff: what was the thread's status prior to
+         delivering this signal? */
+      ThreadStatus status;
+      /* Sanity check word.  Is the highest-addressed word; do not
+         move!*/
+      UInt magicE;
+   }
+   VgSigFrame;
+
+/*------------------------------------------------------------*/
+/*--- Signal operations                                    ---*/
+/*------------------------------------------------------------*/
+
+/* Make up a plausible-looking thread state from the thread's current state */
+static void synth_ucontext(ThreadId tid, const vki_ksiginfo_t *si, 
+			   const vki_ksigset_t *set, struct vki_ucontext *uc)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   struct vki_sigcontext *sc = &uc->uc_mcontext;
+
+   VG_(memset)(uc, 0, sizeof(*uc));
+
+   uc->uc_flags = 0;
+   uc->uc_link = 0;
+   uc->uc_sigmask = *set;
+   uc->uc_stack = tst->altstack;
+
+#define SC(reg)	sc->reg = tst->arch.m_##reg
+   SC(gs);
+   SC(fs);
+   SC(es);
+   SC(ds);
+
+   SC(edi);
+   SC(esi);
+   SC(ebp);
+   SC(esp);
+   SC(ebx);
+   SC(edx);
+   SC(ecx);
+   SC(eax);
+
+   SC(eip);
+   SC(cs);
+   SC(eflags);
+   SC(ss);
+   /* XXX esp_at_signal */
+   /* XXX trapno */
+   /* XXX err */
+#undef SC
+
+   sc->cr2 = (UInt)si->_sifields._sigfault._addr;
+}
+
+void VGA_(push_signal_frame)(ThreadId tid, Addr esp_top_of_frame,
+                             const vki_ksiginfo_t *siginfo,
+                             void *handler, UInt flags,
+                             const vki_ksigset_t *mask)
+{
+   Addr		esp;
+   ThreadState* tst;
+   Int          i;
+   VgSigFrame*  frame;
+   Int		sigNo = siginfo->si_signo;
+
+   esp = esp_top_of_frame;
+   esp -= sizeof(VgSigFrame);
+   frame = (VgSigFrame*)esp;
+
+   tst = & VG_(threads)[tid];
+
+   /* 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;
+   frame->sigNo_private = sigNo;
+   VG_TRACK( post_mem_write, (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, (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_ksiginfo_t));
+      VG_TRACK( post_mem_write, (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, (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, (Addr)&frame->handlerArgs, 
+		sizeof(frame->handlerArgs.sigContext) );
+      
+      frame->handlerArgs.sigContext.oldmask = tst->sig_mask.ws[0];
+   }
+
+   frame->magicPI    = 0x31415927;
+
+   for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++)
+      frame->m_sse[i] = tst->arch.m_sse[i];
+
+   frame->m_eax      = tst->arch.m_eax;
+   frame->m_ecx      = tst->arch.m_ecx;
+   frame->m_edx      = tst->arch.m_edx;
+   frame->m_ebx      = tst->arch.m_ebx;
+   frame->m_ebp      = tst->arch.m_ebp;
+   frame->m_esp      = tst->arch.m_esp;
+   frame->m_esi      = tst->arch.m_esi;
+   frame->m_edi      = tst->arch.m_edi;
+   frame->m_eflags   = tst->arch.m_eflags;
+   frame->m_eip      = tst->arch.m_eip;
+
+   if (VG_(needs).shadow_regs) {
+      frame->sh_eax     = tst->arch.sh_eax;
+      frame->sh_ecx     = tst->arch.sh_ecx;
+      frame->sh_edx     = tst->arch.sh_edx;
+      frame->sh_ebx     = tst->arch.sh_ebx;
+      frame->sh_ebp     = tst->arch.sh_ebp;
+      frame->sh_esp     = tst->arch.sh_esp;
+      frame->sh_esi     = tst->arch.sh_esi;
+      frame->sh_edi     = tst->arch.sh_edi;
+      frame->sh_eflags  = tst->arch.sh_eflags;
+   }
+
+   frame->mask = tst->sig_mask;
+
+   /* 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->magicE     = 0x27182818;
+
+   /* 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);
+
+   tst->arch.m_eip  = (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.m_eip, tst->status);
+}
+
+Int VGA_(pop_signal_frame)(ThreadId tid)
+{
+   Addr          esp;
+   Int           i;
+   VgSigFrame*   frame;
+   ThreadState*  tst;
+
+   vg_assert(VG_(is_valid_tid)(tid));
+   tst = & VG_(threads)[tid];
+
+   /* Correctly reestablish the frame base address. */
+   esp   = tst->arch.m_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->m_eip);
+
+   /* Mark the frame structure as nonaccessible. */
+   VG_TRACK( die_mem_stack_signal, (Addr)frame, sizeof(VgSigFrame) );
+
+   /* restore machine state */
+   for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++)
+      tst->arch.m_sse[i] = frame->m_sse[i];
+
+   tst->arch.m_eax     = frame->m_eax;
+   tst->arch.m_ecx     = frame->m_ecx;
+   tst->arch.m_edx     = frame->m_edx;
+   tst->arch.m_ebx     = frame->m_ebx;
+   tst->arch.m_ebp     = frame->m_ebp; 
+   tst->arch.m_esp     = frame->m_esp;
+   tst->arch.m_esi     = frame->m_esi;
+   tst->arch.m_edi     = frame->m_edi;
+   tst->arch.m_eflags  = frame->m_eflags;
+   tst->arch.m_eip     = frame->m_eip;
+
+   if (VG_(needs).shadow_regs) {
+      tst->arch.sh_eax     = frame->sh_eax;
+      tst->arch.sh_ecx     = frame->sh_ecx;
+      tst->arch.sh_edx     = frame->sh_edx;
+      tst->arch.sh_ebx     = frame->sh_ebx;
+      tst->arch.sh_ebp     = frame->sh_ebp; 
+      tst->arch.sh_esp     = frame->sh_esp;
+      tst->arch.sh_esi     = frame->sh_esi;
+      tst->arch.sh_edi     = frame->sh_edi;
+      tst->arch.sh_eflags  = frame->sh_eflags;
+   }
+
+   /* And restore the thread's status to what it was before the signal
+      was delivered. */
+   tst->status    = frame->status;
+
+   tst->sig_mask  = frame->mask;
+
+   /* don't use the copy exposed to the handler; it might have changed
+      it. */
+   return frame->sigNo_private; 
+}
+
+/*------------------------------------------------------------*/
+/*--- Making coredumps                                     ---*/
+/*------------------------------------------------------------*/
+
+void VGA_(fill_elfregs_from_BB)(struct user_regs_struct* regs)
+{
+   regs->eflags = VG_(baseBlock)[VGOFF_(m_eflags)];
+   regs->esp    = VG_(baseBlock)[VGOFF_(m_esp)];
+   regs->eip    = VG_(baseBlock)[VGOFF_(m_eip)];
+
+   regs->ebx    = VG_(baseBlock)[VGOFF_(m_ebx)];
+   regs->ecx    = VG_(baseBlock)[VGOFF_(m_ecx)];
+   regs->edx    = VG_(baseBlock)[VGOFF_(m_edx)];
+   regs->esi    = VG_(baseBlock)[VGOFF_(m_esi)];
+   regs->edi    = VG_(baseBlock)[VGOFF_(m_edi)];
+   regs->ebp    = VG_(baseBlock)[VGOFF_(m_ebp)];
+   regs->eax    = VG_(baseBlock)[VGOFF_(m_eax)];
+
+   regs->cs     = VG_(baseBlock)[VGOFF_(m_cs)];
+   regs->ds     = VG_(baseBlock)[VGOFF_(m_ds)];
+   regs->ss     = VG_(baseBlock)[VGOFF_(m_ss)];
+   regs->es     = VG_(baseBlock)[VGOFF_(m_es)];
+   regs->fs     = VG_(baseBlock)[VGOFF_(m_fs)];
+   regs->gs     = VG_(baseBlock)[VGOFF_(m_gs)];
+}
+
+
+void VGA_(fill_elfregs_from_tst)(struct user_regs_struct* regs, 
+                                 const arch_thread_t* arch)
+{
+   regs->eflags = arch->m_eflags;
+   regs->esp    = arch->m_esp;
+   regs->eip    = arch->m_eip;
+
+   regs->ebx    = arch->m_ebx;
+   regs->ecx    = arch->m_ecx;
+   regs->edx    = arch->m_edx;
+   regs->esi    = arch->m_esi;
+   regs->edi    = arch->m_edi;
+   regs->ebp    = arch->m_ebp;
+   regs->eax    = arch->m_eax;
+
+   regs->cs     = arch->m_cs;
+   regs->ds     = arch->m_ds;
+   regs->ss     = arch->m_ss;
+   regs->es     = arch->m_es;
+   regs->fs     = arch->m_fs;
+   regs->gs     = arch->m_gs;
+}
+
+static void fill_fpu(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_BB)( elf_fpregset_t* fpu )
+{
+   fill_fpu(fpu, (const Char *)&VG_(baseBlock)[VGOFF_(m_ssestate)]);
+}
+
+void VGA_(fill_elffpregs_from_tst)( elf_fpregset_t* fpu,
+                                    const arch_thread_t* arch)
+{
+   fill_fpu(fpu, (const Char *)&arch->m_sse);
+}
+
+void VGA_(fill_elffpxregs_from_BB) ( elf_fpxregset_t* xfpu )
+{
+   VG_(memcpy)(xfpu, &VG_(baseBlock)[VGOFF_(m_ssestate)], sizeof(*xfpu));
+}
+
+void VGA_(fill_elffpxregs_from_tst) ( elf_fpxregset_t* xfpu,
+                                      const arch_thread_t* arch )
+{
+   VG_(memcpy)(xfpu, arch->m_sse, sizeof(*xfpu));
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/