1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Create/destroy signal delivery frames.                       ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                       sigframe-ppc32-linux.c ---*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2000-2011 Nicholas Nethercote
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      njn@valgrind.org
13b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2004-2011 Paul Mackerras
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      paulus@samba.org
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_ppc32_linux)
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h"
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h"
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vkiscnums.h"
39b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_core_libcsetjmp.h"    // to keep _threadstate.h happy
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_threadstate.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_aspacemgr.h"
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h"
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h"
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h"
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_machine.h"
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_options.h"
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_sigframe.h"
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_signals.h"
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_tooliface.h"
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_trampoline.h"
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_transtab.h"      // VG_(discard_translations)
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This module creates and removes signal frames for signal deliveries
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   on ppc32-linux.
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note, this file contains kernel-specific knowledge in the form of
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'struct sigframe' and 'struct rt_sigframe'.  How does that relate
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to the vki kernel interface stuff?
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Either a 'struct sigframe' or a 'struct rtsigframe' is pushed
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   onto the client's stack.  This contains a subsidiary
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vki_ucontext.  That holds the vcpu's state across the signal,
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   so that the sighandler can mess with the vcpu state if it
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   really wants.
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FIXME: sigcontexting is basically broken for the moment.  When
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delivering a signal, the integer registers and %eflags are
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   correctly written into the sigcontext, however the FP and SSE state
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is not.  When returning from a signal, only the integer registers
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   are restored from the sigcontext; the rest of the CPU state is
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   restored to what it was before the signal.
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This will be fixed.
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Signal frame layouts                                 ---*/
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// A structure in which to save the application's registers
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// during the execution of signal handlers.
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Linux has 2 signal frame structures: one for normal signal
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// deliveries, and one for SA_SIGINFO deliveries (also known as RT
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// signals).
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// In theory, so long as we get the arguments to the handler function
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// right, it doesn't matter what the exact layout of the rest of the
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// frame is.  Unfortunately, things like gcc's exception unwinding
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// make assumptions about the locations of various parts of the frame,
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// so we need to duplicate it exactly.
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Structure containing bits of information that we want to save
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   on signal delivery. */
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct vg_sig_private {
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt magicPI;
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt sigNo_private;
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC32State vex_shadow1;
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC32State vex_shadow2;
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Structure put on stack for signal handlers with SA_SIGINFO clear. */
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct nonrt_sigframe {
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt gap1[16];
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vki_sigcontext sigcontext;
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vki_mcontext mcontext;
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_sig_private priv;
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unsigned char abigap[224];
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Structure put on stack for signal handlers with SA_SIGINFO set. */
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct rt_sigframe {
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt gap1[20];
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vki_siginfo_t siginfo;
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vki_ucontext ucontext;
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_sig_private priv;
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unsigned char abigap[224];
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SET_SIGNAL_LR(zztst, zzval)                          \
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do { tst->arch.vex.guest_LR = (zzval);                    \
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,     \
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                offsetof(VexGuestPPC32State,guest_LR),       \
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sizeof(UWord) );                             \
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } while (0)
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SET_SIGNAL_GPR(zztst, zzn, zzval)                    \
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do { tst->arch.vex.guest_GPR##zzn = (zzval);              \
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,     \
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                offsetof(VexGuestPPC32State,guest_GPR##zzn), \
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sizeof(UWord) );                             \
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } while (0)
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid stack_mcontext ( struct vki_mcontext *mc,
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      ThreadState* tst,
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Bool use_rt_sigreturn,
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      UInt fault_addr )
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal frame mcontext",
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (Addr)mc, sizeof(struct vki_pt_regs) );
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define DO(gpr)  mc->mc_gregs[VKI_PT_R0+gpr] = tst->arch.vex.guest_GPR##gpr
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO(0);  DO(1);  DO(2);  DO(3);  DO(4);  DO(5);  DO(6);  DO(7);
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO(8);  DO(9);  DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef DO
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_NIP]     = tst->arch.vex.guest_CIA;
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_MSR]     = 0xf032;   /* pretty arbitrary */
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_ORIG_R3] = tst->arch.vex.guest_GPR3;
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_CTR]     = tst->arch.vex.guest_CTR;
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_LNK]     = tst->arch.vex.guest_LR;
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_XER]     = LibVEX_GuestPPC32_get_XER(&tst->arch.vex);
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_CCR]     = LibVEX_GuestPPC32_get_CR(&tst->arch.vex);
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_MQ]      = 0;
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_TRAP]    = 0;
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_DAR]     = fault_addr;
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_DSISR]   = 0;
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_gregs[VKI_PT_RESULT]  = 0;
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid,
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (Addr)mc, sizeof(struct vki_pt_regs) );
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* XXX should do FP and vector regs */
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* set up signal return trampoline */
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* NB.  5 Sept 07.  mc->mc_pad[0..1] used to contain a the code to
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      which the signal handler returns, and it just did sys_sigreturn
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      or sys_rt_sigreturn.  But this doesn't work if the stack is
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      non-executable, and it isn't consistent with the x86-linux and
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      amd64-linux scheme for removing the stack frame.  So instead be
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      consistent and use a stub in m_trampoline.  Then it doesn't
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      matter whether or not the (guest) stack is executable.  This
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fixes #149519 and #145837. */
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK(pre_mem_write, Vg_CoreSignal, tst->tid, "signal frame mcontext",
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (Addr)&mc->mc_pad, sizeof(mc->mc_pad));
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_pad[0] = 0; /* invalid */
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->mc_pad[1] = 0; /* invalid */
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_mem_write,  Vg_CoreSignal, tst->tid,
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (Addr)&mc->mc_pad, sizeof(mc->mc_pad) );
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* invalidate any translation of this area */
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(discard_translations)( (Addr64)(Addr)&mc->mc_pad,
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              sizeof(mc->mc_pad), "stack_mcontext" );
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* set the signal handler to return to the trampoline */
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SET_SIGNAL_LR(tst, (Addr)(use_rt_sigreturn
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               ? (Addr)&VG_(ppc32_linux_SUBST_FOR_rt_sigreturn)
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               : (Addr)&VG_(ppc32_linux_SUBST_FOR_sigreturn)
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      ));
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: /* Valgrind-specific parts of the signal frame */
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: struct vg_sigframe
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* Sanity check word. */
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    UInt magicPI;
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    UInt handlerflags;	/* flags for signal handler */
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* Safely-saved version of sigNo, as described above. */
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    Int  sigNo_private;
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* XXX This is wrong.  Surely we should store the shadow values
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       into the shadow memory behind the actual values? */
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    VexGuestPPC32State vex_shadow;
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* HACK ALERT */
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    VexGuestPPC32State vex;
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* end HACK ALERT */
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* saved signal mask to be restored when handler returns */
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    vki_sigset_t	mask;
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* Sanity check word.  Is the highest-addressed word; do not
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       move!*/
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    UInt magicE;
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: };
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: struct sigframe
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* Sig handler's return address */
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    Addr retaddr;
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    Int  sigNo;
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    struct vki_sigcontext sigContext;
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: //..    struct _vki_fpstate fpstate;
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    struct vg_sigframe vg;
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: };
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: struct rt_sigframe
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* Sig handler's return address */
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    Addr retaddr;
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    Int  sigNo;
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* ptr to siginfo_t. */
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    Addr psigInfo;
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* ptr to ucontext */
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    Addr puContext;
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* pointed to by psigInfo */
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    vki_siginfo_t sigInfo;
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* pointed to by puContext */
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    struct vki_ucontext uContext;
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: //..    struct _vki_fpstate fpstate;
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    struct vg_sigframe vg;
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: };
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: /*------------------------------------------------------------*/
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: /*--- Signal operations                                    ---*/
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: /*------------------------------------------------------------*/
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: /*
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    Great gobs of FP state conversion taken wholesale from
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    linux/arch/i386/kernel/i387.c
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::  */
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: /*
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::  * FXSR floating point environment conversions.
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::  */
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: #define X86_FXSR_MAGIC		0x0000
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: /*
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::  * FPU tag word conversions.
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::  */
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    unsigned int tmp; /* to avoid 16 bit prefixes in the code */
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* Transform each pair of bits into 01 (valid) or 00 (empty) */
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    tmp = ~twd;
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* and move the valid bits to the lower byte. */
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    return tmp;
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: }
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: static unsigned long twd_fxsr_to_i387( const struct i387_fxsave_struct *fxsave )
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    struct _vki_fpxreg *st = NULL;
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    unsigned long twd = (unsigned long) fxsave->twd;
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    unsigned long tag;
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    unsigned long ret = 0xffff0000u;
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    int i;
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: #define FPREG_ADDR(f, n)	((char *)&(f)->st_space + (n) * 16);
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    for ( i = 0 ; i < 8 ; i++ ) {
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       if ( twd & 0x1 ) {
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	 st = (struct _vki_fpxreg *) FPREG_ADDR( fxsave, i );
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	 switch ( st->exponent & 0x7fff ) {
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	 case 0x7fff:
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	    tag = 2;		/* Special */
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	    break;
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	 case 0x0000:
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	    if ( !st->significand[0] &&
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 		 !st->significand[1] &&
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 		 !st->significand[2] &&
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 		 !st->significand[3] ) {
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	       tag = 1;	/* Zero */
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	    } else {
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	       tag = 2;	/* Special */
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	    }
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	    break;
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	 default:
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	    if ( st->significand[3] & 0x8000 ) {
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	       tag = 0;	/* Valid */
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	    } else {
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	       tag = 2;	/* Special */
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	    }
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	    break;
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	 }
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       } else {
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	 tag = 3;			/* Empty */
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       }
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       ret |= (tag << (2 * i));
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       twd = twd >> 1;
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    }
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    return ret;
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: }
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: static void convert_fxsr_to_user( struct _vki_fpstate *buf,
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 				  const struct i387_fxsave_struct *fxsave )
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    unsigned long env[7];
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    struct _vki_fpreg *to;
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    struct _vki_fpxreg *from;
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    int i;
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul;
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    env[1] = (unsigned long)fxsave->swd | 0xffff0000ul;
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    env[2] = twd_fxsr_to_i387(fxsave);
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    env[3] = fxsave->fip;
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    env[5] = fxsave->foo;
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    env[6] = fxsave->fos;
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    VG_(memcpy)(buf, env, 7 * sizeof(unsigned long));
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    to = &buf->_st[0];
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    from = (struct _vki_fpxreg *) &fxsave->st_space[0];
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       unsigned long __user *t = (unsigned long __user *)to;
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       unsigned long *f = (unsigned long *)from;
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       t[0] = f[0];
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       t[1] = f[1];
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       to->exponent = from->exponent;
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    }
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: }
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: static void convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 				    const struct _vki_fpstate *buf )
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    unsigned long env[7];
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    struct _vki_fpxreg *to;
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    const struct _vki_fpreg *from;
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    int i;
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    VG_(memcpy)(env, buf, 7 * sizeof(long));
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    fxsave->cwd = (unsigned short)(env[0] & 0xffff);
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    fxsave->swd = (unsigned short)(env[1] & 0xffff);
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    fxsave->fip = env[3];
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16);
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    fxsave->fcs = (env[4] & 0xffff);
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    fxsave->foo = env[5];
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    fxsave->fos = env[6];
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    to = (struct _vki_fpxreg *) &fxsave->st_space[0];
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    from = &buf->_st[0];
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       unsigned long *t = (unsigned long *)to;
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       unsigned long __user *f = (unsigned long __user *)from;
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       t[0] = f[0];
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       t[1] = f[1];
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       to->exponent = from->exponent;
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    }
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: }
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: static inline void save_i387_fsave( arch_thread_t *regs, struct _vki_fpstate *buf )
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    struct i387_fsave_struct *fs = &regs->m_sse.fsave;
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    fs->status = fs->swd;
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    VG_(memcpy)(buf, fs, sizeof(*fs));
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: }
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: static void save_i387_fxsave( arch_thread_t *regs, struct _vki_fpstate *buf )
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    const struct i387_fxsave_struct *fx = &regs->m_sse.fxsave;
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    convert_fxsr_to_user( buf, fx );
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    buf->status = fx->swd;
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    buf->magic = X86_FXSR_MAGIC;
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    VG_(memcpy)(buf->_fxsr_env, fx, sizeof(struct i387_fxsave_struct));
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: }
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: static void save_i387( arch_thread_t *regs, struct _vki_fpstate *buf )
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    if ( VG_(have_ssestate) )
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       save_i387_fxsave( regs, buf );
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    else
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       save_i387_fsave( regs, buf );
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: }
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: static inline void restore_i387_fsave( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    VG_(memcpy)( &regs->m_sse.fsave, buf, sizeof(struct i387_fsave_struct) );
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: }
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: static void restore_i387_fxsave( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    VG_(memcpy)(&regs->m_sse.fxsave, &buf->_fxsr_env[0],
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: 	       sizeof(struct i387_fxsave_struct) );
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    /* mxcsr reserved bits must be masked to zero for security reasons */
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    regs->m_sse.fxsave.mxcsr &= 0xffbf;
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    convert_fxsr_from_user( &regs->m_sse.fxsave, buf );
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: }
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: static void restore_i387( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: {
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    if ( VG_(have_ssestate) ) {
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       restore_i387_fxsave( regs, buf );
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    } else {
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::       restore_i387_fsave( regs, buf );
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//::    }
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//:: }
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Creating signal frames                               ---*/
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. /* Create a plausible-looking sigcontext from the thread's
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Vex guest state.  NOTE: does not fill in the FP or SSE
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    bits of sigcontext at the moment.
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. */
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. void synth_ucontext(ThreadId tid, const vki_siginfo_t *si,
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                     const vki_sigset_t *set, struct vki_ucontext *uc)
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    ThreadState *tst = VG_(get_ThreadState)(tid);
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    struct vki_sigcontext *sc = &uc->uc_mcontext;
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    VG_(memset)(uc, 0, sizeof(*uc));
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    uc->uc_flags = 0;
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    uc->uc_link = 0;
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    uc->uc_sigmask = *set;
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    uc->uc_stack = tst->altstack;
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    sc->fpstate = fpstate;
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    // FIXME: save_i387(&tst->arch, fpstate);
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #  define SC2(reg,REG)  sc->reg = tst->arch.vex.guest_##REG
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(gs,GS);
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(fs,FS);
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(es,ES);
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(ds,DS);
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(edi,EDI);
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(esi,ESI);
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(ebp,EBP);
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(esp,ESP);
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(ebx,EBX);
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(edx,EDX);
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(ecx,ECX);
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(eax,EAX);
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(eip,EIP);
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(cs,CS);
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    sc->eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SC2(ss,SS);
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* XXX esp_at_signal */
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* XXX trapno */
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* XXX err */
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #  undef SC2
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    sc->cr2 = (UInt)si->_sifields._sigfault._addr;
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define SET_SIGNAL_ESP(zztid, zzval) \
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SET_THREAD_REG(zztid, zzval, STACK_PTR, post_reg_write, \
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                   Vg_CoreSignal, zztid, VG_O_STACK_PTR, sizeof(Addr))
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Extend the stack segment downwards if needed so as to ensure the
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   new signal frames are mapped to something.  Return a Bool
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   indicating whether or not the operation was successful.
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool extend ( ThreadState *tst, Addr addr, SizeT size )
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId        tid = tst->tid;
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NSegment const* stackseg = NULL;
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stackseg = VG_(am_find_nsegment)(addr);
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 && stackseg)
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		     addr, stackseg->start, stackseg->end);
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) {
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Vg_UserMsg,
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "Can't extend stack to %#lx during signal delivery for thread %d:\n",
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr, tid);
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (stackseg == NULL)
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg, "  no stack segment\n");
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg, "  too small or bad protection modes\n");
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set SIGSEGV to default handler */
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(set_default_handler)(VKI_SIGSEGV);
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(synth_fault_mapping)(tid, addr);
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The whole process should be about to die, since the default
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 action of SIGSEGV to kill the whole process. */
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* For tracking memory events, indicate the entire frame has been
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allocated. */
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB,
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             size + VG_STACK_REDZONE_SZB, tid );
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. /* Build the Valgrind-specific part of a signal frame. */
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static void build_vg_sigframe(struct vg_sigframe *frame,
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			      ThreadState *tst,
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			      const vki_sigset_t *mask,
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			      UInt flags,
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			      Int sigNo)
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->sigNo_private = sigNo;
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->magicPI       = 0x31415927;
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->vex_shadow    = tst->arch.vex_shadow;
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* HACK ALERT */
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->vex           = tst->arch.vex;
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* end HACK ALERT */
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->mask          = tst->sig_mask;
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->handlerflags  = flags;
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->magicE        = 0x27182818;
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static Addr build_sigframe(ThreadState *tst,
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			   Addr esp_top_of_frame,
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			   const vki_siginfo_t *siginfo,
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			   void *handler, UInt flags,
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			   const vki_sigset_t *mask,
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			   void *restorer)
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    struct sigframe *frame;
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Addr esp = esp_top_of_frame;
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Int	sigNo = siginfo->si_signo;
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    struct vki_ucontext uc;
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    vg_assert((flags & VKI_SA_SIGINFO) == 0);
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    esp -= sizeof(*frame);
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    esp = ROUNDDN(esp, 16);
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame = (struct sigframe *)esp;
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (!extend(tst, esp, sizeof(*frame)))
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       return esp_top_of_frame;
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* retaddr, sigNo, siguContext fields are to be written */
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame",
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 	     esp, offsetof(struct sigframe, vg) );
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->sigNo = sigNo;
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (flags & VKI_SA_RESTORER)
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       frame->retaddr = (Addr)restorer;
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    else
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       frame->retaddr
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          = VG_(client_trampoline_code)+VG_(tramp_sigreturn_offset);
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    synth_ucontext(tst->tid, siginfo, mask, &uc, &frame->fpstate);
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    VG_(memcpy)(&frame->sigContext, &uc.uc_mcontext,
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 	       sizeof(struct vki_sigcontext));
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->sigContext.oldmask = mask->sig[0];
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid,
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..              esp, offsetof(struct sigframe, vg) );
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo);
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    return esp;
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static Addr build_rt_sigframe(ThreadState *tst,
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			      Addr esp_top_of_frame,
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			      const vki_siginfo_t *siginfo,
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			      void *handler, UInt flags,
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			      const vki_sigset_t *mask,
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 			      void *restorer)
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    struct rt_sigframe *frame;
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Addr esp = esp_top_of_frame;
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Int	sigNo = siginfo->si_signo;
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    vg_assert((flags & VKI_SA_SIGINFO) != 0);
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    esp -= sizeof(*frame);
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    esp = ROUNDDN(esp, 16);
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame = (struct rt_sigframe *)esp;
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (!extend(tst, esp, sizeof(*frame)))
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       return esp_top_of_frame;
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* retaddr, sigNo, pSiginfo, puContext fields are to be written */
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "rt signal handler frame",
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 	     esp, offsetof(struct rt_sigframe, vg) );
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->sigNo = sigNo;
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (flags & VKI_SA_RESTORER)
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       frame->retaddr = (Addr)restorer;
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    else
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       frame->retaddr
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          = VG_(client_trampoline_code)+VG_(tramp_rt_sigreturn_offset);
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->psigInfo = (Addr)&frame->sigInfo;
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    frame->puContext = (Addr)&frame->uContext;
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t));
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* SIGILL defines addr to be the faulting address */
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       frame->sigInfo._sifields._sigfault._addr
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          = (void*)tst->arch.vex.guest_CIA;
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    synth_ucontext(tst->tid, siginfo, mask, &frame->uContext, &frame->fpstate);
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    VG_TRACK( post_mem_write,  Vg_CoreSignal, tst->tid,
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..              esp, offsetof(struct rt_sigframe, vg) );
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo);
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    return esp;
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* EXPORTED */
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(sigframe_create)( ThreadId tid,
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Addr sp_top_of_frame,
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           const vki_siginfo_t *siginfo,
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           const struct vki_ucontext *siguc,
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           void *handler,
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           UInt flags,
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           const vki_sigset_t *mask,
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		           void *restorer )
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_sig_private *priv;
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr sp;
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState *tst;
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int sigNo = siginfo->si_signo;
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr faultaddr;
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Stack must be 16-byte aligned */
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sp_top_of_frame &= ~0xf;
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (flags & VKI_SA_SIGINFO) {
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sp = sp_top_of_frame - sizeof(struct rt_sigframe);
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sp = sp_top_of_frame - sizeof(struct nonrt_sigframe);
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst = VG_(get_ThreadState)(tid);
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!extend(tst, sp, sp_top_of_frame - sp))
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_16_ALIGNED(sp));
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up the stack chain pointer */
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             sp, sizeof(UWord) );
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *(Addr *)sp = tst->arch.vex.guest_GPR1;
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             sp, sizeof(UWord) );
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   faultaddr = (Addr)siginfo->_sifields._sigfault._addr;
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      faultaddr = tst->arch.vex.guest_CIA;
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (flags & VKI_SA_SIGINFO) {
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct rt_sigframe *frame = (struct rt_sigframe *) sp;
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct vki_ucontext *ucp = &frame->ucontext;
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame siginfo",
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                (Addr)&frame->siginfo, sizeof(frame->siginfo) );
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(memcpy)(&frame->siginfo, siginfo, sizeof(*siginfo));
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                (Addr)&frame->siginfo, sizeof(frame->siginfo) );
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame ucontext",
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                (Addr)ucp, offsetof(struct vki_ucontext, uc_pad) );
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ucp->uc_flags = 0;
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ucp->uc_link = 0;
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ucp->uc_stack = tst->altstack;
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( post_mem_write, Vg_CoreSignal, tid, (Addr)ucp,
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                offsetof(struct vki_ucontext, uc_pad) );
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame ucontext",
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                (Addr)&ucp->uc_regs,
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sizeof(ucp->uc_regs) + sizeof(ucp->uc_sigmask) );
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ucp->uc_regs = &ucp->uc_mcontext;
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ucp->uc_sigmask = tst->sig_mask;
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                (Addr)&ucp->uc_regs,
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sizeof(ucp->uc_regs) + sizeof(ucp->uc_sigmask) );
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stack_mcontext(&ucp->uc_mcontext, tst, True/*use_rt_sigreturn*/, faultaddr);
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      priv = &frame->priv;
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SET_SIGNAL_GPR(tid, 4, (Addr) &frame->siginfo);
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SET_SIGNAL_GPR(tid, 5, (Addr) ucp);
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* the kernel sets this, though it doesn't seem to be in the ABI */
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SET_SIGNAL_GPR(tid, 6, (Addr) &frame->siginfo);
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* non-RT signal delivery */
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct nonrt_sigframe *frame = (struct nonrt_sigframe *) sp;
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct vki_sigcontext *scp = &frame->sigcontext;
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame sigcontext",
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                (Addr)&scp->_unused[3], sizeof(*scp) - 3 * sizeof(UInt) );
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      scp->signal = sigNo;
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      scp->handler = (Addr) handler;
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      scp->oldmask = tst->sig_mask.sig[0];
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      scp->_unused[3] = tst->sig_mask.sig[1];
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                (Addr)&scp->_unused[3], sizeof(*scp) - 3 * sizeof(UInt) );
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stack_mcontext(&frame->mcontext, tst, False/*!use_rt_sigreturn*/, faultaddr);
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      priv = &frame->priv;
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SET_SIGNAL_GPR(tid, 4, (Addr) scp);
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   priv->magicPI       = 0x31415927;
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   priv->sigNo_private = sigNo;
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   priv->vex_shadow1   = tst->arch.vex_shadow1;
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   priv->vex_shadow2   = tst->arch.vex_shadow2;
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SET_SIGNAL_GPR(tid, 1, sp);
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SET_SIGNAL_GPR(tid, 3, sigNo);
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->arch.vex.guest_CIA = (Addr) handler;
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Addr		esp;
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    ThreadState* tst = VG_(get_ThreadState)(tid);
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (flags & VKI_SA_SIGINFO)
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       esp = build_rt_sigframe(tst, esp_top_of_frame, siginfo,
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                    handler, flags, mask, restorer);
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    else
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       esp = build_sigframe(tst, esp_top_of_frame,
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 siginfo, handler, flags, mask, restorer);
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* Set the thread so it will next run the handler. */
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* tst->m_esp  = esp; */
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SET_SIGNAL_ESP(tid, esp);
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    //VG_(printf)("handler = %p\n", handler);
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_CIA = (Addr) handler;
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* This thread needs to be marked runnable, but we leave that the
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       caller to do. */
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0)
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("pushed signal frame; %%R1 now = %#lx, "
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "next %%CIA = %#x, status=%d\n",
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  sp, tst->arch.vex.guest_CIA, tst->status);
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Destroying signal frames                             ---*/
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. /* Return False and don't do anything, just set the client to take a
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    segfault, if it looks like the frame is corrupted. */
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. Bool restore_vg_sigframe ( ThreadState *tst,
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                            struct vg_sigframe *frame, Int *sigNo )
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (frame->magicPI != 0x31415927 ||
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..        frame->magicE  != 0x27182818) {
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       VG_(message)(Vg_UserMsg, "Thread %d return signal frame "
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                "corrupted.  Killing process.",
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. 		   tst->tid);
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       VG_(set_default_handler)(VKI_SIGSEGV);
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       VG_(synth_fault)(tst->tid);
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       *sigNo = VKI_SIGSEGV;
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       return False;
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    }
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->sig_mask        = frame->mask;
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->tmp_sig_mask    = frame->mask;
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex_shadow = frame->vex_shadow;
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* HACK ALERT */
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex        = frame->vex;
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* end HACK ALERT */
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    *sigNo               = frame->sigNo_private;
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    return True;
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. void restore_sigcontext( ThreadState *tst,
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                          struct vki_sigcontext *sc )
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //..                          struct vki_sigcontext *sc, struct _vki_fpstate *fpstate )
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_EAX     = sc->eax;
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_ECX     = sc->ecx;
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_EDX     = sc->edx;
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_EBX     = sc->ebx;
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_EBP     = sc->ebp;
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_ESP     = sc->esp;
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_ESI     = sc->esi;
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_EDI     = sc->edi;
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //::    tst->arch.vex.guest_eflags  = sc->eflags;
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //::    tst->arch.vex.guest_EIP     = sc->eip;
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_CS      = sc->cs;
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_SS      = sc->ss;
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_DS      = sc->ds;
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_ES      = sc->es;
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_FS      = sc->fs;
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst->arch.vex.guest_GS      = sc->gs;
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //::    restore_i387(&tst->arch, fpstate);
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. SizeT restore_sigframe ( ThreadState *tst,
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                          struct sigframe *frame, Int *sigNo )
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (restore_vg_sigframe(tst, &frame->vg, sigNo))
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       restore_sigcontext(tst, &frame->sigContext, &frame->fpstate);
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    return sizeof(*frame);
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. SizeT restore_rt_sigframe ( ThreadState *tst,
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                             struct rt_sigframe *frame, Int *sigNo )
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (restore_vg_sigframe(tst, &frame->vg, sigNo))
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       restore_sigcontext(tst, &frame->uContext.uc_mcontext, &frame->fpstate);
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    return sizeof(*frame);
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* EXPORTED */
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState *tst;
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_sig_private *priv;
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr sp;
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt frame_size;
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vki_mcontext *mc;
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int sigNo;
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool has_siginfo = isRT;
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst = VG_(get_ThreadState)(tid);
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Check that the stack frame looks valid */
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sp = tst->arch.vex.guest_GPR1;
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_16_ALIGNED(sp));
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* JRS 17 Nov 05: This code used to check that *sp -- which should
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      have been set by the stwu at the start of the handler -- points
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to just above the frame (ie, the previous frame).  However, that
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      isn't valid when delivering signals on alt stacks.  So I removed
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      it.  The frame is still sanity-checked using the priv->magicPI
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      field. */
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (has_siginfo) {
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct rt_sigframe *frame = (struct rt_sigframe *)sp;
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      frame_size = sizeof(*frame);
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mc = &frame->ucontext.uc_mcontext;
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      priv = &frame->priv;
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(priv->magicPI == 0x31415927);
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tst->sig_mask = frame->ucontext.uc_sigmask;
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct nonrt_sigframe *frame = (struct nonrt_sigframe *)sp;
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      frame_size = sizeof(*frame);
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mc = &frame->mcontext;
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      priv = &frame->priv;
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(priv->magicPI == 0x31415927);
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tst->sig_mask.sig[0] = frame->sigcontext.oldmask;
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tst->sig_mask.sig[1] = frame->sigcontext._unused[3];
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->tmp_sig_mask = tst->sig_mask;
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sigNo = priv->sigNo_private;
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define DO(gpr)  tst->arch.vex.guest_GPR##gpr = mc->mc_gregs[VKI_PT_R0+gpr]
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO(0);  DO(1);  DO(2);  DO(3);  DO(4);  DO(5);  DO(6);  DO(7);
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO(8);  DO(9);  DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef DO
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->arch.vex.guest_CIA = mc->mc_gregs[VKI_PT_NIP];
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Umm ... ? (jrs 2005 July 8)
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // tst->arch.m_orig_gpr3 = mc->mc_gregs[VKI_PT_ORIG_R3];
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_GuestPPC32_put_CR( mc->mc_gregs[VKI_PT_CCR], &tst->arch.vex );
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->arch.vex.guest_LR  = mc->mc_gregs[VKI_PT_LNK];
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->arch.vex.guest_CTR = mc->mc_gregs[VKI_PT_CTR];
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_GuestPPC32_put_XER( mc->mc_gregs[VKI_PT_XER], &tst->arch.vex );
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->arch.vex_shadow1 = priv->vex_shadow1;
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->arch.vex_shadow2 = priv->vex_shadow2;
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK(die_mem_stack_signal, sp, frame_size);
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_signals))
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_DebugMsg,
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "vg_pop_signal_frame (thread %d): "
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "isRT=%d valid magic; EIP=%#x\n",
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   tid, has_siginfo, tst->arch.vex.guest_CIA);
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* tell the tools */
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_deliver_signal, tid, sigNo );
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Addr          esp;
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    ThreadState*  tst;
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    SizeT	 size;
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Int		 sigNo;
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    tst = VG_(get_ThreadState)(tid);
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* Correctly reestablish the frame base address. */
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    esp   = tst->arch.vex.guest_ESP;
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (!isRT)
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       size = restore_sigframe(tst, (struct sigframe *)esp, &sigNo);
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    else
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       size = restore_rt_sigframe(tst, (struct rt_sigframe *)esp, &sigNo);
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    VG_TRACK( die_mem_stack_signal, esp, size );
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (VG_(clo_trace_signals))
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       VG_(message)(
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          Vg_DebugMsg,
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          "VG_(signal_return) (thread %d): isRT=%d valid magic; EIP=%p",
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          tid, isRT, tst->arch.vex.guest_EIP);
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* tell the tools */
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    VG_TRACK( post_deliver_signal, tid, sigNo );
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // defined(VGP_ppc32_linux)
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
985