1
2 /*--------------------------------------------------------------------*/
3 /*--- Create/destroy signal delivery frames. ---*/
4 /*--- sigframe-arm-linux.c ---*/
5 /*--------------------------------------------------------------------*/
6
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
11 Copyright (C) 2000-2017 Nicholas Nethercote
12 njn@valgrind.org
13 Copyright (C) 2004-2017 Paul Mackerras
14 paulus@samba.org
15 Copyright (C) 2008-2017 Evan Geller
16 gaze@bea.ms
17
18 This program is free software; you can redistribute it and/or
19 modify it under the terms of the GNU General Public License as
20 published by the Free Software Foundation; either version 2 of the
21 License, or (at your option) any later version.
22
23 This program is distributed in the hope that it will be useful, but
24 WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
31 02111-1307, USA.
32
33 The GNU General Public License is contained in the file COPYING.
34 */
35
36 #if defined(VGP_arm_linux)
37
38 #include "pub_core_basics.h"
39 #include "pub_core_vki.h"
40 #include "pub_core_vkiscnums.h"
41 #include "pub_core_threadstate.h"
42 #include "pub_core_aspacemgr.h"
43 #include "pub_core_libcbase.h"
44 #include "pub_core_libcassert.h"
45 #include "pub_core_libcprint.h"
46 #include "pub_core_machine.h"
47 #include "pub_core_options.h"
48 #include "pub_core_sigframe.h"
49 #include "pub_core_signals.h"
50 #include "pub_core_tooliface.h"
51 #include "pub_core_trampoline.h"
52 #include "priv_sigframe.h"
53
54
55 /* This uses the hack of dumping the vex guest state along with both
56 shadows in the frame, and restoring it afterwards from there,
57 rather than pulling it out of the ucontext. Then, integer
58 registers, the SP and the PC are restored from the ucontext. That
59 means that signal handlers which modify floating point registers or
60 in general any register state apart from R0 to R15 in the ucontext
61 and then return, expecting their modifications to take effect, will
62 have those modifications ignored. */
63
64 struct vg_sig_private {
65 UInt magicPI;
66 UInt sigNo_private;
67 VexGuestARMState vex;
68 VexGuestARMState vex_shadow1;
69 VexGuestARMState vex_shadow2;
70 };
71
72 struct sigframe {
73 struct vki_ucontext uc;
74 unsigned long retcode[2];
75 struct vg_sig_private vp;
76 };
77
78 struct rt_sigframe {
79 vki_siginfo_t info;
80 struct sigframe sig;
81 };
82
83
synth_ucontext(ThreadId tid,const vki_siginfo_t * si,UWord trapno,UWord err,const vki_sigset_t * set,struct vki_ucontext * uc)84 static void synth_ucontext( ThreadId tid, const vki_siginfo_t *si,
85 UWord trapno, UWord err, const vki_sigset_t *set,
86 struct vki_ucontext *uc){
87
88 ThreadState *tst = VG_(get_ThreadState)(tid);
89 struct vki_sigcontext *sc = &uc->uc_mcontext;
90
91 VG_(memset)(uc, 0, sizeof(*uc));
92
93 uc->uc_flags = 0;
94 uc->uc_link = 0;
95 uc->uc_sigmask = *set;
96 uc->uc_stack = tst->altstack;
97
98 # define TO_CTX(reg,REG) sc->arm_##reg = tst->arch.vex.guest_##REG
99 TO_CTX(r0,R0); TO_CTX(r1,R1); TO_CTX(r2,R2); TO_CTX(r3,R3);
100 TO_CTX(r4,R4); TO_CTX(r5,R5); TO_CTX(r6,R6); TO_CTX(r7,R7);
101 TO_CTX(r8,R8); TO_CTX(r9,R9); TO_CTX(r10,R10); TO_CTX(fp,R11);
102 TO_CTX(ip,R12); TO_CTX(sp,R13); TO_CTX(lr,R14); TO_CTX(pc,R15T);
103 # undef TO_CTX
104
105 sc->trap_no = trapno;
106 sc->error_code = err;
107 sc->fault_address = (UInt)si->_sifields._sigfault._addr;
108 }
109
110
build_sigframe(ThreadState * tst,struct sigframe * frame,const vki_siginfo_t * siginfo,const struct vki_ucontext * siguc,void * handler,UInt flags,const vki_sigset_t * mask,void * restorer)111 static void build_sigframe(ThreadState *tst,
112 struct sigframe *frame,
113 const vki_siginfo_t *siginfo,
114 const struct vki_ucontext *siguc,
115 void *handler, UInt flags,
116 const vki_sigset_t *mask,
117 void *restorer){
118
119 UWord trapno;
120 UWord err;
121 Int sigNo = siginfo->si_signo;
122 struct vg_sig_private *priv = &frame->vp;
123
124 VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame",
125 (Addr)frame, offsetof(struct sigframe, vp));
126
127 if(siguc) {
128 trapno = siguc->uc_mcontext.trap_no;
129 err = siguc->uc_mcontext.error_code;
130 } else {
131 trapno = 0;
132 err = 0;
133 }
134
135 synth_ucontext(tst->tid, siginfo, trapno, err, mask, &frame->uc);
136
137 VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid,
138 (Addr)frame, offsetof(struct sigframe, vp));
139
140 priv->magicPI = 0x31415927;
141 priv->sigNo_private = sigNo;
142 priv->vex = tst->arch.vex;
143 priv->vex_shadow1 = tst->arch.vex_shadow1;
144 priv->vex_shadow2 = tst->arch.vex_shadow2;
145
146 }
147
148
149
150 /* EXPORTED */
VG_(sigframe_create)151 void VG_(sigframe_create)( ThreadId tid,
152 Bool on_altstack,
153 Addr sp_top_of_frame,
154 const vki_siginfo_t *siginfo,
155 const struct vki_ucontext *siguc,
156 void *handler,
157 UInt flags,
158 const vki_sigset_t *mask,
159 void *restorer )
160 {
161 Addr sp = sp_top_of_frame;
162 ThreadState *tst;
163 Int sigNo = siginfo->si_signo;
164 UInt size;
165
166 tst = VG_(get_ThreadState)(tid);
167
168 size = flags & VKI_SA_SIGINFO ? sizeof(struct rt_sigframe) :
169 sizeof(struct sigframe);
170
171 sp -= size;
172 sp = VG_ROUNDDN(sp, 16);
173
174 if (! ML_(sf_maybe_extend_stack)(tst, sp, size, flags))
175 I_die_here; // XXX Incorrect behavior
176
177
178 if (flags & VKI_SA_SIGINFO){
179 struct rt_sigframe *rsf = (struct rt_sigframe *)sp;
180
181 /* Track our writes to siginfo */
182 VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, /* VVVVV */
183 "signal handler siginfo", (Addr)rsf,
184 offsetof(struct rt_sigframe, sig));
185
186 VG_(memcpy)(&rsf->info, siginfo, sizeof(vki_siginfo_t));
187
188 if(sigNo == VKI_SIGILL && siginfo->si_code > 0) {
189 rsf->info._sifields._sigfault._addr
190 = (Addr *) (tst)->arch.vex.guest_R12; /* IP */
191 }
192 VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, /* ^^^^^ */
193 (Addr)rsf, offsetof(struct rt_sigframe, sig));
194
195 build_sigframe(tst, &rsf->sig, siginfo, siguc,
196 handler, flags, mask, restorer);
197 tst->arch.vex.guest_R1 = (Addr)&rsf->info;
198 tst->arch.vex.guest_R2 = (Addr)&rsf->sig.uc;
199 }
200 else {
201 build_sigframe(tst, (struct sigframe *)sp, siginfo, siguc,
202 handler, flags, mask, restorer);
203 }
204
205 VG_(set_SP)(tid, sp);
206 VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR,
207 sizeof(Addr));
208 tst->arch.vex.guest_R0 = sigNo;
209
210 if (flags & VKI_SA_RESTORER)
211 tst->arch.vex.guest_R14 = (Addr)restorer;
212 else
213 tst->arch.vex.guest_R14
214 = (flags & VKI_SA_SIGINFO)
215 ? (Addr)&VG_(arm_linux_SUBST_FOR_rt_sigreturn)
216 : (Addr)&VG_(arm_linux_SUBST_FOR_sigreturn);
217
218 tst->arch.vex.guest_R15T = (Addr) handler; /* R15 == PC */
219
220 /* Regardless of what the state of ITSTATE was, it makes no sense
221 to enter the handler with the first 1-4 instructions possibly
222 predicated as "don't execute". So set ITSTATE to [AL,AL,AL,AL]
223 before entering the handler. */
224 tst->arch.vex.guest_ITSTATE = 0;
225
226 if (VG_(clo_trace_signals))
227 VG_(message)(Vg_DebugMsg,
228 "VG_(sigframe_create): continuing in handler with PC=%#lx\n",
229 (Addr)handler);
230 }
231
232
233 /*------------------------------------------------------------*/
234 /*--- Destroying signal frames ---*/
235 /*------------------------------------------------------------*/
236
237 /* EXPORTED */
VG_(sigframe_destroy)238 void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
239 {
240 ThreadState *tst;
241 struct vg_sig_private *priv;
242 Addr sp;
243 UInt frame_size;
244 Int sigNo;
245 Bool has_siginfo = isRT;
246
247 struct rt_sigframe *rt_frame = NULL;
248
249 vg_assert(VG_(is_valid_tid)(tid));
250 tst = VG_(get_ThreadState)(tid);
251 sp = tst->arch.vex.guest_R13;
252
253 if (has_siginfo) {
254 struct rt_sigframe *frame = (struct rt_sigframe *)sp;
255 frame_size = sizeof(*frame);
256 priv = &frame->sig.vp;
257 vg_assert(priv->magicPI == 0x31415927);
258 tst->sig_mask = frame->sig.uc.uc_sigmask;
259 rt_frame = frame;
260 } else {
261 struct sigframe *frame = (struct sigframe *)sp;
262 frame_size = sizeof(*frame);
263 priv = &frame->vp;
264 vg_assert(priv->magicPI == 0x31415927);
265 tst->sig_mask = frame->uc.uc_sigmask;
266 }
267 tst->tmp_sig_mask = tst->sig_mask;
268
269 sigNo = priv->sigNo_private;
270
271 /* Restore the entire machine state from our private copy. This
272 isn't really right, but we'll now move on to pick up at least
273 some changes that the signal handler may have made to the
274 sigcontext. */
275 tst->arch.vex = priv->vex;
276 tst->arch.vex_shadow1 = priv->vex_shadow1;
277 tst->arch.vex_shadow2 = priv->vex_shadow2;
278
279 if (has_siginfo) {
280 /* Pick up at least some state changes from the ucontext, just
281 in case the handler changed it. The shadow values will be
282 wrong, but hey. This restores the integer registers, the
283 program counter and stack pointer. FP/Vector regs, and any
284 condition code, FP status/control bits, etc, are not
285 restored. */
286 vg_assert(rt_frame != NULL);
287 struct vki_sigcontext *sc = &rt_frame->sig.uc.uc_mcontext;
288 Bool handler_changed_pc = sc->arm_pc != tst->arch.vex.guest_R15T;
289
290 # define FROM_CTX(reg,REG) tst->arch.vex.guest_##REG = sc->arm_##reg;
291 FROM_CTX(r0,R0); FROM_CTX(r1,R1); FROM_CTX(r2,R2); FROM_CTX(r3,R3);
292 FROM_CTX(r4,R4); FROM_CTX(r5,R5); FROM_CTX(r6,R6); FROM_CTX(r7,R7);
293 FROM_CTX(r8,R8); FROM_CTX(r9,R9); FROM_CTX(r10,R10); FROM_CTX(fp,R11);
294 FROM_CTX(ip,R12); FROM_CTX(sp,R13); FROM_CTX(lr,R14); FROM_CTX(pc,R15T);
295 # undef FROM_CTX
296
297 /* A nasty ITSTATE hack -- apparently necessary as there doesn't
298 seem to be anywhere in the mcontext in which the ITSTATE is
299 stored. If the handler appears to have changed the PC, set
300 ITSTATE to [AL,AL,AL,AL] on the basis that it would be nuts
301 to start executing code with an ITSTATE value that pertained
302 to some other code address. Otherwise ITSTATE is restored
303 directly from the VEX state that we shoved on the stack when
304 creating the signal frame. */
305 if (handler_changed_pc) {
306 tst->arch.vex.guest_ITSTATE = 0;
307 }
308 }
309
310 VG_TRACK( die_mem_stack_signal, sp - VG_STACK_REDZONE_SZB,
311 frame_size + VG_STACK_REDZONE_SZB );
312
313 if (VG_(clo_trace_signals))
314 VG_(message)(Vg_DebugMsg,
315 "vg_pop_signal_frame (thread %u): "
316 "isRT=%d valid magic; PC=%#x\n",
317 tid, has_siginfo, tst->arch.vex.guest_R15T);
318
319 /* tell the tools */
320 VG_TRACK( post_deliver_signal, tid, sigNo );
321 }
322
323 #endif // defined(VGP_arm_linux)
324
325 /*--------------------------------------------------------------------*/
326 /*--- end sigframe-arm-linux.c ---*/
327 /*--------------------------------------------------------------------*/
328