/*--------------------------------------------------------------------*/
/*--- Create/destroy signal delivery frames. ---*/
/*--- sigframe-x86-darwin.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2006-2015 OpenWorks Ltd
info@open-works.co.uk
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_x86_darwin)
#include "pub_core_basics.h"
#include "pub_core_vki.h"
#include "pub_core_vkiscnums.h"
#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_signals.h"
#include "pub_core_tooliface.h"
#include "pub_core_trampoline.h"
#include "pub_core_sigframe.h" /* self */
#include "priv_sigframe.h"
/* Originally copied from ppc32-aix5 code.
Produce a frame with layout entirely of our own choosing.
This module creates and removes signal frames for signal deliveries
on x86-darwin. The machine state is saved in a ucontext and retrieved
from it later, so the handler can modify it and return.
Frame should have a 16-aligned size, just in case that turns out to
be important for Darwin. (be conservative)
*/
struct hacky_sigframe {
/* first four words look like a call to a 3-arg x86 function */
UInt returnAddr;
UInt a1_signo;
UInt a2_siginfo;
UInt a3_ucontext;
UChar lower_guardzone[512]; // put nothing here
VexGuestX86State vex;
VexGuestX86State vex_shadow1;
VexGuestX86State vex_shadow2;
vki_siginfo_t fake_siginfo;
struct vki_ucontext fake_ucontext;
UInt magicPI;
UInt sigNo_private;
vki_sigset_t mask; // saved sigmask; restore when hdlr returns
UInt __pad[3];
UChar upper_guardzone[512]; // put nothing here
// and don't zero it, since that might overwrite the client's
// stack redzone, at least on archs which have one
};
/* Create a plausible-looking sigcontext from the thread's
Vex guest state. NOTE: does not fill in the FP or SSE
bits of sigcontext at the moment.
*/
static void synthesize_ucontext(ThreadState *tst,
struct vki_ucontext *uc,
const struct vki_ucontext *siguc)
{
VG_(memset)(uc, 0, sizeof(*uc));
if (siguc) uc->uc_sigmask = siguc->uc_sigmask;
uc->uc_stack = tst->altstack;
uc->uc_mcontext = &uc->__mcontext_data;
# define SC2(reg,REG) uc->__mcontext_data.__ss.reg = tst->arch.vex.guest_##REG
SC2(__edi,EDI);
SC2(__esi,ESI);
SC2(__ebp,EBP);
SC2(__ebx,EBX);
SC2(__edx,EDX);
SC2(__eax,EAX);
SC2(__ecx,ECX);
SC2(__esp,ESP);
SC2(__eip,EIP);
uc->__mcontext_data.__ss.__eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
if (siguc)
uc->__mcontext_data.__es = siguc->__mcontext_data.__es;
# undef SC2
}
static void restore_from_ucontext(ThreadState *tst,
const struct vki_ucontext *uc)
{
# define SC2(REG,reg) tst->arch.vex.guest_##REG = uc->__mcontext_data.__ss.reg
SC2(EDI,__edi);
SC2(ESI,__esi);
SC2(EBP,__ebp);
SC2(EBX,__ebx);
SC2(EDX,__edx);
SC2(EAX,__eax);
SC2(ECX,__ecx);
SC2(ESP,__esp);
SC2(EIP,__eip);
/* There doesn't seem to be an easy way to restore eflags */
# undef SC2
}
/* Create a signal frame for thread 'tid'. Make a 3-arg frame
regardless of whether the client originally requested a 1-arg
version (no SA_SIGINFO) or a 3-arg one (SA_SIGINFO) since in the
former case, the x86 calling conventions will simply cause the
extra 2 args to be ignored (inside the handler). */
void VG_(sigframe_create) ( ThreadId tid,
Bool on_altstack,
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 )
{
ThreadState* tst;
Addr esp;
struct hacky_sigframe* frame;
Int sigNo = siginfo->si_signo;
vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
sp_top_of_frame &= ~0xf;
esp = sp_top_of_frame - sizeof(struct hacky_sigframe);
esp -= 4; /* ELF ABI says that esp+4 must be 16 aligned on
entry to a function. */
tst = VG_(get_ThreadState)(tid);
if (! ML_(sf_maybe_extend_stack)(tst, esp, sp_top_of_frame - esp, flags))
return;
vg_assert(VG_IS_16_ALIGNED(esp+4));
frame = (struct hacky_sigframe *) esp;
/* clear it (very conservatively) */
VG_(memset)(&frame->lower_guardzone, 0, sizeof frame->lower_guardzone);
VG_(memset)(&frame->vex, 0, sizeof(VexGuestX86State));
VG_(memset)(&frame->vex_shadow1, 0, sizeof(VexGuestX86State));
VG_(memset)(&frame->vex_shadow2, 0, sizeof(VexGuestX86State));
VG_(memset)(&frame->fake_siginfo, 0, sizeof(frame->fake_siginfo));
VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext));
/* save stuff in frame */
frame->vex = tst->arch.vex;
frame->vex_shadow1 = tst->arch.vex_shadow1;
frame->vex_shadow2 = tst->arch.vex_shadow2;
frame->sigNo_private = sigNo;
frame->mask = tst->sig_mask;
frame->magicPI = 0x31415927;
/* Fill in the siginfo and ucontext. */
synthesize_ucontext(tst, &frame->fake_ucontext, siguc);
frame->fake_siginfo = *siginfo;
/* Set up stack pointer */
vg_assert(esp == (Addr)&frame->returnAddr);
VG_(set_SP)(tid, esp);
VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(UInt));
/* Set up program counter */
VG_(set_IP)(tid, (UInt)handler);
VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(UInt));
/* Set up RA and args for the frame */
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
(Addr)frame, 4*sizeof(UInt) );
frame->returnAddr = (UInt)&VG_(x86_darwin_SUBST_FOR_sigreturn);
frame->a1_signo = sigNo;
frame->a2_siginfo = (UInt) &frame->fake_siginfo;
frame->a3_ucontext = (UInt) &frame->fake_ucontext;
VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
(Addr)frame, 4*sizeof(UInt) );
VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
(Addr)&frame->fake_siginfo, sizeof(frame->fake_siginfo));
VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
(Addr)&frame->fake_ucontext, sizeof(frame->fake_ucontext));
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugMsg,
"sigframe_create (thread %u): "
"next EIP=%#lx, next ESP=%#lx\n",
tid, (Addr)handler, (Addr)frame );
}
/* Remove a signal frame from thread 'tid's stack, and restore the CPU
state from it. Note, isRT is irrelevant here. */
void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
{
ThreadState *tst;
Addr esp;
Int sigNo;
struct hacky_sigframe* frame;
vg_assert(VG_(is_valid_tid)(tid));
tst = VG_(get_ThreadState)(tid);
/* Check that the stack frame looks valid */
esp = VG_(get_SP)(tid);
/* why -4 ? because the signal handler's return will have popped
the return address off the stack; and the return address is the
lowest-addressed element of hacky_sigframe. */
frame = (struct hacky_sigframe*)(esp - 4);
vg_assert(frame->magicPI == 0x31415927);
/* This +4 is because of the -4 referred to in the ELF ABI comment
in VG_(sigframe_create) just above. */
vg_assert(VG_IS_16_ALIGNED((Addr)frame + 4));
/* restore the entire guest state, and shadows, from the frame. */
tst->arch.vex = frame->vex;
tst->arch.vex_shadow1 = frame->vex_shadow1;
tst->arch.vex_shadow2 = frame->vex_shadow2;
restore_from_ucontext(tst, &frame->fake_ucontext);
tst->sig_mask = frame->mask;
tst->tmp_sig_mask = frame->mask;
sigNo = frame->sigNo_private;
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugMsg,
"sigframe_destroy (thread %u): "
"valid magic; next EIP=%#x\n",
tid, tst->arch.vex.guest_EIP);
VG_TRACK( die_mem_stack_signal,
(Addr)frame - VG_STACK_REDZONE_SZB,
sizeof(struct hacky_sigframe) );
/* tell the tools */
VG_TRACK( post_deliver_signal, tid, sigNo );
}
#endif // defined(VGP_x86_darwin)
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/