Home | History | Annotate | Download | only in m_sigframe
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Create/destroy signal delivery frames.                       ---*/
      4 /*---                                       sigframe-ppc64-linux.c ---*/
      5 /*--------------------------------------------------------------------*/
      6 
      7 /*
      8    This file is part of Valgrind, a dynamic binary instrumentation
      9    framework.
     10 
     11    Copyright (C) 2000-2011 Nicholas Nethercote
     12       njn (at) valgrind.org
     13    Copyright (C) 2004-2011 Paul Mackerras
     14       paulus (at) samba.org
     15 
     16    This program is free software; you can redistribute it and/or
     17    modify it under the terms of the GNU General Public License as
     18    published by the Free Software Foundation; either version 2 of the
     19    License, or (at your option) any later version.
     20 
     21    This program is distributed in the hope that it will be useful, but
     22    WITHOUT ANY WARRANTY; without even the implied warranty of
     23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     24    General Public License for more details.
     25 
     26    You should have received a copy of the GNU General Public License
     27    along with this program; if not, write to the Free Software
     28    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     29    02111-1307, USA.
     30 
     31    The GNU General Public License is contained in the file COPYING.
     32 */
     33 
     34 #if defined(VGP_ppc64_linux)
     35 
     36 #include "pub_core_basics.h"
     37 #include "pub_core_vki.h"
     38 #include "pub_core_vkiscnums.h"
     39 #include "pub_core_libcsetjmp.h"    // to keep _threadstate.h happy
     40 #include "pub_core_threadstate.h"
     41 #include "pub_core_aspacemgr.h"
     42 #include "pub_core_libcbase.h"
     43 #include "pub_core_libcassert.h"
     44 #include "pub_core_libcprint.h"
     45 #include "pub_core_machine.h"
     46 #include "pub_core_options.h"
     47 #include "pub_core_sigframe.h"
     48 #include "pub_core_signals.h"
     49 #include "pub_core_tooliface.h"
     50 #include "pub_core_trampoline.h"
     51 #include "pub_core_transtab.h"      // VG_(discard_translations)
     52 
     53 
     54 /* This module creates and removes signal frames for signal deliveries
     55    on ppc64-linux.
     56 
     57    Note, this file contains kernel-specific knowledge in the form of
     58    'struct sigframe' and 'struct rt_sigframe'.  How does that relate
     59    to the vki kernel interface stuff?
     60 
     61    Either a 'struct sigframe' or a 'struct rtsigframe' is pushed
     62    onto the client's stack.  This contains a subsidiary
     63    vki_ucontext.  That holds the vcpu's state across the signal,
     64    so that the sighandler can mess with the vcpu state if it
     65    really wants.
     66 
     67    FIXME: sigcontexting is basically broken for the moment.  When
     68    delivering a signal, the integer registers and %eflags are
     69    correctly written into the sigcontext, however the FP and SSE state
     70    is not.  When returning from a signal, only the integer registers
     71    are restored from the sigcontext; the rest of the CPU state is
     72    restored to what it was before the signal.
     73 
     74    This will be fixed.
     75 */
     76 
     77 
     78 /*------------------------------------------------------------*/
     79 /*--- Signal frame layouts                                 ---*/
     80 /*------------------------------------------------------------*/
     81 
     82 // A structure in which to save the application's registers
     83 // during the execution of signal handlers.
     84 
     85 // On ppc64-linux, rt_sigframe is used for all signals.
     86 
     87 // In theory, so long as we get the arguments to the handler function
     88 // right, it doesn't matter what the exact layout of the rest of the
     89 // frame is.  Unfortunately, things like gcc's exception unwinding
     90 // make assumptions about the locations of various parts of the frame,
     91 // so we need to duplicate it exactly.
     92 
     93 /* Many of these byzantine details derived from
     94    linux-2.6.13/arch/ppc64/kernel/signal.c */
     95 
     96 #define TRAMP_SIZE 6 /* who knows why - it only needs to be 2. */
     97 
     98 /* Structure containing bits of information that we want to save
     99    on signal delivery. */
    100 struct vg_sig_private {
    101    UInt  magicPI;
    102    UInt  sigNo_private;
    103    ULong _unused; /* makes the struct size be zero % 16 */
    104    VexGuestPPC64State vex_shadow1;
    105    VexGuestPPC64State vex_shadow2;
    106 };
    107 
    108 /* Structure put on stack for all signal handlers. */
    109 struct rt_sigframe {
    110    struct vki_ucontext   uc;
    111    ULong                 _unused[2];
    112    UInt                  tramp[TRAMP_SIZE];
    113    struct vki_siginfo*   pinfo;
    114    void*                 puc;
    115    vki_siginfo_t         info;
    116    struct vg_sig_private priv;
    117    UChar                 abigap[288];
    118 };
    119 
    120 #define SET_SIGNAL_LR(zztst, zzval)                          \
    121    do { tst->arch.vex.guest_LR = (zzval);                    \
    122       VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,     \
    123                 offsetof(VexGuestPPC64State,guest_LR),       \
    124                 sizeof(UWord) );                             \
    125    } while (0)
    126 
    127 #define SET_SIGNAL_GPR(zztst, zzn, zzval)                    \
    128    do { tst->arch.vex.guest_GPR##zzn = (zzval);              \
    129       VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,     \
    130                 offsetof(VexGuestPPC64State,guest_GPR##zzn), \
    131                 sizeof(UWord) );                             \
    132    } while (0)
    133 
    134 
    135 /* Extend the stack segment downwards if needed so as to ensure the
    136    new signal frames are mapped to something.  Return a Bool
    137    indicating whether or not the operation was successful.
    138 */
    139 static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
    140 {
    141    ThreadId        tid = tst->tid;
    142    NSegment const* stackseg = NULL;
    143 
    144    if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
    145       stackseg = VG_(am_find_nsegment)(addr);
    146       if (0 && stackseg)
    147 	 VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
    148 		     addr, stackseg->start, stackseg->end);
    149    }
    150 
    151    if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) {
    152       VG_(message)(
    153          Vg_UserMsg,
    154          "Can't extend stack to %#lx during signal delivery for thread %d:\n",
    155          addr, tid);
    156       if (stackseg == NULL)
    157          VG_(message)(Vg_UserMsg, "  no stack segment\n");
    158       else
    159          VG_(message)(Vg_UserMsg, "  too small or bad protection modes\n");
    160 
    161       /* set SIGSEGV to default handler */
    162       VG_(set_default_handler)(VKI_SIGSEGV);
    163       VG_(synth_fault_mapping)(tid, addr);
    164 
    165       /* The whole process should be about to die, since the default
    166 	 action of SIGSEGV to kill the whole process. */
    167       return False;
    168    }
    169 
    170    /* For tracking memory events, indicate the entire frame has been
    171       allocated. */
    172    VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB,
    173              size + VG_STACK_REDZONE_SZB, tid );
    174 
    175    return True;
    176 }
    177 
    178 
    179 /* EXPORTED */
    180 void VG_(sigframe_create)( ThreadId tid,
    181                            Addr sp_top_of_frame,
    182                            const vki_siginfo_t *siginfo,
    183                            const struct vki_ucontext *siguc,
    184                            void *handler,
    185                            UInt flags,
    186                            const vki_sigset_t *mask,
    187 		           void *restorer )
    188 {
    189    struct vg_sig_private* priv;
    190    Addr sp;
    191    ThreadState* tst;
    192    Int sigNo = siginfo->si_signo;
    193    /* Addr faultaddr; */ /* UNUSED */
    194    struct rt_sigframe* frame;
    195 
    196    /* Stack must be 16-byte aligned */
    197    vg_assert(VG_IS_16_ALIGNED(sizeof(struct vg_sig_private)));
    198    vg_assert(VG_IS_16_ALIGNED(sizeof(struct rt_sigframe)));
    199 
    200    sp_top_of_frame &= ~0xf;
    201    sp = sp_top_of_frame - sizeof(struct rt_sigframe);
    202 
    203    tst = VG_(get_ThreadState)(tid);
    204    if (!extend(tst, sp, sp_top_of_frame - sp))
    205       return;
    206 
    207    vg_assert(VG_IS_16_ALIGNED(sp));
    208 
    209    frame = (struct rt_sigframe *) sp;
    210 
    211    /* clear it (conservatively) */
    212    VG_(memset)(frame, 0, sizeof(*frame));
    213 
    214    /////////
    215    frame->pinfo = &frame->info;
    216    frame->puc = &frame->uc;
    217 
    218    frame->uc.uc_flags = 0;
    219    frame->uc.uc_link = 0;
    220    /////////
    221 
    222    /* Set up the stack chain pointer */
    223    VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
    224              sp, sizeof(UWord) );
    225    *(Addr *)sp = tst->arch.vex.guest_GPR1;
    226    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
    227              sp, sizeof(UWord) );
    228 
    229    /* UNUSED:
    230    faultaddr = (Addr)siginfo->_sifields._sigfault._addr;
    231    if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
    232       faultaddr = tst->arch.vex.guest_CIA;
    233    */
    234 
    235    VG_(memcpy)(&frame->info, siginfo, sizeof(*siginfo));
    236    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
    237              (Addr)&frame->info, sizeof(frame->info) );
    238 
    239    frame->uc.uc_flags = 0;
    240    frame->uc.uc_link  = 0;
    241    frame->uc.uc_stack = tst->altstack;
    242    frame->uc.uc_sigmask = tst->sig_mask;
    243    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
    244              (Addr)(&frame->uc), sizeof(frame->uc) );
    245 
    246 #  define DO(gpr)  frame->uc.uc_mcontext.gp_regs[VKI_PT_R0+gpr] \
    247                       = tst->arch.vex.guest_GPR##gpr
    248    DO(0);  DO(1);  DO(2);  DO(3);  DO(4);  DO(5);  DO(6);  DO(7);
    249    DO(8);  DO(9);  DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
    250    DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
    251    DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
    252 #  undef DO
    253 
    254    frame->uc.uc_mcontext.gp_regs[VKI_PT_NIP]     = tst->arch.vex.guest_CIA;
    255    frame->uc.uc_mcontext.gp_regs[VKI_PT_MSR]     = 0xf032;   /* pretty arbitrary */
    256    frame->uc.uc_mcontext.gp_regs[VKI_PT_ORIG_R3] = tst->arch.vex.guest_GPR3;
    257    frame->uc.uc_mcontext.gp_regs[VKI_PT_CTR]     = tst->arch.vex.guest_CTR;
    258    frame->uc.uc_mcontext.gp_regs[VKI_PT_LNK]     = tst->arch.vex.guest_LR;
    259    frame->uc.uc_mcontext.gp_regs[VKI_PT_XER]     = LibVEX_GuestPPC64_get_XER(
    260                                                       &tst->arch.vex);
    261    frame->uc.uc_mcontext.gp_regs[VKI_PT_CCR]     = LibVEX_GuestPPC64_get_CR(
    262                                                       &tst->arch.vex);
    263    //mc->mc_gregs[VKI_PT_MQ]      = 0;
    264    //mc->mc_gregs[VKI_PT_TRAP]    = 0;
    265    //mc->mc_gregs[VKI_PT_DAR]     = fault_addr;
    266    //mc->mc_gregs[VKI_PT_DSISR]   = 0;
    267    //mc->mc_gregs[VKI_PT_RESULT]  = 0;
    268 
    269    /* XXX should do FP and vector regs */
    270 
    271    /* set up signal return trampoline */
    272    /* NB.  5 Sept 07.  mc->mc_pad[0..1] used to contain a the code to
    273       which the signal handler returns, and it just did sys_sigreturn
    274       or sys_rt_sigreturn.  But this doesn't work if the stack is
    275       non-executable, and it isn't consistent with the x86-linux and
    276       amd64-linux scheme for removing the stack frame.  So instead be
    277       consistent and use a stub in m_trampoline.  Then it doesn't
    278       matter whether or not the (guest) stack is executable.  This
    279       fixes #149519 and #145837. */
    280    frame->tramp[0] = 0; /* invalid */
    281    frame->tramp[1] = 0; /* invalid */
    282    VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid,
    283             (Addr)&frame->tramp, sizeof(frame->tramp));
    284 
    285    /* invalidate any translation of this area */
    286    VG_(discard_translations)( (Addr64)&frame->tramp[0],
    287                               sizeof(frame->tramp), "stack_mcontext" );
    288 
    289    /* set the signal handler to return to the trampoline */
    290    SET_SIGNAL_LR(tst, (Addr)&VG_(ppc64_linux_SUBST_FOR_rt_sigreturn));
    291 
    292    /* Stack pointer for the handler .. (note, back chain set
    293       earlier) */
    294    SET_SIGNAL_GPR(tid, 1, sp);
    295 
    296    /* Args for the handler .. */
    297    SET_SIGNAL_GPR(tid, 3, sigNo);
    298    SET_SIGNAL_GPR(tid, 4, (Addr) &frame->info);
    299    SET_SIGNAL_GPR(tid, 5, (Addr) &frame->uc);
    300    /* the kernel sets this, though it doesn't seem to be in the ABI */
    301    SET_SIGNAL_GPR(tid, 6, (Addr) &frame->info);
    302 
    303    /* Handler is in fact a standard ppc64-linux function descriptor,
    304       so extract the function entry point and also the toc ptr to use. */
    305    SET_SIGNAL_GPR(tid, 2, (Addr) ((ULong*)handler)[1]);
    306    tst->arch.vex.guest_CIA = (Addr) ((ULong*)handler)[0];
    307 
    308    priv = &frame->priv;
    309    priv->magicPI       = 0x31415927;
    310    priv->sigNo_private = sigNo;
    311    priv->vex_shadow1   = tst->arch.vex_shadow1;
    312    priv->vex_shadow2   = tst->arch.vex_shadow2;
    313 
    314    if (0)
    315       VG_(printf)("pushed signal frame; %%R1 now = %#lx, "
    316                   "next %%CIA = %#llx, status=%d\n",
    317 		  sp, tst->arch.vex.guest_CIA, tst->status);
    318 }
    319 
    320 
    321 /*------------------------------------------------------------*/
    322 /*--- Destroying signal frames                             ---*/
    323 /*------------------------------------------------------------*/
    324 
    325 /* EXPORTED */
    326 void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
    327 {
    328    ThreadState *tst;
    329    struct vg_sig_private *priv;
    330    Addr sp;
    331    UInt frame_size;
    332    struct rt_sigframe *frame;
    333    Int sigNo;
    334    Bool has_siginfo = isRT;
    335 
    336    vg_assert(VG_(is_valid_tid)(tid));
    337    tst = VG_(get_ThreadState)(tid);
    338 
    339    /* Check that the stack frame looks valid */
    340    sp = tst->arch.vex.guest_GPR1;
    341    vg_assert(VG_IS_16_ALIGNED(sp));
    342    /* JRS 17 Nov 05: This code used to check that *sp -- which should
    343       have been set by the stwu at the start of the handler -- points
    344       to just above the frame (ie, the previous frame).  However, that
    345       isn't valid when delivering signals on alt stacks.  So I removed
    346       it.  The frame is still sanity-checked using the priv->magicPI
    347       field. */
    348 
    349    frame = (struct rt_sigframe *)sp;
    350    frame_size = sizeof(*frame);
    351    priv = &frame->priv;
    352    vg_assert(priv->magicPI == 0x31415927);
    353    tst->sig_mask = frame->uc.uc_sigmask;
    354    tst->tmp_sig_mask = tst->sig_mask;
    355 
    356    sigNo = priv->sigNo_private;
    357 
    358 #  define DO(gpr)  tst->arch.vex.guest_GPR##gpr \
    359                       = frame->uc.uc_mcontext.gp_regs[VKI_PT_R0+gpr]
    360    DO(0);  DO(1);  DO(2);  DO(3);  DO(4);  DO(5);  DO(6);  DO(7);
    361    DO(8);  DO(9);  DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
    362    DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
    363    DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
    364 #  undef DO
    365 
    366    tst->arch.vex.guest_CIA = frame->uc.uc_mcontext.gp_regs[VKI_PT_NIP];
    367 
    368    LibVEX_GuestPPC64_put_CR( frame->uc.uc_mcontext.gp_regs[VKI_PT_CCR],
    369                              &tst->arch.vex );
    370 
    371    tst->arch.vex.guest_LR  = frame->uc.uc_mcontext.gp_regs[VKI_PT_LNK];
    372    tst->arch.vex.guest_CTR = frame->uc.uc_mcontext.gp_regs[VKI_PT_CTR];
    373    LibVEX_GuestPPC64_put_XER( frame->uc.uc_mcontext.gp_regs[VKI_PT_XER],
    374                               &tst->arch.vex );
    375 
    376    tst->arch.vex_shadow1 = priv->vex_shadow1;
    377    tst->arch.vex_shadow2 = priv->vex_shadow2;
    378 
    379    VG_TRACK(die_mem_stack_signal, sp, frame_size);
    380 
    381    if (VG_(clo_trace_signals))
    382       VG_(message)(Vg_DebugMsg,
    383                    "vg_pop_signal_frame (thread %d): isRT=%d "
    384                    "valid magic; EIP=%#llx\n",
    385                    tid, has_siginfo, tst->arch.vex.guest_CIA);
    386 
    387    /* tell the tools */
    388    VG_TRACK( post_deliver_signal, tid, sigNo );
    389 }
    390 
    391 #endif // defined(VGP_ppc64_linux)
    392 
    393 /*--------------------------------------------------------------------*/
    394 /*--- end                                                          ---*/
    395 /*--------------------------------------------------------------------*/
    396