blob: fc8e613c20306ced8544815e170b6854417c665b [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- Create/destroy signal delivery frames. ---*/
/*--- sigframe-mips64-linux.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2010-2013 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_mips64_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;
VexGuestMIPS64State vex_shadow1;
VexGuestMIPS64State 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_sigcontext ( 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);
Int sigNo = siginfo->si_signo;
struct vg_sig_private *priv;
/* Stack must be 16-byte aligned */
sp_top_of_frame &= ~0xf;
sp = sp_top_of_frame - sizeof(struct rt_sigframe);
tst = VG_(get_ThreadState)(tid);
if (!extend(tst, sp, sp_top_of_frame - sp))
return;
sp = VG_ROUNDDN(sp, 16);
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_sigcontext(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_(mips64_linux_SUBST_FOR_rt_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. */
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;
vg_assert(VG_(is_valid_tid)(tid));
tst = VG_(get_ThreadState)(tid);
sp = tst->arch.vex.guest_r29;
struct rt_sigframe *frame = (struct rt_sigframe *)sp;
struct vki_ucontext *ucp = &frame->rs_uc;
frame_size = sizeof(*frame);
mc = &ucp->uc_mcontext;
tst->sig_mask = ucp->uc_sigmask;
tst->tmp_sig_mask = ucp->uc_sigmask;
priv1 = &frame->priv;
sigNo = priv1->sigNo_private;
vg_assert(priv1->magicPI == 0x31415927);
/* 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=%#llx\n",
tid, isRT, tst->arch.vex.guest_PC);
/* tell the tools */
VG_TRACK( post_deliver_signal, tid, sigNo );
}
#endif /* defined(VGP_mips64_linux) */
/*--------------------------------------------------------------------*/
/*--- end sigframe-mips64-linux.c ---*/
/*--------------------------------------------------------------------*/