/*--------------------------------------------------------------------*/
/*--- Create/destroy signal delivery frames. ---*/
/*--- sigframe-mips32-linux.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2010-2012 RT-RK
mips-valgrind@rt-rk.com
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.
*/
#if defined(VGP_mips32_linux)
#include "pub_core_basics.h"
#include "pub_core_vki.h"
#include "pub_core_vkiscnums.h"
#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy
#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_sigframe.h"
#include "pub_core_signals.h"
#include "pub_core_tooliface.h"
#include "pub_core_trampoline.h"
#include "pub_core_transtab.h" // VG_(discard_translations)
struct vg_sig_private
{
UInt magicPI;
UInt sigNo_private;
VexGuestMIPS32State vex_shadow1;
VexGuestMIPS32State vex_shadow2;
};
struct sigframe
{
UInt sf_ass[4]; /* argument save space for o32 */
UInt sf_pad[2]; /* Was: signal trampoline */
struct vki_sigcontext sf_sc;
vki_sigset_t sf_mask;
struct vg_sig_private priv;
};
struct rt_sigframe
{
UInt rs_ass[4]; /* argument save space for o32 */
UInt rs_pad[2]; /* Was: signal trampoline */
vki_siginfo_t rs_info;
struct vki_ucontext rs_uc;
struct vg_sig_private priv;
};
/* 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 )
{
ThreadId tid = tst->tid;
NSegment const* stackseg = NULL;
if (VG_(extend_stack)(addr, tst->client_stack_szB))
{
stackseg = VG_(am_find_nsegment)(addr);
}
if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW)
{
VG_(message)(Vg_UserMsg,
"Can't extend stack to %#lx during signal delivery for thread %d:\n",
addr, tid );
if (stackseg == NULL)
VG_(message)( Vg_UserMsg, " no stack segment\n" );
else
VG_(message)( Vg_UserMsg, " too small or bad protection modes\n" );
/* set SIGSEGV to default handler */
VG_(set_default_handler)( VKI_SIGSEGV );
VG_(synth_fault_mapping)( tid, addr );
/* The whole process should be about to die, since the default
action of SIGSEGV to kill the whole process. */
return False;
}
/* For tracking memory events, indicate the entire frame has been
allocated. */
VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB,
size + VG_STACK_REDZONE_SZB, tid );
return True;
}
static
void setup_sigcontext2 ( ThreadState* tst, struct vki_sigcontext **sc1, const vki_siginfo_t *si)
{
struct vki_sigcontext *sc = *sc1;
VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal frame mcontext",
(Addr)sc, sizeof(unsigned long long)*34 );
sc->sc_regs[1] = tst->arch.vex.guest_r1;
sc->sc_regs[2] = tst->arch.vex.guest_r2;
sc->sc_regs[3] = tst->arch.vex.guest_r3;
sc->sc_regs[4] = tst->arch.vex.guest_r4;
sc->sc_regs[5] = tst->arch.vex.guest_r5;
sc->sc_regs[6] = tst->arch.vex.guest_r6;
sc->sc_regs[7] = tst->arch.vex.guest_r7;
sc->sc_regs[8] = tst->arch.vex.guest_r8;
sc->sc_regs[9] = tst->arch.vex.guest_r9;
sc->sc_regs[10] = tst->arch.vex.guest_r10;
sc->sc_regs[11] = tst->arch.vex.guest_r11;
sc->sc_regs[12] = tst->arch.vex.guest_r12;
sc->sc_regs[13] = tst->arch.vex.guest_r13;
sc->sc_regs[14] = tst->arch.vex.guest_r14;
sc->sc_regs[15] = tst->arch.vex.guest_r15;
sc->sc_regs[16] = tst->arch.vex.guest_r16;
sc->sc_regs[17] = tst->arch.vex.guest_r17;
sc->sc_regs[18] = tst->arch.vex.guest_r18;
sc->sc_regs[19] = tst->arch.vex.guest_r19;
sc->sc_regs[20] = tst->arch.vex.guest_r20;
sc->sc_regs[21] = tst->arch.vex.guest_r21;
sc->sc_regs[22] = tst->arch.vex.guest_r22;
sc->sc_regs[23] = tst->arch.vex.guest_r23;
sc->sc_regs[24] = tst->arch.vex.guest_r24;
sc->sc_regs[25] = tst->arch.vex.guest_r25;
sc->sc_regs[26] = tst->arch.vex.guest_r26;
sc->sc_regs[27] = tst->arch.vex.guest_r27;
sc->sc_regs[28] = tst->arch.vex.guest_r28;
sc->sc_regs[29] = tst->arch.vex.guest_r29;
sc->sc_regs[30] = tst->arch.vex.guest_r30;
sc->sc_regs[31] = tst->arch.vex.guest_r31;
sc->sc_pc = tst->arch.vex.guest_PC;
sc->sc_mdhi = tst->arch.vex.guest_HI;
sc->sc_mdlo = tst->arch.vex.guest_LO;
}
/* EXPORTED */
void VG_(sigframe_create)( ThreadId tid,
Addr sp_top_of_frame,
const vki_siginfo_t *siginfo,
const struct vki_ucontext *siguc,
void *handler,
UInt flags,
const vki_sigset_t *mask,
void *restorer )
{
Addr sp;
ThreadState* tst = VG_(get_ThreadState)(tid);
Addr faultaddr;
Int sigNo = siginfo->si_signo;
struct vg_sig_private *priv;
/* Stack must be 8-byte aligned */
sp_top_of_frame &= ~0xf;
if (flags & VKI_SA_SIGINFO)
{
sp = sp_top_of_frame - sizeof(struct rt_sigframe);
}
else
{
sp = sp_top_of_frame - sizeof(struct sigframe);
}
tst = VG_(get_ThreadState)(tid);
if (!extend(tst, sp, sp_top_of_frame - sp))
return;
vg_assert(VG_IS_8_ALIGNED(sp));
/* SIGILL defines addr to be the faulting address */
faultaddr = (Addr)siginfo->_sifields._sigfault._addr;
if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
faultaddr = tst->arch.vex.guest_PC;
if (flags & VKI_SA_SIGINFO)
{
struct rt_sigframe *frame = (struct rt_sigframe *) sp;
struct vki_ucontext *ucp = &frame->rs_uc;
if (VG_(clo_trace_signals))
VG_(printf)("rt_sigframe\n");
/* Create siginfo. */
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame siginfo",
(Addr)&frame->rs_info, sizeof(frame->rs_info) );
VG_(memcpy)(&frame->rs_info, siginfo, sizeof(*siginfo));
VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
(Addr)&frame->rs_info, sizeof(frame->rs_info) );
/* Create the ucontext. */
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame ucontext",
(Addr)ucp, offsetof(struct vki_ucontext, uc_mcontext) );
ucp->uc_flags = 0;
ucp->uc_link = 0;
ucp->uc_stack = tst->altstack;
VG_TRACK( post_mem_write, Vg_CoreSignal, tid, (Addr)ucp,
offsetof(struct vki_ucontext, uc_mcontext) );
struct vki_sigcontext *scp = &(frame->rs_uc.uc_mcontext);
setup_sigcontext2(tst, &(scp), siginfo);
ucp->uc_sigmask = tst->sig_mask;
priv = &frame->priv;
/*
* Arguments to signal handler:
*
* a0 = signal number
* a1 = 0 (should be cause)
* a2 = pointer to ucontext
*
* $25 and c0_epc point to the signal handler, $29 points to
* the struct rt_sigframe.
*/
tst->arch.vex.guest_r4 = siginfo->si_signo;
tst->arch.vex.guest_r5 = (Addr) &frame->rs_info;
tst->arch.vex.guest_r6 = (Addr) &frame->rs_uc;
tst->arch.vex.guest_r29 = (Addr) frame;
tst->arch.vex.guest_r25 = (Addr) handler;
if (flags & VKI_SA_RESTORER)
{
tst->arch.vex.guest_r31 = (Addr) restorer;
}
else
{
tst->arch.vex.guest_r31 = (Addr)&VG_(mips32_linux_SUBST_FOR_rt_sigreturn);
}
}
else
{
if (VG_(clo_trace_signals))
VG_(printf)("sigframe\n");
struct sigframe *frame = (struct sigframe *) sp;
struct vki_sigcontext *scp = &(frame->sf_sc);
setup_sigcontext2(tst, &(scp), siginfo);
frame->sf_mask = tst->sig_mask;
priv = &frame->priv;
/*
* Arguments to signal handler:
*
* a0 = signal number
* a1 = 0 (should be cause)
* a2 = pointer to struct sigcontext
*
* $25 and c0_epc point to the signal handler, $29 points to the
* struct sigframe.
*/
tst->arch.vex.guest_r4 = siginfo->si_signo;
tst->arch.vex.guest_r5 = 0;
tst->arch.vex.guest_r6 = (Addr) &frame->sf_sc;
tst->arch.vex.guest_r29 = (Addr) frame;
tst->arch.vex.guest_r25 = (Addr) handler;
if (flags & VKI_SA_RESTORER)
{
tst->arch.vex.guest_r31 = (Addr) restorer;
}
else
{
tst->arch.vex.guest_r31 = (Addr)&VG_(mips32_linux_SUBST_FOR_sigreturn);
}
}
priv->magicPI = 0x31415927;
priv->sigNo_private = sigNo;
priv->vex_shadow1 = tst->arch.vex_shadow1;
priv->vex_shadow2 = tst->arch.vex_shadow2;
/* Set the thread so it will next run the handler. */
/* tst->m_sp = sp; also notify the tool we've updated SP */
VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(Addr));
if (VG_(clo_trace_signals))
VG_(printf)("handler = %p\n", handler);
tst->arch.vex.guest_PC = (Addr) handler;
/* This thread needs to be marked runnable, but we leave that the
caller to do. */
}
/* EXPORTED */
void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
{
ThreadState *tst;
struct vg_sig_private *priv1;
Addr sp;
UInt frame_size;
struct vki_sigcontext *mc;
Int sigNo;
Bool has_siginfo = isRT;
vg_assert(VG_(is_valid_tid)(tid));
tst = VG_(get_ThreadState)(tid);
sp = tst->arch.vex.guest_r29;
if (has_siginfo)
{
struct rt_sigframe *frame = (struct rt_sigframe *)sp;
struct vki_ucontext *ucp = &frame->rs_uc;
frame_size = sizeof(*frame);
mc = &ucp->uc_mcontext;
priv1 = &frame->priv;
vg_assert(priv1->magicPI == 0x31415927);
sigNo = priv1->sigNo_private;
}
else
{
struct sigframe *frame = (struct sigframe *)sp;
frame_size = sizeof(*frame);
mc = &(frame->sf_sc);
priv1 = &frame->priv;
vg_assert(priv1->magicPI == 0x31415927);
tst->sig_mask = frame->sf_mask;
tst->tmp_sig_mask = tst->sig_mask;
sigNo = priv1->sigNo_private;
}
//restore regs
tst->arch.vex.guest_r1 = mc->sc_regs[1];
tst->arch.vex.guest_r2 = mc->sc_regs[2];
tst->arch.vex.guest_r3 = mc->sc_regs[3];
tst->arch.vex.guest_r4 = mc->sc_regs[4];
tst->arch.vex.guest_r5 = mc->sc_regs[5];
tst->arch.vex.guest_r6 = mc->sc_regs[6];
tst->arch.vex.guest_r7 = mc->sc_regs[7];
tst->arch.vex.guest_r8 = mc->sc_regs[8];
tst->arch.vex.guest_r9 = mc->sc_regs[9];
tst->arch.vex.guest_r10 = mc->sc_regs[10];
tst->arch.vex.guest_r11 = mc->sc_regs[11];
tst->arch.vex.guest_r12 = mc->sc_regs[12];
tst->arch.vex.guest_r13= mc->sc_regs[13];
tst->arch.vex.guest_r14 = mc->sc_regs[14];
tst->arch.vex.guest_r15 = mc->sc_regs[15];
tst->arch.vex.guest_r16 = mc->sc_regs[16];
tst->arch.vex.guest_r17 = mc->sc_regs[17];
tst->arch.vex.guest_r18 = mc->sc_regs[18];
tst->arch.vex.guest_r19 = mc->sc_regs[19];
tst->arch.vex.guest_r20 = mc->sc_regs[20];
tst->arch.vex.guest_r21 = mc->sc_regs[21];
tst->arch.vex.guest_r22 = mc->sc_regs[22];
tst->arch.vex.guest_r23 = mc->sc_regs[23];
tst->arch.vex.guest_r24 = mc->sc_regs[24];
tst->arch.vex.guest_r25 = mc->sc_regs[25];
tst->arch.vex.guest_r26 = mc->sc_regs[26];
tst->arch.vex.guest_r27 = mc->sc_regs[27];
tst->arch.vex.guest_r28 = mc->sc_regs[28];
tst->arch.vex.guest_r30 = mc->sc_regs[30];
tst->arch.vex.guest_PC = mc->sc_pc;
tst->arch.vex.guest_r31 = mc->sc_regs[31];
tst->arch.vex.guest_r29 = mc->sc_regs[29];
tst->arch.vex.guest_HI = mc->sc_mdhi;
tst->arch.vex.guest_LO = mc->sc_mdlo;
tst->arch.vex_shadow1 = priv1->vex_shadow1;
tst->arch.vex_shadow2 = priv1->vex_shadow2;
VG_TRACK(die_mem_stack_signal, sp, frame_size);
if (VG_(clo_trace_signals))
VG_(message)( Vg_DebugMsg,
"VG_(signal_return) (thread %d): isRT=%d valid magic; EIP=%#x\n",
tid, isRT, tst->arch.vex.guest_PC);
/* tell the tools */
VG_TRACK( post_deliver_signal, tid, sigNo );
}
#endif // defined(VGP_mips32_linux)
/*--------------------------------------------------------------------*/
/*--- end sigframe-mips32-linux.c ---*/
/*--------------------------------------------------------------------*/