mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-11 05:55:48 +00:00
signal frames. This commit looks worse than it is -- really just a load of moving-code-around. This is the first multiple-implementation module, in that it has a single interface (pub_core_sigframe.h) but multiple implementations, depending on the os-cpu pair. All the grotty details are hidden in the implementation in m_sigframe/; callers need be aware only of the interface. Yay. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3556
313 lines
10 KiB
C
313 lines
10 KiB
C
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- Arch-specific signals stuff. arm/signals.c ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2000-2005 Nicholas Nethercote
|
|
njn25@cam.ac.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.
|
|
*/
|
|
|
|
#include "core.h"
|
|
|
|
#include "libvex_guest_arm.h"
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Signal frame ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
// A structure in which to save the application's registers
|
|
// during the execution of signal handlers.
|
|
|
|
#if 0
|
|
typedef
|
|
struct {
|
|
/* There are two different stack frame formats, depending on
|
|
whether the client set the SA_SIGINFO flag for the handler.
|
|
This structure is put onto the client's stack as part of
|
|
signal delivery, and therefore appears as the signal
|
|
handler's arguments.
|
|
|
|
The first two words are common for both frame formats -
|
|
they're the return address and the signal number. */
|
|
|
|
/* Sig handler's (bogus) return address */
|
|
Addr retaddr;
|
|
/* The arg to the sig handler. We need to inspect this after
|
|
the handler returns, but it's unreasonable to assume that the
|
|
handler won't change it. So we keep a second copy of it in
|
|
sigNo_private. */
|
|
Int sigNo;
|
|
|
|
/* This is where the two frames start differing. */
|
|
union {
|
|
struct { /* set SA_SIGINFO */
|
|
/* ptr to siginfo_t. */
|
|
Addr psigInfo;
|
|
|
|
/* ptr to ucontext */
|
|
Addr puContext;
|
|
} sigInfo;
|
|
struct vki_sigcontext sigContext; /* did not set SA_SIGINFO */
|
|
} handlerArgs;
|
|
|
|
/* The rest are private fields which the handler is unaware of. */
|
|
|
|
/* Sanity check word. */
|
|
UInt magicPI;
|
|
/* pointed to by psigInfo */
|
|
vki_siginfo_t sigInfo;
|
|
/* pointed to by puContext */
|
|
struct vki_ucontext uContext;
|
|
|
|
/* Safely-saved version of sigNo, as described above. */
|
|
Int sigNo_private;
|
|
|
|
/* Saved processor state. */
|
|
VexGuestX86State vex;
|
|
VexGuestX86State vex_shadow;
|
|
|
|
/* saved signal mask to be restored when handler returns */
|
|
vki_sigset_t mask;
|
|
|
|
/* Scheduler-private stuff: what was the thread's status prior to
|
|
delivering this signal? */
|
|
ThreadStatus status;
|
|
void* /*pthread_mutex_t* */ associated_mx;
|
|
void* /*pthread_cond_t* */ associated_cv;
|
|
|
|
/* Sanity check word. Is the highest-addressed word; do not
|
|
move!*/
|
|
UInt magicE;
|
|
}
|
|
VgSigFrame;
|
|
#endif
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Signal operations ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
#if 0
|
|
/* Make up a plausible-looking thread state from the thread's current state */
|
|
static void synth_ucontext(ThreadId tid, const vki_siginfo_t *si,
|
|
const vki_sigset_t *set, struct vki_ucontext *uc)
|
|
{
|
|
ThreadState *tst = VG_(get_ThreadState)(tid);
|
|
struct vki_sigcontext *sc = &uc->uc_mcontext;
|
|
|
|
VG_(memset)(uc, 0, sizeof(*uc));
|
|
|
|
uc->uc_flags = 0;
|
|
uc->uc_link = 0;
|
|
uc->uc_sigmask = *set;
|
|
uc->uc_stack = tst->altstack;
|
|
|
|
#define SC2(reg,REG) sc->reg = tst->arch.vex.guest_##REG
|
|
SC2(gs,GS);
|
|
SC2(fs,FS);
|
|
SC2(es,ES);
|
|
SC2(ds,DS);
|
|
|
|
SC2(edi,EDI);
|
|
SC2(esi,ESI);
|
|
SC2(ebp,EBP);
|
|
SC2(esp,ESP);
|
|
SC2(ebx,EBX);
|
|
SC2(edx,EDX);
|
|
SC2(ecx,ECX);
|
|
SC2(eax,EAX);
|
|
|
|
SC2(eip,EIP);
|
|
SC2(cs,CS);
|
|
sc->eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
|
|
SC2(ss,SS);
|
|
/* XXX esp_at_signal */
|
|
/* XXX trapno */
|
|
/* XXX err */
|
|
#undef SC2
|
|
|
|
sc->cr2 = (UInt)si->_sifields._sigfault._addr;
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
#define SET_SIGNAL_ESP(zztid, zzval) \
|
|
SET_THREAD_REG(zztid, zzval, VGA_STACK_PTR, VGA_R_STACK_PTR, \
|
|
post_reg_write_deliver_signal)
|
|
#endif
|
|
|
|
void VGA_(push_signal_frame)(ThreadId tid, Addr esp_top_of_frame,
|
|
const vki_siginfo_t *siginfo,
|
|
void *handler, UInt flags,
|
|
const vki_sigset_t *mask)
|
|
{
|
|
I_die_here;
|
|
#if 0
|
|
Addr esp;
|
|
ThreadState* tst;
|
|
VgSigFrame* frame;
|
|
Int sigNo = siginfo->si_signo;
|
|
|
|
esp = esp_top_of_frame;
|
|
esp -= sizeof(VgSigFrame);
|
|
frame = (VgSigFrame*)esp;
|
|
|
|
tst = & VG_(threads)[tid];
|
|
|
|
/* For tracking memory events, indicate the entire frame has been
|
|
* allocated, but pretend that only the first four words are written */
|
|
VG_TRACK( new_mem_stack_signal, (Addr)frame, sizeof(VgSigFrame) );
|
|
|
|
/* Assert that the frame is placed correctly. */
|
|
vg_assert( (sizeof(VgSigFrame) & 0x3) == 0 );
|
|
vg_assert( ((Char*)(&frame->magicE)) + sizeof(UInt)
|
|
== ((Char*)(esp_top_of_frame)) );
|
|
|
|
/* retaddr, sigNo, psigInfo, puContext fields are to be written */
|
|
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
|
|
(Addr)frame, offsetof(VgSigFrame, handlerArgs) );
|
|
frame->retaddr = (UInt)VG_(client_trampoline_code)+VG_(tramp_sigreturn_offset);
|
|
frame->sigNo = sigNo;
|
|
frame->sigNo_private = sigNo;
|
|
VG_TRACK( post_mem_write, (Addr)frame, offsetof(VgSigFrame, handlerArgs) );
|
|
|
|
if (flags & VKI_SA_SIGINFO) {
|
|
/* if the client asked for a siginfo delivery, then build the stack that way */
|
|
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)",
|
|
(Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigInfo) );
|
|
frame->handlerArgs.sigInfo.psigInfo = (Addr)&frame->sigInfo;
|
|
frame->handlerArgs.sigInfo.puContext = (Addr)&frame->uContext;
|
|
VG_TRACK( post_mem_write, (Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigInfo) );
|
|
|
|
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)",
|
|
(Addr)&frame->sigInfo, sizeof(frame->sigInfo) );
|
|
VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t));
|
|
VG_TRACK( post_mem_write, (Addr)&frame->sigInfo, sizeof(frame->sigInfo) );
|
|
|
|
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)",
|
|
(Addr)&frame->uContext, sizeof(frame->uContext) );
|
|
synth_ucontext(tid, siginfo, mask, &frame->uContext);
|
|
VG_TRACK( post_mem_write, (Addr)&frame->uContext, sizeof(frame->uContext) );
|
|
} else {
|
|
struct vki_ucontext uc;
|
|
|
|
/* otherwise just put the sigcontext there */
|
|
|
|
synth_ucontext(tid, siginfo, mask, &uc);
|
|
|
|
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (sigcontext)",
|
|
(Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigContext) );
|
|
VG_(memcpy)(&frame->handlerArgs.sigContext, &uc.uc_mcontext,
|
|
sizeof(struct vki_sigcontext));
|
|
VG_TRACK( post_mem_write, (Addr)&frame->handlerArgs,
|
|
sizeof(frame->handlerArgs.sigContext) );
|
|
|
|
frame->handlerArgs.sigContext.oldmask = tst->sig_mask.sig[0];
|
|
}
|
|
|
|
frame->magicPI = 0x31415927;
|
|
|
|
frame->vex = tst->arch.vex;
|
|
if (VG_(needs).shadow_regs)
|
|
frame->vex_shadow = tst->arch.vex_shadow;
|
|
|
|
frame->mask = tst->sig_mask;
|
|
|
|
/* If the thread is currently blocked in a syscall, we want it to
|
|
resume as runnable. */
|
|
if (tst->status == VgTs_WaitSys)
|
|
frame->status = VgTs_Runnable;
|
|
else
|
|
frame->status = tst->status;
|
|
|
|
frame->associated_mx = tst->associated_mx;
|
|
frame->associated_cv = tst->associated_cv;
|
|
|
|
frame->magicE = 0x27182818;
|
|
|
|
/* Ensure 'tid' and 'tst' correspond */
|
|
vg_assert(& VG_(threads)[tid] == tst);
|
|
/* Set the thread so it will next run the handler. */
|
|
/* tst->m_esp = esp; */
|
|
SET_SIGNAL_ESP(tid, esp);
|
|
|
|
tst->arch.vex.guest_EIP = (Addr) handler;
|
|
/* This thread needs to be marked runnable, but we leave that the
|
|
caller to do. */
|
|
|
|
if (0)
|
|
VG_(printf)("pushed signal frame; %%ESP now = %p, next %%EBP = %p, status=%d\n",
|
|
esp, tst->arch.vex.guest_EIP, tst->status);
|
|
#endif
|
|
}
|
|
|
|
Int VGA_(pop_signal_frame)(ThreadId tid)
|
|
{
|
|
I_die_here;
|
|
#if 0
|
|
Addr esp;
|
|
VgSigFrame* frame;
|
|
ThreadState* tst;
|
|
|
|
vg_assert(VG_(is_valid_tid)(tid));
|
|
tst = & VG_(threads)[tid];
|
|
|
|
/* Correctly reestablish the frame base address. */
|
|
esp = tst->arch.vex.guest_ESP;
|
|
frame = (VgSigFrame*)
|
|
(esp -4 /* because the handler's RET pops the RA */
|
|
+20 /* because signalreturn_bogusRA pushes 5 words */);
|
|
|
|
vg_assert(frame->magicPI == 0x31415927);
|
|
vg_assert(frame->magicE == 0x27182818);
|
|
if (VG_(clo_trace_signals))
|
|
VG_(message)(Vg_DebugMsg,
|
|
"vg_pop_signal_frame (thread %d): valid magic; EIP=%p", tid, frame->vex.guest_EIP);
|
|
|
|
/* Mark the frame structure as nonaccessible. */
|
|
VG_TRACK( die_mem_stack_signal, (Addr)frame, sizeof(VgSigFrame) );
|
|
|
|
/* restore machine state */
|
|
tst->arch.vex = frame->vex;
|
|
if (VG_(needs).shadow_regs)
|
|
tst->arch.vex_shadow = frame->vex_shadow;
|
|
|
|
/* And restore the thread's status to what it was before the signal
|
|
was delivered. */
|
|
tst->status = frame->status;
|
|
|
|
tst->associated_mx = frame->associated_mx;
|
|
tst->associated_cv = frame->associated_cv;
|
|
|
|
tst->sig_mask = frame->mask;
|
|
|
|
/* don't use the copy exposed to the handler; it might have changed
|
|
it. */
|
|
return frame->sigNo_private;
|
|
#endif
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end ---*/
|
|
/*--------------------------------------------------------------------*/
|