Add 469782 to NEWS
[valgrind.git] / coregrind / m_sigframe / sigframe-arm64-linux.c
blobf98d563b150f4e5cbd5539bf1a1a047784697040
2 /*--------------------------------------------------------------------*/
3 /*--- Create/destroy signal delivery frames. ---*/
4 /*--- sigframe-arm64-linux.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
11 Copyright (C) 2013-2017 OpenWorks
12 info@open-works.net
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
30 #if defined(VGP_arm64_linux)
32 #include "pub_core_basics.h"
33 #include "pub_core_vki.h"
34 #include "pub_core_threadstate.h"
35 #include "pub_core_aspacemgr.h"
36 #include "pub_core_libcbase.h"
37 #include "pub_core_libcassert.h"
38 #include "pub_core_libcprint.h"
39 #include "pub_core_machine.h"
40 #include "pub_core_options.h"
41 #include "pub_core_sigframe.h"
42 #include "pub_core_signals.h"
43 #include "pub_core_tooliface.h"
44 #include "pub_core_trampoline.h"
45 #include "priv_sigframe.h"
48 /* This uses the hack of dumping the vex guest state along with both
49 shadows in the frame, and restoring it afterwards from there,
50 rather than pulling it out of the ucontext. Then, integer
51 registers, the SP and the PC are restored from the ucontext. That
52 means that signal handlers which modify floating point registers or
53 in general any register state apart from X0-X30, XSP and PC in the
54 ucontext and then return, expecting their modifications to take
55 effect, will have those modifications ignored. */
57 /* This also always does the 'has siginfo' behaviour whether or
58 not it is requested. */
60 struct vg_sig_private {
61 UInt magicPI;
62 UInt sigNo_private;
63 VexGuestARM64State vex;
64 VexGuestARM64State vex_shadow1;
65 VexGuestARM64State vex_shadow2;
68 struct sigframe {
69 struct vki_ucontext uc;
70 unsigned long retcode[2];
71 struct vg_sig_private vp;
74 struct rt_sigframe {
75 vki_siginfo_t info;
76 struct sigframe sig;
80 static void synth_ucontext( ThreadId tid, const vki_siginfo_t *si,
81 UWord trapno, UWord err, const vki_sigset_t *set,
82 struct vki_ucontext *uc)
85 ThreadState *tst = VG_(get_ThreadState)(tid);
86 struct vki_sigcontext *sc = &uc->uc_mcontext;
88 VG_(memset)(uc, 0, sizeof(*uc));
90 uc->uc_flags = 0;
91 uc->uc_link = 0;
92 uc->uc_sigmask = *set;
93 uc->uc_stack = tst->altstack;
95 # define TO_CTX(reg) sc->regs[reg] = tst->arch.vex.guest_X##reg
96 TO_CTX(0); TO_CTX(1); TO_CTX(2); TO_CTX(3);
97 TO_CTX(4); TO_CTX(5); TO_CTX(6); TO_CTX(7);
98 TO_CTX(8); TO_CTX(9); TO_CTX(10); TO_CTX(11);
99 TO_CTX(12); TO_CTX(13); TO_CTX(14); TO_CTX(15);
100 TO_CTX(16); TO_CTX(17); TO_CTX(18); TO_CTX(19);
101 TO_CTX(20); TO_CTX(21); TO_CTX(22); TO_CTX(23);
102 TO_CTX(24); TO_CTX(25); TO_CTX(26); TO_CTX(27);
103 TO_CTX(28); TO_CTX(29); TO_CTX(30);
104 # undef TO_CTX
105 sc->sp = tst->arch.vex.guest_XSP;
106 sc->pc = tst->arch.vex.guest_PC;
107 sc->pstate = 0; /* slack .. could do better */
109 //sc->trap_no = trapno;
110 //sc->error_code = err;
111 sc->fault_address = (ULong)si->_sifields._sigfault._addr;
115 static void build_sigframe(ThreadState *tst,
116 struct sigframe *frame,
117 const vki_siginfo_t *siginfo,
118 const struct vki_ucontext *siguc,
119 void *handler, UInt flags,
120 const vki_sigset_t *mask,
121 void *restorer)
123 UWord trapno;
124 UWord err;
125 Int sigNo = siginfo->si_signo;
126 struct vg_sig_private *priv = &frame->vp;
128 VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame",
129 (Addr)frame, offsetof(struct sigframe, vp));
131 if (siguc) {
132 trapno = 0; //siguc->uc_mcontext.trap_no;
133 err = 0; //siguc->uc_mcontext.error_code;
134 } else {
135 trapno = 0;
136 err = 0;
139 synth_ucontext(tst->tid, siginfo, trapno, err, mask, &frame->uc);
141 VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid,
142 (Addr)frame, offsetof(struct sigframe, vp));
144 priv->magicPI = 0x31415927;
145 priv->sigNo_private = sigNo;
146 priv->vex = tst->arch.vex;
147 priv->vex_shadow1 = tst->arch.vex_shadow1;
148 priv->vex_shadow2 = tst->arch.vex_shadow2;
152 /* EXPORTED */
153 void VG_(sigframe_create)( ThreadId tid,
154 Bool on_altstack,
155 Addr sp_top_of_frame,
156 const vki_siginfo_t *siginfo,
157 const struct vki_ucontext *siguc,
158 void *handler,
159 UInt flags,
160 const vki_sigset_t *mask,
161 void *restorer )
163 ThreadState *tst;
164 Addr sp = sp_top_of_frame;
165 Int sigNo = siginfo->si_signo;
166 UInt size;
168 tst = VG_(get_ThreadState)(tid);
170 size = sizeof(struct rt_sigframe);
172 sp -= size;
173 sp = VG_ROUNDDN(sp, 16);
175 if (! ML_(sf_maybe_extend_stack)(tst, sp, size, flags))
176 return; // Give up. No idea if this is correct
178 struct rt_sigframe *rsf = (struct rt_sigframe *)sp;
180 /* Track our writes to siginfo */
181 VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, /* VVVVV */
182 "signal handler siginfo", (Addr)rsf,
183 offsetof(struct rt_sigframe, sig));
185 VG_(memcpy)(&rsf->info, siginfo, sizeof(vki_siginfo_t));
187 if (sigNo == VKI_SIGILL && siginfo->si_code > 0) {
188 rsf->info._sifields._sigfault._addr
189 = (Addr*)(tst)->arch.vex.guest_PC;
191 VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, /* ^^^^^ */
192 (Addr)rsf, offsetof(struct rt_sigframe, sig));
194 build_sigframe(tst, &rsf->sig, siginfo, siguc,
195 handler, flags, mask, restorer);
196 tst->arch.vex.guest_X1 = (Addr)&rsf->info;
197 tst->arch.vex.guest_X2 = (Addr)&rsf->sig.uc;
199 VG_(set_SP)(tid, sp);
200 tst->arch.vex.guest_X0 = sigNo;
202 if (flags & VKI_SA_RESTORER)
203 tst->arch.vex.guest_X30 = (Addr)restorer;
204 else
205 tst->arch.vex.guest_X30
206 = (Addr)&VG_(arm64_linux_SUBST_FOR_rt_sigreturn);
208 tst->arch.vex.guest_PC = (Addr)handler;
210 VG_TRACK( post_reg_write, Vg_CoreSignal, tid,
211 VG_O_STACK_PTR, sizeof(Addr));
212 VG_TRACK( post_reg_write, Vg_CoreSignal, tid,
213 offsetof(VexGuestARM64State, guest_X0), sizeof(Addr));
214 VG_TRACK( post_reg_write, Vg_CoreSignal, tid,
215 offsetof(VexGuestARM64State, guest_X1), sizeof(Addr));
216 VG_TRACK( post_reg_write, Vg_CoreSignal, tid,
217 offsetof(VexGuestARM64State, guest_X2), sizeof(Addr));
218 VG_TRACK( post_reg_write, Vg_CoreSignal, tid,
219 offsetof(VexGuestARM64State, guest_X30), sizeof(Addr));
220 VG_TRACK( post_reg_write, Vg_CoreSignal, tid,
221 offsetof(VexGuestARM64State, guest_PC), sizeof(Addr));
225 /*------------------------------------------------------------*/
226 /*--- Destroying signal frames ---*/
227 /*------------------------------------------------------------*/
229 /* EXPORTED */
230 void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
232 vg_assert(VG_(is_valid_tid)(tid));
234 Bool has_siginfo = isRT;
235 ThreadState* tst = VG_(get_ThreadState)(tid);
236 Addr sp = tst->arch.vex.guest_XSP;
238 struct rt_sigframe* frame = (struct rt_sigframe *)sp;
239 struct vg_sig_private* priv = &frame->sig.vp;
240 vg_assert(priv->magicPI == 0x31415927);
242 tst->sig_mask = frame->sig.uc.uc_sigmask;
243 tst->tmp_sig_mask = tst->sig_mask;
245 Int sigNo = priv->sigNo_private;
246 UInt frame_size = sizeof(*frame);
248 /* Restore the entire machine state from our private copy. This
249 isn't really right, but we'll now move on to pick up at least
250 some changes that the signal handler may have made to the
251 sigcontext. */
252 tst->arch.vex = priv->vex;
253 tst->arch.vex_shadow1 = priv->vex_shadow1;
254 tst->arch.vex_shadow2 = priv->vex_shadow2;
256 if (has_siginfo) {
257 /* Pick up at least some state changes from the ucontext, just
258 in case the handler changed it. The shadow values will be
259 wrong, but hey. This restores the integer registers, the
260 program counter and stack pointer. FP/Vector regs, and any
261 condition code, FP status/control bits, etc, are not
262 restored. */
263 struct vki_sigcontext *sc =&frame->sig.uc.uc_mcontext;
264 # define FROM_CTX(reg) tst->arch.vex.guest_X##reg = sc->regs[reg]
265 FROM_CTX(0); FROM_CTX(1); FROM_CTX(2); FROM_CTX(3);
266 FROM_CTX(4); FROM_CTX(5); FROM_CTX(6); FROM_CTX(7);
267 FROM_CTX(8); FROM_CTX(9); FROM_CTX(10); FROM_CTX(11);
268 FROM_CTX(12); FROM_CTX(13); FROM_CTX(14); FROM_CTX(15);
269 FROM_CTX(16); FROM_CTX(17); FROM_CTX(18); FROM_CTX(19);
270 FROM_CTX(20); FROM_CTX(21); FROM_CTX(22); FROM_CTX(23);
271 FROM_CTX(24); FROM_CTX(25); FROM_CTX(26); FROM_CTX(27);
272 FROM_CTX(28); FROM_CTX(29); FROM_CTX(30);
273 # undef FROM_CTX
274 tst->arch.vex.guest_XSP = sc->sp; // should we use SET_SP here?
275 tst->arch.vex.guest_PC = sc->pc;
278 VG_TRACK( die_mem_stack_signal, sp - VG_STACK_REDZONE_SZB,
279 frame_size + VG_STACK_REDZONE_SZB );
281 if (VG_(clo_trace_signals))
282 VG_(message)(Vg_DebugMsg,
283 "VG_(sigframe_destroy) (thread %u): "
284 "isRT=%d valid magic; PC=%#llx\n",
285 tid, has_siginfo, tst->arch.vex.guest_PC);
287 /* tell the tools */
288 VG_TRACK( post_deliver_signal, tid, sigNo );
291 #endif // defined(VGP_arm_linux)
293 /*--------------------------------------------------------------------*/
294 /*--- end sigframe-arm64-linux.c ---*/
295 /*--------------------------------------------------------------------*/