Home | History | Annotate | Download | only in m_sigframe
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Create/destroy signal delivery frames.                       ---*/
      4 /*---                                        sigframe-x86-darwin.c ---*/
      5 /*--------------------------------------------------------------------*/
      6 
      7 /*
      8    This file is part of Valgrind, a dynamic binary instrumentation
      9    framework.
     10 
     11    Copyright (C) 2006-2015 OpenWorks Ltd
     12       info (at) open-works.co.uk
     13 
     14    This program is free software; you can redistribute it and/or
     15    modify it under the terms of the GNU General Public License as
     16    published by the Free Software Foundation; either version 2 of the
     17    License, or (at your option) any later version.
     18 
     19    This program is distributed in the hope that it will be useful, but
     20    WITHOUT ANY WARRANTY; without even the implied warranty of
     21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     22    General Public License for more details.
     23 
     24    You should have received a copy of the GNU General Public License
     25    along with this program; if not, write to the Free Software
     26    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     27    02111-1307, USA.
     28 
     29    The GNU General Public License is contained in the file COPYING.
     30 */
     31 
     32 #if defined(VGP_x86_darwin)
     33 
     34 #include "pub_core_basics.h"
     35 #include "pub_core_vki.h"
     36 #include "pub_core_vkiscnums.h"
     37 #include "pub_core_threadstate.h"
     38 #include "pub_core_aspacemgr.h"
     39 #include "pub_core_libcbase.h"
     40 #include "pub_core_libcassert.h"
     41 #include "pub_core_libcprint.h"
     42 #include "pub_core_machine.h"
     43 #include "pub_core_options.h"
     44 #include "pub_core_signals.h"
     45 #include "pub_core_tooliface.h"
     46 #include "pub_core_trampoline.h"
     47 #include "pub_core_sigframe.h"      /* self */
     48 #include "priv_sigframe.h"
     49 
     50 
     51 /* Originally copied from ppc32-aix5 code.
     52    Produce a frame with layout entirely of our own choosing.
     53 
     54    This module creates and removes signal frames for signal deliveries
     55    on x86-darwin.  The machine state is saved in a ucontext and retrieved
     56    from it later, so the handler can modify it and return.
     57 
     58    Frame should have a 16-aligned size, just in case that turns out to
     59    be important for Darwin.  (be conservative)
     60 */
     61 struct hacky_sigframe {
     62    /* first four words look like a call to a 3-arg x86 function */
     63    UInt             returnAddr;
     64    UInt             a1_signo;
     65    UInt             a2_siginfo;
     66    UInt             a3_ucontext;
     67    UChar            lower_guardzone[512];  // put nothing here
     68    VexGuestX86State vex;
     69    VexGuestX86State vex_shadow1;
     70    VexGuestX86State vex_shadow2;
     71    vki_siginfo_t    fake_siginfo;
     72    struct vki_ucontext fake_ucontext;
     73    UInt             magicPI;
     74    UInt             sigNo_private;
     75    vki_sigset_t     mask; // saved sigmask; restore when hdlr returns
     76    UInt             __pad[3];
     77    UChar            upper_guardzone[512]; // put nothing here
     78    // and don't zero it, since that might overwrite the client's
     79    // stack redzone, at least on archs which have one
     80 };
     81 
     82 /* Create a plausible-looking sigcontext from the thread's
     83    Vex guest state.  NOTE: does not fill in the FP or SSE
     84    bits of sigcontext at the moment.
     85  */
     86 static void synthesize_ucontext(ThreadState *tst,
     87 				struct vki_ucontext *uc,
     88 				const struct vki_ucontext *siguc)
     89 {
     90    VG_(memset)(uc, 0, sizeof(*uc));
     91 
     92    if (siguc) uc->uc_sigmask = siguc->uc_sigmask;
     93    uc->uc_stack = tst->altstack;
     94    uc->uc_mcontext = &uc->__mcontext_data;
     95 
     96 #  define SC2(reg,REG)  uc->__mcontext_data.__ss.reg = tst->arch.vex.guest_##REG
     97    SC2(__edi,EDI);
     98    SC2(__esi,ESI);
     99    SC2(__ebp,EBP);
    100    SC2(__ebx,EBX);
    101    SC2(__edx,EDX);
    102    SC2(__eax,EAX);
    103    SC2(__ecx,ECX);
    104    SC2(__esp,ESP);
    105    SC2(__eip,EIP);
    106    uc->__mcontext_data.__ss.__eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
    107 
    108    if (siguc)
    109       uc->__mcontext_data.__es = siguc->__mcontext_data.__es;
    110 #  undef SC2
    111 }
    112 
    113 static void restore_from_ucontext(ThreadState *tst,
    114 				  const struct vki_ucontext *uc)
    115 {
    116 #  define SC2(REG,reg)  tst->arch.vex.guest_##REG = uc->__mcontext_data.__ss.reg
    117    SC2(EDI,__edi);
    118    SC2(ESI,__esi);
    119    SC2(EBP,__ebp);
    120    SC2(EBX,__ebx);
    121    SC2(EDX,__edx);
    122    SC2(EAX,__eax);
    123    SC2(ECX,__ecx);
    124    SC2(ESP,__esp);
    125    SC2(EIP,__eip);
    126    /* There doesn't seem to be an easy way to restore eflags */
    127 #  undef SC2
    128 }
    129 
    130 /* Create a signal frame for thread 'tid'.  Make a 3-arg frame
    131    regardless of whether the client originally requested a 1-arg
    132    version (no SA_SIGINFO) or a 3-arg one (SA_SIGINFO) since in the
    133    former case, the x86 calling conventions will simply cause the
    134    extra 2 args to be ignored (inside the handler). */
    135 void VG_(sigframe_create) ( ThreadId tid,
    136                             Bool on_altstack,
    137                             Addr sp_top_of_frame,
    138                             const vki_siginfo_t *siginfo,
    139                             const struct vki_ucontext *siguc,
    140                             void *handler,
    141                             UInt flags,
    142                             const vki_sigset_t *mask,
    143                             void *restorer )
    144 {
    145    ThreadState* tst;
    146    Addr esp;
    147    struct hacky_sigframe* frame;
    148    Int sigNo = siginfo->si_signo;
    149 
    150    vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
    151 
    152    sp_top_of_frame &= ~0xf;
    153    esp = sp_top_of_frame - sizeof(struct hacky_sigframe);
    154    esp -= 4; /* ELF ABI says that esp+4 must be 16 aligned on
    155                 entry to a function. */
    156 
    157    tst = VG_(get_ThreadState)(tid);
    158    if (! ML_(sf_maybe_extend_stack)(tst, esp, sp_top_of_frame - esp, flags))
    159       return;
    160 
    161    vg_assert(VG_IS_16_ALIGNED(esp+4));
    162 
    163    frame = (struct hacky_sigframe *) esp;
    164 
    165    /* clear it (very conservatively) */
    166    VG_(memset)(&frame->lower_guardzone, 0, sizeof frame->lower_guardzone);
    167    VG_(memset)(&frame->vex,      0, sizeof(VexGuestX86State));
    168    VG_(memset)(&frame->vex_shadow1, 0, sizeof(VexGuestX86State));
    169    VG_(memset)(&frame->vex_shadow2, 0, sizeof(VexGuestX86State));
    170    VG_(memset)(&frame->fake_siginfo,  0, sizeof(frame->fake_siginfo));
    171    VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext));
    172 
    173    /* save stuff in frame */
    174    frame->vex           = tst->arch.vex;
    175    frame->vex_shadow1   = tst->arch.vex_shadow1;
    176    frame->vex_shadow2   = tst->arch.vex_shadow2;
    177    frame->sigNo_private = sigNo;
    178    frame->mask          = tst->sig_mask;
    179    frame->magicPI       = 0x31415927;
    180 
    181    /* Fill in the siginfo and ucontext.  */
    182    synthesize_ucontext(tst, &frame->fake_ucontext, siguc);
    183    frame->fake_siginfo = *siginfo;
    184 
    185    /* Set up stack pointer */
    186    vg_assert(esp == (Addr)&frame->returnAddr);
    187    VG_(set_SP)(tid, esp);
    188    VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(UInt));
    189 
    190    /* Set up program counter */
    191    VG_(set_IP)(tid, (UInt)handler);
    192    VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(UInt));
    193 
    194    /* Set up RA and args for the frame */
    195    VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
    196              (Addr)frame, 4*sizeof(UInt) );
    197    frame->returnAddr  = (UInt)&VG_(x86_darwin_SUBST_FOR_sigreturn);
    198 
    199    frame->a1_signo    =         sigNo;
    200    frame->a2_siginfo  = (UInt)  &frame->fake_siginfo;
    201    frame->a3_ucontext = (UInt)  &frame->fake_ucontext;
    202 
    203    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
    204              (Addr)frame, 4*sizeof(UInt) );
    205    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
    206              (Addr)&frame->fake_siginfo, sizeof(frame->fake_siginfo));
    207    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
    208              (Addr)&frame->fake_ucontext, sizeof(frame->fake_ucontext));
    209 
    210    if (VG_(clo_trace_signals))
    211       VG_(message)(Vg_DebugMsg,
    212                    "sigframe_create (thread %u): "
    213                    "next EIP=%#lx, next ESP=%#lx\n",
    214                    tid, (Addr)handler, (Addr)frame );
    215 }
    216 
    217 
    218 /* Remove a signal frame from thread 'tid's stack, and restore the CPU
    219    state from it.  Note, isRT is irrelevant here. */
    220 void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
    221 {
    222    ThreadState *tst;
    223    Addr esp;
    224    Int sigNo;
    225    struct hacky_sigframe* frame;
    226 
    227    vg_assert(VG_(is_valid_tid)(tid));
    228    tst = VG_(get_ThreadState)(tid);
    229 
    230    /* Check that the stack frame looks valid */
    231    esp = VG_(get_SP)(tid);
    232 
    233    /* why -4 ? because the signal handler's return will have popped
    234       the return address off the stack; and the return address is the
    235       lowest-addressed element of hacky_sigframe. */
    236    frame = (struct hacky_sigframe*)(esp - 4);
    237    vg_assert(frame->magicPI == 0x31415927);
    238 
    239    /* This +4 is because of the -4 referred to in the ELF ABI comment
    240       in VG_(sigframe_create) just above. */
    241    vg_assert(VG_IS_16_ALIGNED((Addr)frame + 4));
    242 
    243    /* restore the entire guest state, and shadows, from the frame. */
    244    tst->arch.vex            = frame->vex;
    245    tst->arch.vex_shadow1    = frame->vex_shadow1;
    246    tst->arch.vex_shadow2    = frame->vex_shadow2;
    247    restore_from_ucontext(tst, &frame->fake_ucontext);
    248 
    249    tst->sig_mask            = frame->mask;
    250    tst->tmp_sig_mask        = frame->mask;
    251    sigNo                    = frame->sigNo_private;
    252 
    253    if (VG_(clo_trace_signals))
    254       VG_(message)(Vg_DebugMsg,
    255                    "sigframe_destroy (thread %u): "
    256                    "valid magic; next EIP=%#x\n",
    257                    tid, tst->arch.vex.guest_EIP);
    258 
    259    VG_TRACK( die_mem_stack_signal,
    260              (Addr)frame - VG_STACK_REDZONE_SZB,
    261              sizeof(struct hacky_sigframe) );
    262 
    263    /* tell the tools */
    264    VG_TRACK( post_deliver_signal, tid, sigNo );
    265 }
    266 
    267 #endif // defined(VGP_x86_darwin)
    268 
    269 /*--------------------------------------------------------------------*/
    270 /*--- end                                                          ---*/
    271 /*--------------------------------------------------------------------*/
    272