]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Merge r6095:
authorJulian Seward <jseward@acm.org>
Tue, 17 Oct 2006 01:05:09 +0000 (01:05 +0000)
committerJulian Seward <jseward@acm.org>
Tue, 17 Oct 2006 01:05:09 +0000 (01:05 +0000)
A minimal sigframe implementation for AIX5.  Works but does not
provide valid siginfo or ucontext to handlers.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@6246

coregrind/m_sigframe/sigframe-ppc32-aix5.c [new file with mode: 0644]
coregrind/m_sigframe/sigframe-ppc64-aix5.c [new file with mode: 0644]

diff --git a/coregrind/m_sigframe/sigframe-ppc32-aix5.c b/coregrind/m_sigframe/sigframe-ppc32-aix5.c
new file mode 100644 (file)
index 0000000..5c5fb48
--- /dev/null
@@ -0,0 +1,220 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Create/destroy signal delivery frames.                       ---*/
+/*---                                        sigframe-ppc32-aix5.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2006-2006 OpenWorks LLP
+      info@open-works.co.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 "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_machine.h"
+#include "pub_core_options.h"
+#include "pub_core_signals.h"
+#include "pub_core_tooliface.h"
+#include "pub_core_trampoline.h"
+#include "pub_core_transtab.h"      // VG_(discard_translations)
+#include "pub_core_sigframe.h"      /* self */
+
+
+/* This module creates and removes signal frames for signal deliveries
+   on ppc32-aix5.  Kludgey; the machine state ought to be saved in a
+   ucontext and retrieved from it later, so the handler can modify it
+   and return.  However .. for now .. just stick the vex guest state
+   in the frame and snarf it again later.
+
+   Also, don't bother with creating siginfo and ucontext in the
+   handler, although do point them somewhere non-faulting.
+*/
+struct hacky_sigframe {
+   UChar              lower_guardzone[512];  // put nothing here
+   VexGuestPPC32State gst;
+   VexGuestPPC32State gshadow;
+   UInt               magicPI;
+   UInt               sigNo_private;
+   UInt               tramp[2];
+   UChar              upper_guardzone[512]; // put nothing here
+};
+
+
+/* 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 )
+{
+   /* For tracking memory events, indicate the entire frame has been
+      allocated.  Except, don't mess with the area which
+      overlaps the previous frame's redzone. */
+   VG_TRACK( new_mem_stack_signal, addr, size - VG_STACK_REDZONE_SZB );
+   return True;
+}
+
+#define SET_SIGNAL_LR(zztst, zzval)                          \
+   do { tst->arch.vex.guest_LR = (zzval);                    \
+      VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,     \
+                offsetof(VexGuestPPC32State,guest_LR),       \
+                sizeof(UWord) );                             \
+   } while (0)
+
+#define SET_SIGNAL_GPR(zztst, zzn, zzval)                    \
+   do { tst->arch.vex.guest_GPR##zzn = (zzval);              \
+      VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,     \
+                offsetof(VexGuestPPC32State,guest_GPR##zzn), \
+                sizeof(UWord) );                             \
+   } while (0)
+
+
+/* Create a signal frame for thread 'tid'. */
+void VG_(sigframe_create) ( ThreadId tid,
+                            Addr sp_top_of_frame,
+                            const vki_siginfo_t *siginfo,
+                            void *handler,
+                            UInt flags,
+                            const vki_sigset_t *mask,
+                            void *restorer )
+{
+   ThreadState* tst;
+   Addr sp;
+   struct hacky_sigframe* frame;
+   Int sigNo = siginfo->si_signo;
+   Int __NR_FAKE_SIGRETURN = __NR_AIX5_FAKE_SIGRETURN;
+
+   vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
+
+   sp_top_of_frame &= ~0xf;
+   sp = sp_top_of_frame - sizeof(struct hacky_sigframe);
+
+   tst = VG_(get_ThreadState)(tid);
+   if (!extend(tst, sp, sp_top_of_frame - sp))
+     return;
+
+   vg_assert(VG_IS_16_ALIGNED(sp));
+
+   frame = (struct hacky_sigframe *) sp;
+
+   /* clear it (very conservatively) */
+   VG_(memset)(&frame->lower_guardzone, 0, 512);
+   VG_(memset)(&frame->gst,     0, sizeof(VexGuestPPC32State));
+   VG_(memset)(&frame->gshadow, 0, sizeof(VexGuestPPC32State));
+
+   /* save stuff in frame */
+   frame->gst           = tst->arch.vex;
+   frame->gshadow       = tst->arch.vex_shadow;
+   frame->sigNo_private = sigNo;
+   frame->magicPI       = 0x31415927;
+
+   /* Set up stack frame pointer */
+   sp += 256;
+   vg_assert(sp == (Addr)&frame->lower_guardzone[256]);
+   VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
+             sp, sizeof(UWord) );
+   *(Addr*)sp = tst->arch.vex.guest_GPR1;
+   VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
+             sp, sizeof(UWord) );
+
+   /* Set regs for the handler */
+   SET_SIGNAL_GPR(tid, 1, sp);
+   SET_SIGNAL_GPR(tid, 2, ((UWord*)handler)[1]);
+   SET_SIGNAL_GPR(tid, 3, sigNo);
+   SET_SIGNAL_GPR(tid, 4, 0); /* XXX: the siginfo* */
+   SET_SIGNAL_GPR(tid, 5, 0); /* XXX: the ucontext* */
+   tst->arch.vex.guest_CIA = ((UWord*)handler)[0];
+
+   /* set up return trampoline */
+   vg_assert(__NR_FAKE_SIGRETURN >= 10000);
+   vg_assert(__NR_FAKE_SIGRETURN <= 32767);
+   frame->tramp[0] = 0x38400000U 
+                     + __NR_FAKE_SIGRETURN; /* li 2,__NR_FAKE_SIGRETURN */
+   frame->tramp[1] = 0x44000002U;           /* sc */
+
+   /* invalidate any translation of this area */
+   VG_(discard_translations)( (Addr64)(Addr)&frame->tramp[0], 
+                              sizeof(frame->tramp), "sigframe tramp" );   
+   /* set the signal handler to return to the trampoline */
+   SET_SIGNAL_LR(tst, (Addr) &frame->tramp[0]);
+
+   VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid,
+            (Addr)&frame->tramp, sizeof(frame->tramp));
+
+   if (0) {
+      VG_(printf)("pushed signal frame for sig %d; R1 now = %p, "
+                  "next %%CIA = %p, status=%d\n", 
+                  sigNo,
+                 sp, tst->arch.vex.guest_CIA, tst->status);
+      VG_(printf)("trampoline is at %p\n",  &frame->tramp[0]);
+   }
+}
+
+
+/* Remove a signal frame from thread 'tid's stack, and restore the CPU
+   state from it.  Note, isRT is irrelevant here. */
+void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
+{
+   ThreadState *tst;
+   Addr sp;
+   Int sigNo;
+   struct hacky_sigframe* frame;
+   vg_assert(VG_(is_valid_tid)(tid));
+   tst = VG_(get_ThreadState)(tid);
+
+   /* Check that the stack frame looks valid */
+   sp = tst->arch.vex.guest_GPR1;
+   vg_assert(VG_IS_16_ALIGNED(sp));
+
+   frame = (struct hacky_sigframe*)(sp - 256);
+   vg_assert(frame->magicPI == 0x31415927);
+
+   /* restore the entire guest state, and shadow, from the
+      frame.  Note, as per comments above, this is a kludge - should
+      restore it from saved ucontext.  Oh well. */
+   tst->arch.vex = frame->gst;
+   tst->arch.vex_shadow = frame->gshadow;
+   sigNo = frame->sigNo_private;
+
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg,
+                   "vg_pop_signal_frame (thread %d): valid magic; CIA=%p",
+                   tid, tst->arch.vex.guest_CIA);
+
+   VG_TRACK( die_mem_stack_signal, 
+             (Addr)frame, 
+             sizeof(struct hacky_sigframe) - VG_STACK_REDZONE_SZB );
+
+   /* tell the tools */
+   VG_TRACK( post_deliver_signal, tid, sigNo );
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                   sigframe-ppc32-linux.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_sigframe/sigframe-ppc64-aix5.c b/coregrind/m_sigframe/sigframe-ppc64-aix5.c
new file mode 100644 (file)
index 0000000..e46da88
--- /dev/null
@@ -0,0 +1,254 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Create/destroy signal delivery frames.                       ---*/
+/*---                                        sigframe-ppc64-aix5.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2006-2006 OpenWorks LLP
+      info@open-works.co.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 "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_machine.h"
+#include "pub_core_options.h"
+#include "pub_core_signals.h"
+#include "pub_core_tooliface.h"
+#include "pub_core_trampoline.h"
+#include "pub_core_transtab.h"      // VG_(discard_translations)
+#include "pub_core_sigframe.h"      /* self */
+
+
+/* This module creates and removes signal frames for signal deliveries
+   on ppc64-aix5.  Kludgey; the machine state ought to be saved in a
+   ucontext and retrieved from it later, so the handler can modify it
+   and return.  However .. for now .. just stick the vex guest state
+   in the frame and snarf it again later.
+
+   Also, don't bother with creating siginfo and ucontext in the
+   handler, although do point them somewhere non-faulting.
+*/
+struct hacky_sigframe {
+   UChar              lower_guardzone[1024];  // put nothing here
+   VexGuestPPC64State gst;
+   VexGuestPPC64State gshadow;
+   UInt               magicPI;
+   UInt               sigNo_private;
+   UInt               tramp[2];
+   UChar              upper_guardzone[1024]; // put nothing here
+};
+
+
+/* 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 )
+{
+   /* For tracking memory events, indicate the entire frame has been
+      allocated.  Except, don't mess with the area which
+      overlaps the previous frame's redzone. */
+   VG_TRACK( new_mem_stack_signal, addr, size - VG_STACK_REDZONE_SZB );
+   return True;
+}
+
+#define SET_SIGNAL_LR(zztst, zzval)                          \
+   do { tst->arch.vex.guest_LR = (zzval);                    \
+      VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,     \
+                offsetof(VexGuestPPC64State,guest_LR),       \
+                sizeof(UWord) );                             \
+   } while (0)
+
+#define SET_SIGNAL_GPR(zztst, zzn, zzval)                    \
+   do { tst->arch.vex.guest_GPR##zzn = (zzval);              \
+      VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,     \
+                offsetof(VexGuestPPC64State,guest_GPR##zzn), \
+                sizeof(UWord) );                             \
+   } while (0)
+
+
+/* Create a signal frame for thread 'tid'. */
+void VG_(sigframe_create) ( ThreadId tid,
+                            Addr sp_top_of_frame,
+                            const vki_siginfo_t *siginfo,
+                            void *handler,
+                            UInt flags,
+                            const vki_sigset_t *mask,
+                            void *restorer )
+{
+   ThreadState* tst;
+   Addr sp;
+   struct hacky_sigframe* frame;
+   Int sigNo = siginfo->si_signo;
+   Int __NR_FAKE_SIGRETURN = __NR_AIX5_FAKE_SIGRETURN;
+
+   vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
+
+   sp_top_of_frame &= ~0xf;
+   sp = sp_top_of_frame - sizeof(struct hacky_sigframe);
+
+   tst = VG_(get_ThreadState)(tid);
+   if (!extend(tst, sp, sp_top_of_frame - sp))
+     return;
+
+   vg_assert(VG_IS_16_ALIGNED(sp));
+
+   frame = (struct hacky_sigframe *) sp;
+
+   /* clear it (very conservatively) */
+   VG_(memset)(&frame->lower_guardzone, 0, 1024);
+   VG_(memset)(&frame->gst,     0, sizeof(VexGuestPPC64State));
+   VG_(memset)(&frame->gshadow, 0, sizeof(VexGuestPPC64State));
+
+   /* save stuff in frame */
+   frame->gst           = tst->arch.vex;
+   frame->gshadow       = tst->arch.vex_shadow;
+   frame->sigNo_private = sigNo;
+   frame->magicPI       = 0x31415927;
+
+   /* Set up stack frame pointer */
+   sp += 512;
+   vg_assert(sp == (Addr)&frame->lower_guardzone[512]);
+   VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
+             sp, sizeof(UWord) );
+   *(Addr*)sp = tst->arch.vex.guest_GPR1;
+   VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
+             sp, sizeof(UWord) );
+
+   /* Set regs for the handler */
+   SET_SIGNAL_GPR(tid, 1, sp);
+   SET_SIGNAL_GPR(tid, 2, ((UWord*)handler)[1]);
+   SET_SIGNAL_GPR(tid, 3, sigNo);
+   SET_SIGNAL_GPR(tid, 4, 0); /* XXX: the siginfo* */
+   SET_SIGNAL_GPR(tid, 5, 0); /* XXX: the ucontext* */
+   tst->arch.vex.guest_CIA = ((UWord*)handler)[0];
+
+   /* set up return trampoline */
+   vg_assert(__NR_FAKE_SIGRETURN >= 10000);
+   vg_assert(__NR_FAKE_SIGRETURN <= 32767);
+   frame->tramp[0] = 0x38400000U 
+                     + __NR_FAKE_SIGRETURN; /* li 2,__NR_FAKE_SIGRETURN */
+   frame->tramp[1] = 0x44000002U;           /* sc */
+
+   /* invalidate any translation of this area */
+   VG_(discard_translations)( (Addr64)(Addr)&frame->tramp[0], 
+                              sizeof(frame->tramp), "sigframe tramp" );   
+   /* set the signal handler to return to the trampoline */
+   SET_SIGNAL_LR(tst, (Addr) &frame->tramp[0]);
+
+   VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid,
+            (Addr)&frame->tramp, sizeof(frame->tramp));
+
+   if (0) {
+      VG_(printf)("pushed signal frame for sig %d; R1 now = %p, "
+                  "next %%CIA = %p, status=%d\n", 
+                  sigNo,
+                 sp, tst->arch.vex.guest_CIA, tst->status);
+      VG_(printf)("trampoline is at %p\n",  &frame->tramp[0]);
+   }
+}
+
+
+/* Remove a signal frame from thread 'tid's stack, and restore the CPU
+   state from it.  Note, isRT is irrelevant here. */
+void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
+{
+   ThreadState *tst;
+   Addr sp, sp_max;
+   const UWord one_meg = 1048576;
+   UWord scannable_bytes;
+
+   Int sigNo, i;
+   struct hacky_sigframe* frame;
+   vg_assert(VG_(is_valid_tid)(tid));
+   tst = VG_(get_ThreadState)(tid);
+
+   /* Check that the stack frame looks valid */
+   sp = tst->arch.vex.guest_GPR1;
+   vg_assert(VG_IS_16_ALIGNED(sp));
+
+   /* If the frame is being cleared by some mechanism other than our
+      fake sigreturn, sp may not be as it was after the frame was
+      constructed.  If so, scan back up the stack looking for the most
+      recently pushed frame and assume that's the right one to use.
+      Urk. */
+   sp_max = tst->client_stack_highest_word;
+   scannable_bytes = 0;
+   if (sp_max > sp)
+      scannable_bytes = sp_max - sp;
+   if (scannable_bytes > one_meg)
+      scannable_bytes = one_meg;
+   if (scannable_bytes < (sizeof(struct hacky_sigframe)-512)) 
+      scannable_bytes = 0;
+   else
+      scannable_bytes -= (sizeof(struct hacky_sigframe)-512);
+
+   vg_assert(scannable_bytes <= one_meg);
+
+   frame = (struct hacky_sigframe*)(sp - 512);
+   if (frame->magicPI != 0x31415927) {
+      if (!VG_(clo_xml))
+         VG_(message)(Vg_DebugMsg, 
+            "WARNING: dubious signal return: searching %ld bytes for frame", 
+            scannable_bytes);
+      for (i = 0; i < scannable_bytes/4; i++) {
+         if (frame->magicPI == 0x31415927)
+            break;
+         frame = (struct hacky_sigframe*)(((Addr)frame)+4);
+      }
+   }
+
+   /* If we haven't found the frame by now, we're hosed. */
+   vg_assert(frame->magicPI == 0x31415927);
+
+   /* restore the entire guest state, and shadow, from the
+      frame.  Note, as per comments above, this is a kludge - should
+      restore it from saved ucontext.  Oh well. */
+   tst->arch.vex = frame->gst;
+   tst->arch.vex_shadow = frame->gshadow;
+   sigNo = frame->sigNo_private;
+
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg,
+                   "vg_pop_signal_frame (thread %d): valid magic; CIA=%p",
+                   tid, tst->arch.vex.guest_CIA);
+
+   VG_TRACK( die_mem_stack_signal, 
+             (Addr)frame, 
+             sizeof(struct hacky_sigframe) - VG_STACK_REDZONE_SZB );
+
+   /* tell the tools */
+   VG_TRACK( post_deliver_signal, tid, sigNo );
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                   sigframe-ppc64-linux.c ---*/
+/*--------------------------------------------------------------------*/