From: Julian Seward Date: Fri, 8 Jul 2005 18:28:40 +0000 (+0000) Subject: Import sigframe stuff from Paul's tree. With this and the other changes X-Git-Tag: svn/VALGRIND_3_0_0~180 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=eeb4b800cdf5a56d1e9d838e53fa8e03fbfb34fd;p=thirdparty%2Fvalgrind.git Import sigframe stuff from Paul's tree. With this and the other changes today, it's possible to run bash on ppc32-linux. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@4138 --- diff --git a/coregrind/m_sigframe/sigframe-ppc32-linux.c b/coregrind/m_sigframe/sigframe-ppc32-linux.c index 7a086049d0..6d9e00427f 100644 --- a/coregrind/m_sigframe/sigframe-ppc32-linux.c +++ b/coregrind/m_sigframe/sigframe-ppc32-linux.c @@ -8,8 +8,10 @@ This file is part of Valgrind, a dynamic binary instrumentation framework. - Copyright (C) 2005 Nicholas Nethercote - njn25@cam.ac.uk + Copyright (C) 2000-2005 Nicholas Nethercote + njn@valgrind.org + Copyright (C) 2004-2005 Paul Mackerras + paulus@samba.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -42,6 +44,8 @@ #include "pub_core_signals.h" #include "pub_core_tooliface.h" #include "pub_core_trampoline.h" +#include "pub_core_transtab.h" // VG_(discard_translations) +#include "vki_unistd-ppc32-linux.h" // __NR_rt_sigreturn /* This module creates and removes signal frames for signal deliveries @@ -85,66 +89,155 @@ // make assumptions about the locations of various parts of the frame, // so we need to duplicate it exactly. -/* Valgrind-specific parts of the signal frame */ -struct vg_sigframe -{ - /* Sanity check word. */ +/* Structure containing bits of information that we want to save + on signal delivery. */ +struct vg_sig_private { UInt magicPI; - - UInt handlerflags; /* flags for signal handler */ - - - /* Safely-saved version of sigNo, as described above. */ - Int sigNo_private; - - /* XXX This is wrong. Surely we should store the shadow values - into the shadow memory behind the actual values? */ - VexGuestPPC32State vex_shadow; - - /* HACK ALERT */ - VexGuestPPC32State vex; - /* end HACK ALERT */ - - /* saved signal mask to be restored when handler returns */ - vki_sigset_t mask; - - /* Sanity check word. Is the highest-addressed word; do not - move!*/ - UInt magicE; + UInt sigNo_private; + VexGuestPPC32State shadow; }; -struct sigframe -{ - /* Sig handler's return address */ - Addr retaddr; - Int sigNo; - - struct vki_sigcontext sigContext; -//.. struct _vki_fpstate fpstate; +/* Structure put on stack for signal handlers with SA_SIGINFO clear. */ +struct nonrt_sigframe { + UInt gap1[16]; + struct vki_sigcontext sigcontext; + struct vki_mcontext mcontext; + struct vg_sig_private priv; + unsigned char abigap[224]; +}; - struct vg_sigframe vg; +/* Structure put on stack for signal handlers with SA_SIGINFO set. */ +struct rt_sigframe { + UInt gap1[20]; + vki_siginfo_t siginfo; + struct vki_ucontext ucontext; + struct vg_sig_private priv; + unsigned char abigap[224]; }; -struct rt_sigframe +#define SET_SIGNAL_LR(zztst, zzval) \ + do { tst->arch.vex.guest_LR = (zzval); \ + VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, \ + offsetof(VexGuestPPC32State,guest_LR), \ + sizeof(UWord) ); \ + } while (0) + +#define SET_SIGNAL_GPR(zztst, zzn, zzval) \ + do { tst->arch.vex.guest_GPR##zzn = (zzval); \ + VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, \ + offsetof(VexGuestPPC32State,guest_GPR##zzn), \ + sizeof(UWord) ); \ + } while (0) + + +static +void stack_mcontext ( struct vki_mcontext *mc, + ThreadState* tst, + Int ret, + UInt fault_addr ) { - /* Sig handler's return address */ - Addr retaddr; - Int sigNo; - - /* ptr to siginfo_t. */ - Addr psigInfo; - - /* ptr to ucontext */ - Addr puContext; - /* pointed to by psigInfo */ - vki_siginfo_t sigInfo; - - /* pointed to by puContext */ - struct vki_ucontext uContext; -//.. struct _vki_fpstate fpstate; + VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal frame mcontext", + (Addr)mc, sizeof(struct vki_pt_regs) ); + +# define DO(gpr) mc->mc_gregs[VKI_PT_R0+gpr] = tst->arch.vex.guest_GPR##gpr + DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7); + DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15); + DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23); + DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31); +# undef DO + + mc->mc_gregs[VKI_PT_NIP] = tst->arch.vex.guest_CIA; + mc->mc_gregs[VKI_PT_MSR] = 0xf032; /* pretty arbitrary */ + mc->mc_gregs[VKI_PT_ORIG_R3] = tst->arch.vex.guest_GPR3; + mc->mc_gregs[VKI_PT_CTR] = tst->arch.vex.guest_CTR; + mc->mc_gregs[VKI_PT_LNK] = tst->arch.vex.guest_LR; + mc->mc_gregs[VKI_PT_XER] = tst->arch.vex.guest_XER; + mc->mc_gregs[VKI_PT_CCR] = LibVEX_GuestPPC32_get_cr(&tst->arch.vex); + mc->mc_gregs[VKI_PT_MQ] = 0; + mc->mc_gregs[VKI_PT_TRAP] = 0; + mc->mc_gregs[VKI_PT_DAR] = fault_addr; + mc->mc_gregs[VKI_PT_DSISR] = 0; + mc->mc_gregs[VKI_PT_RESULT] = 0; + VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, + (Addr)mc, sizeof(struct vki_pt_regs) ); + + /* XXX should do FP and vector regs */ + + /* set up signal return trampoline */ + VG_TRACK(pre_mem_write, Vg_CoreSignal, tst->tid, "signal frame mcontext", + (Addr)&mc->mc_pad, sizeof(mc->mc_pad)); + mc->mc_pad[0] = 0x38000000U + ret; /* li 0,ret */ + mc->mc_pad[1] = 0x44000002U; /* sc */ + VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, + (Addr)&mc->mc_pad, sizeof(mc->mc_pad) ); + /* invalidate any translation of this area */ + VG_(discard_translations)( (Addr64)(Addr)&mc->mc_pad, + sizeof(mc->mc_pad) ); + + /* set the signal handler to return to the trampoline */ + SET_SIGNAL_LR(tst, (Addr) &mc->mc_pad[0]); +} - struct vg_sigframe vg; -}; +//:: /* Valgrind-specific parts of the signal frame */ +//:: struct vg_sigframe +//:: { +//:: /* Sanity check word. */ +//:: UInt magicPI; +//:: +//:: UInt handlerflags; /* flags for signal handler */ +//:: +//:: +//:: /* Safely-saved version of sigNo, as described above. */ +//:: Int sigNo_private; +//:: +//:: /* XXX This is wrong. Surely we should store the shadow values +//:: into the shadow memory behind the actual values? */ +//:: VexGuestPPC32State vex_shadow; +//:: +//:: /* HACK ALERT */ +//:: VexGuestPPC32State vex; +//:: /* end HACK ALERT */ +//:: +//:: /* saved signal mask to be restored when handler returns */ +//:: vki_sigset_t mask; +//:: +//:: /* Sanity check word. Is the highest-addressed word; do not +//:: move!*/ +//:: UInt magicE; +//:: }; +//:: +//:: struct sigframe +//:: { +//:: /* Sig handler's return address */ +//:: Addr retaddr; +//:: Int sigNo; +//:: +//:: struct vki_sigcontext sigContext; +//:: //.. struct _vki_fpstate fpstate; +//:: +//:: struct vg_sigframe vg; +//:: }; +//:: +//:: struct rt_sigframe +//:: { +//:: /* Sig handler's return address */ +//:: Addr retaddr; +//:: Int sigNo; +//:: +//:: /* ptr to siginfo_t. */ +//:: Addr psigInfo; +//:: +//:: /* ptr to ucontext */ +//:: Addr puContext; +//:: /* pointed to by psigInfo */ +//:: vki_siginfo_t sigInfo; +//:: +//:: /* pointed to by puContext */ +//:: struct vki_ucontext uContext; +//:: //.. struct _vki_fpstate fpstate; +//:: +//:: struct vg_sigframe vg; +//:: }; //:: /*------------------------------------------------------------*/ @@ -393,49 +486,50 @@ struct rt_sigframe //.. SET_THREAD_REG(zztid, zzval, STACK_PTR, post_reg_write, \ //.. Vg_CoreSignal, zztid, VG_O_STACK_PTR, sizeof(Addr)) */ -//.. /* 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; -//.. Segment *stackseg = NULL; -//.. -//.. if (VG_(extend_stack)(addr, tst->client_stack_szB)) { -//.. stackseg = VG_(find_segment)(addr); -//.. if (0 && stackseg) -//.. VG_(printf)("frame=%p seg=%p-%p\n", -//.. addr, stackseg->addr, stackseg->addr+stackseg->len); -//.. } -//.. -//.. if (stackseg == NULL -//.. || (stackseg->prot & (VKI_PROT_READ|VKI_PROT_WRITE)) == 0) { -//.. VG_(message)( -//.. Vg_UserMsg, -//.. "Can't extend stack to %p during signal delivery for thread %d:", -//.. addr, tid); -//.. if (stackseg == NULL) -//.. VG_(message)(Vg_UserMsg, " no stack segment"); -//.. else -//.. VG_(message)(Vg_UserMsg, " too small or bad protection modes"); -//.. -//.. /* 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, size ); -//.. -//.. return True; -//.. } +/* 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; + Segment *stackseg = NULL; + + if (VG_(extend_stack)(addr, tst->client_stack_szB)) { + stackseg = VG_(find_segment)(addr); + if (0 && stackseg) + VG_(printf)("frame=%p seg=%p-%p\n", + addr, stackseg->addr, stackseg->addr+stackseg->len); + } + + if (stackseg == NULL + || (stackseg->prot & (VKI_PROT_READ|VKI_PROT_WRITE)) == 0) { + VG_(message)( + Vg_UserMsg, + "Can't extend stack to %p during signal delivery for thread %d:", + addr, tid); + if (stackseg == NULL) + VG_(message)(Vg_UserMsg, " no stack segment"); + else + VG_(message)(Vg_UserMsg, " too small or bad protection modes"); + + /* 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 ); + + return True; +} //.. /* Build the Valgrind-specific part of a signal frame. */ //.. @@ -566,7 +660,101 @@ void VG_(sigframe_create)( ThreadId tid, const vki_sigset_t *mask, void *restorer ) { - I_die_here; + struct vg_sig_private *priv; + Addr sp; + ThreadState *tst; + Int sigNo = siginfo->si_signo; + Addr faultaddr; + + /* Stack must be 16-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 nonrt_sigframe); + } + + tst = VG_(get_ThreadState)(tid); + + if (!extend(tst, sp, sp_top_of_frame - sp)) + return; + + vg_assert(VG_IS_16_ALIGNED(sp)); + + /* Set up the stack chain pointer */ + VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame", + sp, sizeof(UWord) ); + *(Addr *)sp = tst->arch.vex.guest_GPR1; + VG_TRACK( post_mem_write, Vg_CoreSignal, tid, + sp, sizeof(UWord) ); + + faultaddr = (Addr)siginfo->_sifields._sigfault._addr; + if (sigNo == VKI_SIGILL && siginfo->si_code > 0) + faultaddr = tst->arch.vex.guest_CIA; + + if (flags & VKI_SA_SIGINFO) { + struct rt_sigframe *frame = (struct rt_sigframe *) sp; + struct vki_ucontext *ucp = &frame->ucontext; + + VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame siginfo", + (Addr)&frame->siginfo, sizeof(frame->siginfo) ); + VG_(memcpy)(&frame->siginfo, siginfo, sizeof(*siginfo)); + VG_TRACK( post_mem_write, Vg_CoreSignal, tid, + (Addr)&frame->siginfo, sizeof(frame->siginfo) ); + + VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame ucontext", + (Addr)ucp, offsetof(struct vki_ucontext, uc_pad) ); + 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_pad) ); + + VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame ucontext", + (Addr)&ucp->uc_regs, + sizeof(ucp->uc_regs) + sizeof(ucp->uc_sigmask) ); + ucp->uc_regs = &ucp->uc_mcontext; + ucp->uc_sigmask = tst->sig_mask; + VG_TRACK( post_mem_write, Vg_CoreSignal, tid, + (Addr)&ucp->uc_regs, + sizeof(ucp->uc_regs) + sizeof(ucp->uc_sigmask) ); + + stack_mcontext(&ucp->uc_mcontext, tst, __NR_rt_sigreturn, faultaddr); + priv = &frame->priv; + + SET_SIGNAL_GPR(tid, 4, (Addr) &frame->siginfo); + SET_SIGNAL_GPR(tid, 5, (Addr) ucp); + /* the kernel sets this, though it doesn't seem to be in the ABI */ + SET_SIGNAL_GPR(tid, 6, (Addr) &frame->siginfo); + + } else { + /* non-RT signal delivery */ + struct nonrt_sigframe *frame = (struct nonrt_sigframe *) sp; + struct vki_sigcontext *scp = &frame->sigcontext; + + VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame sigcontext", + (Addr)&scp->_unused[3], sizeof(*scp) - 3 * sizeof(UInt) ); + scp->signal = sigNo; + scp->handler = (Addr) handler; + scp->oldmask = tst->sig_mask.sig[0]; + scp->_unused[3] = tst->sig_mask.sig[1]; + VG_TRACK( post_mem_write, Vg_CoreSignal, tid, + (Addr)&scp->_unused[3], sizeof(*scp) - 3 * sizeof(UInt) ); + + stack_mcontext(&frame->mcontext, tst, __NR_sigreturn, faultaddr); + priv = &frame->priv; + + SET_SIGNAL_GPR(tid, 4, (Addr) scp); + } + + priv->magicPI = 0x31415927; + priv->sigNo_private = sigNo; + priv->shadow = tst->arch.vex_shadow; + + SET_SIGNAL_GPR(tid, 1, sp); + SET_SIGNAL_GPR(tid, 3, sigNo); + tst->arch.vex.guest_CIA = (Addr) handler; //.. Addr esp; //.. ThreadState* tst = VG_(get_ThreadState)(tid); @@ -586,13 +774,14 @@ void VG_(sigframe_create)( ThreadId tid, //.. tst->arch.vex.guest_CIA = (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 %%EIP = %p, status=%d\n", -//.. esp, tst->arch.vex.guest_CIA, tst->status); + + if (0) + VG_(printf)("pushed signal frame; %R1 now = %p, " + "next %%CIA = %p, status=%d\n", + sp, tst->arch.vex.guest_CIA, tst->status); } + /*------------------------------------------------------------*/ /*--- Destroying signal frames ---*/ /*------------------------------------------------------------*/ @@ -669,9 +858,75 @@ void VG_(sigframe_create)( ThreadId tid, //.. } -//.. /* EXPORTED */ -//.. void VG_(sigframe_destroy)( ThreadId tid, Bool isRT ) -//.. { +/* EXPORTED */ +void VG_(sigframe_destroy)( ThreadId tid, Bool isRT ) +{ + ThreadState *tst; + struct vg_sig_private *priv; + Addr sp; + UInt frame_size; + struct vki_mcontext *mc; + Int sigNo; + Bool has_siginfo = isRT; + + vg_assert(VG_(is_valid_tid)(tid)); + tst = VG_(get_ThreadState)(tid); + + /* Check that the stack frame looks valid */ + sp = tst->arch.vex.guest_GPR1; + vg_assert(VG_IS_16_ALIGNED(sp)); + frame_size = *(Addr *)sp - sp; + + if (has_siginfo) { + struct rt_sigframe *frame = (struct rt_sigframe *)sp; + vg_assert(frame_size == sizeof(*frame)); + mc = &frame->ucontext.uc_mcontext; + priv = &frame->priv; + tst->sig_mask = frame->ucontext.uc_sigmask; + } else { + struct nonrt_sigframe *frame = (struct nonrt_sigframe *)sp; + vg_assert(frame_size == sizeof(*frame)); + mc = &frame->mcontext; + priv = &frame->priv; + tst->sig_mask.sig[0] = frame->sigcontext.oldmask; + tst->sig_mask.sig[1] = frame->sigcontext._unused[3]; + } + tst->tmp_sig_mask = tst->sig_mask; + + vg_assert(priv->magicPI == 0x31415927); + sigNo = priv->sigNo_private; + +# define DO(gpr) tst->arch.vex.guest_GPR##gpr = mc->mc_gregs[VKI_PT_R0+gpr] + DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7); + DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15); + DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23); + DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31); +# undef DO + + tst->arch.vex.guest_CIA = mc->mc_gregs[VKI_PT_NIP]; + + // Umm ... ? (jrs 2005 July 8) + // tst->arch.m_orig_gpr3 = mc->mc_gregs[VKI_PT_ORIG_R3]; + + //tst->arch.m_cr = mc->mc_gregs[VKI_PT_CCR]; + LibVEX_GuestPPC32_put_cr( mc->mc_gregs[VKI_PT_CCR], &tst->arch.vex ); + + tst->arch.vex.guest_LR = mc->mc_gregs[VKI_PT_LNK]; + tst->arch.vex.guest_CTR = mc->mc_gregs[VKI_PT_CTR]; + tst->arch.vex.guest_XER = mc->mc_gregs[VKI_PT_XER]; + + tst->arch.vex_shadow = priv->shadow; + + VG_TRACK(die_mem_stack_signal, sp, frame_size); + + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, + "vg_pop_signal_frame (thread %d): isRT=%d valid magic; EIP=%p", + tid, has_siginfo, tst->arch.vex.guest_CIA); + + /* tell the tools */ + VG_TRACK( post_deliver_signal, tid, sigNo ); + //.. Addr esp; //.. ThreadState* tst; //.. SizeT size; @@ -697,7 +952,7 @@ void VG_(sigframe_create)( ThreadId tid, //.. //.. /* tell the tools */ //.. VG_TRACK( post_deliver_signal, tid, sigNo ); -//.. } +} //:: /*------------------------------------------------------------*/ //:: /*--- Making coredumps ---*/