Home | History | Annotate | Download | only in m_sigframe
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Create/destroy signal delivery frames.                       ---*/
      4 /*---                                           sigframe-solaris.c ---*/
      5 /*--------------------------------------------------------------------*/
      6 
      7 /*
      8    This file is part of Valgrind, a dynamic binary instrumentation
      9    framework.
     10 
     11    Copyright (C) 2011-2015 Petr Pavlu
     12       setup (at) dagobah.cz
     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_solaris) || defined(VGP_amd64_solaris)
     33 
     34 #include "pub_core_basics.h"
     35 #include "pub_core_vki.h"
     36 #include "pub_core_threadstate.h"
     37 #include "pub_core_aspacemgr.h"
     38 #include "pub_core_libcassert.h"
     39 #include "pub_core_libcbase.h"
     40 #include "pub_core_libcprint.h"
     41 #include "pub_core_machine.h"
     42 #include "pub_core_options.h"
     43 #include "pub_core_signals.h"
     44 #include "pub_core_tooliface.h"
     45 #include "pub_core_sigframe.h"      /* Self */
     46 #include "pub_core_syswrap.h"
     47 #include "priv_sigframe.h"
     48 
     49 /* This module creates and removes signal frames for signal deliveries
     50    on x86/amd64-solaris. */
     51 
     52 /* Create a signal frame for thread 'tid'.  Make a 3-arg frame regardless of
     53    whether the client originally requested a 1-arg version (no SA_SIGINFO) or
     54    a 3-arg one (SA_SIGINFO) since in the former case, the x86/amd64 calling
     55    conventions will simply cause the extra 2 args to be ignored (inside the
     56    handler). */
     57 void VG_(sigframe_create)(ThreadId tid, Bool on_altstack,
     58                           Addr sp_top_of_frame, const vki_siginfo_t *siginfo,
     59                           const struct vki_ucontext *siguc,
     60                           void *handler, UInt flags, const vki_sigset_t *mask,
     61                           void *restorer)
     62 {
     63    ThreadState *tst = VG_(get_ThreadState)(tid);
     64    Addr esp;
     65    vki_sigframe_t *frame;
     66    Int signo = siginfo->si_signo;
     67 
     68    /* Calculate new stack pointer. */
     69    esp = sp_top_of_frame - sizeof(vki_sigframe_t);
     70    esp = VG_ROUNDDN(esp, 16) - sizeof(UWord);
     71 
     72    if (!ML_(sf_maybe_extend_stack)(tst, esp, sp_top_of_frame - esp, flags))
     73       return;
     74 
     75    /* Fill in the frame. */
     76    frame = (vki_sigframe_t*)esp;
     77 
     78    /* Set a bogus return address.  This return address should be never used
     79       because to return from a signal handler a program has to call
     80       setcontext() explicitly. */
     81    frame->return_addr = (void*)~0UL;
     82 
     83    /* Save current context.  (This has to be done before the thread state is
     84       modified in any way.) */
     85    VG_(save_context)(tid, &frame->ucontext, Vg_CoreSignal);
     86 
     87    /* Fill in the siginfo. */
     88    frame->siginfo = *siginfo;
     89    /* Set expected si_addr value.
     90 
     91       Manual page siginfo.h(3HEAD) describes that some signals define si_addr
     92       to be an address of the faulting instruction (SIGILL). Then it is needed
     93       to change the real CPU address to the VCPU address. Some signals define
     94       si_addr to be an address of the faulting memory reference (SIGSEGV,
     95       SIGBUS). Then the address should be passed unmodified.
     96 
     97       However documentation contained in the manpage does not reflect the
     98       reality found in the Solaris kernel - uts/<arch>/os/trap.c. Here one can
     99       observe that in some cases si_addr is set to address provided by the
    100       underlying subsystem. In some cases si_addr is set to the current
    101       program counter. Other signals are missing documentation altogether.
    102       It is almost impossible to determine what value is stored in si_addr
    103       based on the information provided by kernel to the signal handler.
    104 
    105       POSIX.1-2008 says about si_addr:
    106       SIGILL, SIGFPE ... Address of faulting instruction.
    107       SIGSEGV, SIGBUS ... Address of faulting memory reference.
    108       For some implementations, the value of si_addr may be inaccurate.
    109 
    110       See tests none/tests/faultstatus and none/tests/x86/badseg for examples.
    111       The code below simply follows the POSIX standard, but propagates any
    112       possibly incorrect values from the kernel to the user.
    113     */
    114    switch (signo) {
    115    case VKI_SIGSEGV:
    116       switch (siginfo->si_code) {
    117       case VKI_SEGV_ACCERR:
    118       case VKI_SEGV_MAPERR:
    119       default:
    120          break;
    121       case VKI_SEGV_MADE_UP_GPF:
    122          /* Translate si_code synthesized by Valgrind to SEGV_MAPPER. */
    123          frame->siginfo.si_code = VKI_SEGV_MAPERR;
    124          break;
    125       }
    126       break;
    127    case VKI_SIGBUS:
    128       break;
    129    case VKI_SIGFPE:
    130    case VKI_SIGILL:
    131    case VKI_SIGTRAP:
    132       frame->siginfo.si_addr = (void*)VG_(get_IP)(tid);
    133       break;
    134    case VKI_SIGPROF:
    135       frame->siginfo.si_faddr = (void*)VG_(get_IP)(tid);
    136       break;
    137    default:
    138       break;
    139    }
    140    VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)&frame->siginfo,
    141             sizeof(frame->siginfo));
    142 
    143    /* Save the signal number in an unused slot.  Later, when a return from the
    144       signal is made, this value is used to inform the tool that the
    145       processing for the given signal has ended. */
    146    VKI_UC_SIGNO(&frame->ucontext) = signo | ((~(UWord)signo & 0xFFFF) << 16);
    147    /* Old context has to point to the saved ucontext. */
    148    tst->os_state.oldcontext = &frame->ucontext;
    149    /* Save ERR and TRAPNO if siguc is present. */
    150    if (siguc) {
    151       frame->ucontext.uc_mcontext.gregs[VKI_REG_ERR]
    152          = siguc->uc_mcontext.gregs[VKI_REG_ERR];
    153       VG_TRACK(post_mem_write, Vg_CoreSignal, tid,
    154                (Addr)&frame->ucontext.uc_mcontext.gregs[VKI_REG_ERR],
    155                sizeof(UWord));
    156       frame->ucontext.uc_mcontext.gregs[VKI_REG_TRAPNO]
    157          = siguc->uc_mcontext.gregs[VKI_REG_TRAPNO];
    158       VG_TRACK(post_mem_write, Vg_CoreSignal, tid,
    159                (Addr)&frame->ucontext.uc_mcontext.gregs[VKI_REG_TRAPNO],
    160                sizeof(UWord));
    161    }
    162 
    163    /* Prepare parameters for a signal handler. */
    164    frame->a1_signo = signo;
    165    /* The first parameter has to be 16-byte aligned, resembling function
    166       calls. */
    167    {
    168       /* Using
    169          vg_assert(VG_IS_16_ALIGNED(&frame->a1_signo));
    170          seems to get miscompiled on amd64 with GCC 4.7.2. */
    171       Addr signo_addr = (Addr)&frame->a1_signo;
    172       vg_assert(VG_IS_16_ALIGNED(signo_addr));
    173    }
    174    frame->a2_siginfo = &frame->siginfo;
    175    VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)&frame->a1_signo,
    176             sizeof(frame->a1_signo) + sizeof(frame->a2_siginfo));
    177 #if defined(VGP_x86_solaris)
    178    frame->a3_ucontext = &frame->ucontext;
    179    VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)&frame->a3_ucontext,
    180             sizeof(frame->a3_ucontext));
    181 #elif defined(VGP_amd64_solaris)
    182    tst->arch.vex.guest_RDI = signo;
    183    VG_TRACK(post_reg_write, Vg_CoreSignal, tid, offsetof(VexGuestAMD64State,
    184             guest_RDI), sizeof(ULong));
    185    tst->arch.vex.guest_RSI = (Addr)&frame->siginfo;
    186    VG_TRACK(post_reg_write, Vg_CoreSignal, tid, offsetof(VexGuestAMD64State,
    187             guest_RSI), sizeof(ULong));
    188    tst->arch.vex.guest_RDX = (Addr)&frame->ucontext;
    189    VG_TRACK(post_reg_write, Vg_CoreSignal, tid, offsetof(VexGuestAMD64State,
    190             guest_RDX), sizeof(ULong));
    191 #endif
    192 
    193    /* Set up the stack pointer. */
    194    vg_assert(esp == (Addr)&frame->return_addr);
    195    VG_(set_SP)(tid, esp);
    196    VG_TRACK(post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(Addr));
    197 
    198    /* Set up the program counter. Note that we don't inform a tool about IP
    199       write because IP is always defined. */
    200    VG_(set_IP)(tid, (Addr)handler);
    201 
    202    /* If the signal is delivered on the alternate stack, copy it out to
    203       ustack.  This has to be done after setting a new IP so the SS_ONSTACK
    204       flag is set by VG_(do_sys_sigaltstack)(). */
    205    if (on_altstack && tst->os_state.ustack
    206        && VG_(am_is_valid_for_client)((Addr)tst->os_state.ustack,
    207                                       sizeof(*tst->os_state.ustack),
    208                                       VKI_PROT_WRITE)) {
    209       SysRes res;
    210       vki_stack_t altstack;
    211 
    212       /* Get information about alternate stack. */
    213       res = VG_(do_sys_sigaltstack)(tid, NULL, &altstack);
    214       vg_assert(!sr_isError(res));
    215 
    216       /* Copy it to ustack. */
    217       *tst->os_state.ustack = altstack;
    218       VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)tst->os_state.ustack,
    219                sizeof(*tst->os_state.ustack));
    220    }
    221 
    222    if (VG_(clo_trace_signals))
    223       VG_(message)(Vg_DebugMsg,
    224                    "sigframe_create (thread %u): next IP=%#lx, "
    225                    "next SP=%#lx\n",
    226                    tid, (Addr)handler, (Addr)frame);
    227 }
    228 
    229 void VG_(sigframe_destroy)(ThreadId tid, Bool isRT)
    230 {
    231    /* Not used on Solaris. */
    232    vg_assert(0);
    233 }
    234 
    235 void VG_(sigframe_return)(ThreadId tid, const vki_ucontext_t *uc)
    236 {
    237    Int signo;
    238 
    239    /* Check if a signal number was saved in the restored context. */
    240    signo = VKI_UC_SIGNO_CONST(uc) & 0xFFFF;
    241    if (!signo || signo != ((~VKI_UC_SIGNO_CONST(uc) >> 16) & 0xFFFF))
    242       return;
    243 
    244    /* Note: The active tool should be informed here about the dead stack area.
    245       However, this was already done when the original context was restored (in
    246       VG_(restore_context)()) so it is not necessary to do it here again.
    247 
    248       There is a small nuance though, VG_(restore_context)() triggers the
    249       die_mem_stack event while in this case, it should really trigger the
    250       die_mem_stack_signal event.  This is not currently a problem because all
    251       official tools handle these two events in the same way.
    252 
    253       If a return from an alternate stack is made then no die_mem_stack event
    254       is currently triggered. */
    255 
    256    /* Returning from a signal handler. */
    257    if (VG_(clo_trace_signals))
    258       VG_(message)(Vg_DebugMsg,
    259                    "sigframe_return (thread %u): IP=%#lx\n",
    260                    tid, VG_(get_IP)(tid));
    261 
    262    /* Tell the tool. */
    263    VG_TRACK(post_deliver_signal, tid, signo);
    264 }
    265 
    266 #endif // defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
    267 
    268 /*--------------------------------------------------------------------*/
    269 /*--- end                                                          ---*/
    270 /*--------------------------------------------------------------------*/
    271