1
2 /*--------------------------------------------------------------------*/
3 /*--- Create/destroy signal delivery frames. ---*/
4 /*--- sigframe-amd64-darwin.c ---*/
5 /*--------------------------------------------------------------------*/
6
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
11 Copyright (C) 2006-2017 OpenWorks Ltd
12 info@open-works.co.uk
13
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.
18
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.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30 */
31
32 #if defined(VGP_amd64_darwin)
33
34 #include "pub_core_basics.h"
35 #include "pub_core_vki.h"
36 #include "pub_core_vkiscnums.h"
37 #include "pub_core_threadstate.h"
38 #include "pub_core_aspacemgr.h"
39 #include "pub_core_libcbase.h"
40 #include "pub_core_libcassert.h"
41 #include "pub_core_libcprint.h"
42 #include "pub_core_machine.h"
43 #include "pub_core_options.h"
44 #include "pub_core_signals.h"
45 #include "pub_core_tooliface.h"
46 #include "pub_core_trampoline.h"
47 #include "pub_core_sigframe.h" /* self */
48 #include "priv_sigframe.h"
49
50
51 /* Originally copied from ppc32-aix5 code.
52 Produce a frame with layout entirely of our own choosing.
53
54 This module creates and removes signal frames for signal deliveries
55 on amd64-darwin. The machine state is saved in a ucontext and retrieved
56 from it later, so the handler can modify it and return.
57
58 Frame should have a 16-aligned size, just in case that turns out to
59 be important for Darwin. (be conservative)
60 */
61 struct hacky_sigframe {
62 /* first word looks like a call to a 3-arg amd64-ELF function */
63 ULong returnAddr;
64 UChar lower_guardzone[512]; // put nothing here
65 VexGuestAMD64State vex;
66 VexGuestAMD64State vex_shadow1;
67 VexGuestAMD64State vex_shadow2;
68 vki_siginfo_t fake_siginfo;
69 struct vki_ucontext fake_ucontext;
70 UInt magicPI;
71 UInt sigNo_private;
72 vki_sigset_t mask; // saved sigmask; restore when hdlr returns
73 UChar upper_guardzone[512]; // put nothing here
74 // and don't zero it, since that might overwrite the client's
75 // stack redzone, at least on archs which have one
76 };
77
78 /* Create a plausible-looking sigcontext from the thread's
79 Vex guest state. NOTE: does not fill in the FP or SSE
80 bits of sigcontext at the moment.
81 */
synthesize_ucontext(ThreadState * tst,struct vki_ucontext * uc,const struct vki_ucontext * siguc)82 static void synthesize_ucontext(ThreadState *tst,
83 struct vki_ucontext *uc,
84 const struct vki_ucontext *siguc)
85 {
86 VG_(memset)(uc, 0, sizeof(*uc));
87
88 if (siguc) uc->uc_sigmask = siguc->uc_sigmask;
89 uc->uc_stack = tst->altstack;
90 uc->uc_mcontext = &uc->__mcontext_data;
91
92 # define SC2(reg,REG) uc->__mcontext_data.__ss.reg = tst->arch.vex.guest_##REG
93 SC2(__r8,R8);
94 SC2(__r9,R9);
95 SC2(__r10,R10);
96 SC2(__r11,R11);
97 SC2(__r12,R12);
98 SC2(__r13,R13);
99 SC2(__r14,R14);
100 SC2(__r15,R15);
101 SC2(__rdi,RDI);
102 SC2(__rsi,RSI);
103 SC2(__rbp,RBP);
104 SC2(__rbx,RBX);
105 SC2(__rdx,RDX);
106 SC2(__rax,RAX);
107 SC2(__rcx,RCX);
108 SC2(__rsp,RSP);
109 SC2(__rip,RIP);
110 uc->__mcontext_data.__ss.__rflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex);
111
112 if (siguc)
113 uc->__mcontext_data.__es = siguc->__mcontext_data.__es;
114 # undef SC2
115 }
116
restore_from_ucontext(ThreadState * tst,const struct vki_ucontext * uc)117 static void restore_from_ucontext(ThreadState *tst,
118 const struct vki_ucontext *uc)
119 {
120 # define SC2(REG,reg) tst->arch.vex.guest_##REG = uc->__mcontext_data.__ss.reg
121 SC2(R8,__r8);
122 SC2(R9,__r9);
123 SC2(R10,__r10);
124 SC2(R11,__r11);
125 SC2(R12,__r12);
126 SC2(R13,__r13);
127 SC2(R14,__r14);
128 SC2(R15,__r15);
129 SC2(RDI,__rdi);
130 SC2(RSI,__rsi);
131 SC2(RBP,__rbp);
132 SC2(RBX,__rbx);
133 SC2(RDX,__rdx);
134 SC2(RAX,__rax);
135 SC2(RCX,__rcx);
136 SC2(RSP,__rsp);
137 SC2(RIP,__rip);
138 /* There doesn't seem to be an easy way to restore rflags */
139 # undef SC2
140 }
141
142 /* Create a signal frame for thread 'tid'. Make a 3-arg frame
143 regardless of whether the client originally requested a 1-arg
144 version (no SA_SIGINFO) or a 3-arg one (SA_SIGINFO) since in the
145 former case, the amd64 calling conventions will simply cause the
146 extra 2 args to be ignored (inside the handler). (We hope!) */
VG_(sigframe_create)147 void VG_(sigframe_create) ( ThreadId tid,
148 Bool on_altstack,
149 Addr sp_top_of_frame,
150 const vki_siginfo_t *siginfo,
151 const struct vki_ucontext *siguc,
152 void *handler,
153 UInt flags,
154 const vki_sigset_t *mask,
155 void *restorer )
156 {
157 ThreadState* tst;
158 Addr rsp;
159 struct hacky_sigframe* frame;
160 Int sigNo = siginfo->si_signo;
161
162 vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
163
164 sp_top_of_frame &= ~0xfUL;
165 rsp = sp_top_of_frame - sizeof(struct hacky_sigframe);
166 rsp -= 8; /* ELF ABI says that rsp+8 must be 16 aligned on
167 entry to a function. */
168
169 tst = VG_(get_ThreadState)(tid);
170 if (! ML_(sf_maybe_extend_stack)(tst, rsp, sp_top_of_frame - rsp, flags))
171 return;
172
173 vg_assert(VG_IS_16_ALIGNED(rsp+8));
174
175 frame = (struct hacky_sigframe *) rsp;
176
177 /* clear it (very conservatively) */
178 VG_(memset)(&frame->lower_guardzone, 0, sizeof frame->lower_guardzone);
179 VG_(memset)(&frame->vex, 0, sizeof(VexGuestAMD64State));
180 VG_(memset)(&frame->vex_shadow1, 0, sizeof(VexGuestAMD64State));
181 VG_(memset)(&frame->vex_shadow2, 0, sizeof(VexGuestAMD64State));
182 VG_(memset)(&frame->fake_siginfo, 0, sizeof(frame->fake_siginfo));
183 VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext));
184
185 /* save stuff in frame */
186 frame->vex = tst->arch.vex;
187 frame->vex_shadow1 = tst->arch.vex_shadow1;
188 frame->vex_shadow2 = tst->arch.vex_shadow2;
189 frame->sigNo_private = sigNo;
190 frame->mask = tst->sig_mask;
191 frame->magicPI = 0x31415927;
192
193 /* Fill in the siginfo and ucontext. */
194 synthesize_ucontext(tst, &frame->fake_ucontext, siguc);
195 frame->fake_siginfo = *siginfo;
196
197 /* Set up stack pointer */
198 vg_assert(rsp == (Addr)&frame->returnAddr);
199 VG_(set_SP)(tid, rsp);
200 VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(ULong));
201
202 /* Set up program counter */
203 VG_(set_IP)(tid, (ULong)handler);
204 VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(ULong));
205
206 /* Set up RA and args for the frame */
207 VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
208 (Addr)frame, 1*sizeof(ULong) );
209 frame->returnAddr = (ULong)&VG_(amd64_darwin_SUBST_FOR_sigreturn);
210
211 /* XXX should tell the tool that these regs got written */
212 tst->arch.vex.guest_RDI = (ULong) sigNo;
213 tst->arch.vex.guest_RSI = (Addr) &frame->fake_siginfo;
214 tst->arch.vex.guest_RDX = (Addr) &frame->fake_ucontext;
215
216 VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
217 (Addr)frame, 1*sizeof(ULong) );
218 VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
219 (Addr)&frame->fake_siginfo, sizeof(frame->fake_siginfo));
220 VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
221 (Addr)&frame->fake_ucontext, sizeof(frame->fake_ucontext));
222
223 if (VG_(clo_trace_signals))
224 VG_(message)(Vg_DebugMsg,
225 "sigframe_create (thread %u): "
226 "next RIP=%#lx, next RSP=%#lx\n",
227 tid, (Addr)handler, (Addr)frame );
228 }
229
230
231 /* Remove a signal frame from thread 'tid's stack, and restore the CPU
232 state from it. Note, isRT is irrelevant here. */
VG_(sigframe_destroy)233 void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
234 {
235 ThreadState *tst;
236 Addr rsp;
237 Int sigNo;
238 struct hacky_sigframe* frame;
239
240 vg_assert(VG_(is_valid_tid)(tid));
241 tst = VG_(get_ThreadState)(tid);
242
243 /* Check that the stack frame looks valid */
244 rsp = VG_(get_SP)(tid);
245
246 /* why -8 ? because the signal handler's return will have popped
247 the return address off the stack; and the return address is the
248 lowest-addressed element of hacky_sigframe. */
249 frame = (struct hacky_sigframe*)(rsp - 8);
250 vg_assert(frame->magicPI == 0x31415927);
251
252 /* This +8 is because of the -8 referred to in the ELF ABI comment
253 in VG_(sigframe_create) just above. */
254 vg_assert(VG_IS_16_ALIGNED((Addr)frame + 8));
255
256 /* restore the entire guest state, and shadows, from the frame. */
257 tst->arch.vex = frame->vex;
258 tst->arch.vex_shadow1 = frame->vex_shadow1;
259 tst->arch.vex_shadow2 = frame->vex_shadow2;
260 restore_from_ucontext(tst, &frame->fake_ucontext);
261
262 tst->sig_mask = frame->mask;
263 tst->tmp_sig_mask = frame->mask;
264 sigNo = frame->sigNo_private;
265
266 if (VG_(clo_trace_signals))
267 VG_(message)(Vg_DebugMsg,
268 "sigframe_destroy (thread %d): "
269 "valid magic; next RIP=%#llx\n",
270 tid, tst->arch.vex.guest_RIP);
271
272 VG_TRACK( die_mem_stack_signal,
273 (Addr)frame - VG_STACK_REDZONE_SZB,
274 sizeof(struct hacky_sigframe) );
275
276 /* tell the tools */
277 VG_TRACK( post_deliver_signal, tid, sigNo );
278 }
279
280 #endif // defined(VGP_amd64_darwin)
281
282 /*--------------------------------------------------------------------*/
283 /*--- end sigframe-amd64-darwin.c ---*/
284 /*--------------------------------------------------------------------*/
285