2 /*--------------------------------------------------------------------*/
3 /*--- Create/destroy signal delivery frames. ---*/
4 /*--- sigframe-amd64-darwin.c ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Valgrind, a dynamic binary instrumentation
11 Copyright (C) 2006-2017 OpenWorks Ltd
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, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 The GNU General Public License is contained in the file COPYING.
32 #if defined(VGP_amd64_darwin)
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"
51 /* Originally copied from ppc32-aix5 code.
52 Produce a frame with layout entirely of our own choosing.
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.
58 Frame should have a 16-aligned size, just in case that turns out to
59 be important for Darwin. (be conservative)
61 struct hacky_sigframe
{
62 /* first word looks like a call to a 3-arg amd64-ELF function */
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
;
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
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.
82 static void synthesize_ucontext(ThreadState
*tst
,
83 struct vki_ucontext
*uc
,
84 const struct vki_ucontext
*siguc
)
86 VG_(memset
)(uc
, 0, sizeof(*uc
));
88 if (siguc
) uc
->uc_sigmask
= siguc
->uc_sigmask
;
89 uc
->uc_stack
= tst
->altstack
;
90 uc
->uc_mcontext
= &uc
->__mcontext_data
;
92 # define SC2(reg,REG) uc->__mcontext_data.__ss.reg = tst->arch.vex.guest_##REG
110 uc
->__mcontext_data
.__ss
.__rflags
= LibVEX_GuestAMD64_get_rflags(&tst
->arch
.vex
);
113 uc
->__mcontext_data
.__es
= siguc
->__mcontext_data
.__es
;
117 static void restore_from_ucontext(ThreadState
*tst
,
118 const struct vki_ucontext
*uc
)
120 # define SC2(REG,reg) tst->arch.vex.guest_##REG = uc->__mcontext_data.__ss.reg
138 /* There doesn't seem to be an easy way to restore rflags */
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!) */
147 void VG_(sigframe_create
) ( ThreadId tid
,
149 Addr sp_top_of_frame
,
150 const vki_siginfo_t
*siginfo
,
151 const struct vki_ucontext
*siguc
,
154 const vki_sigset_t
*mask
,
159 struct hacky_sigframe
* frame
;
160 Int sigNo
= siginfo
->si_signo
;
162 vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe
)));
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. */
169 tst
= VG_(get_ThreadState
)(tid
);
170 if (! ML_(sf_maybe_extend_stack
)(tst
, rsp
, sp_top_of_frame
- rsp
, flags
))
173 vg_assert(VG_IS_16_ALIGNED(rsp
+8));
175 frame
= (struct hacky_sigframe
*) rsp
;
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
));
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;
193 /* Fill in the siginfo and ucontext. */
194 synthesize_ucontext(tst
, &frame
->fake_ucontext
, siguc
);
195 frame
->fake_siginfo
= *siginfo
;
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
));
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
));
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
);
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
;
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
));
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
);
231 /* Remove a signal frame from thread 'tid's stack, and restore the CPU
232 state from it. Note, isRT is irrelevant here. */
233 void VG_(sigframe_destroy
)( ThreadId tid
, Bool isRT
)
238 struct hacky_sigframe
* frame
;
240 vg_assert(VG_(is_valid_tid
)(tid
));
241 tst
= VG_(get_ThreadState
)(tid
);
243 /* Check that the stack frame looks valid */
244 rsp
= VG_(get_SP
)(tid
);
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);
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));
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
);
262 tst
->sig_mask
= frame
->mask
;
263 tst
->tmp_sig_mask
= frame
->mask
;
264 sigNo
= frame
->sigNo_private
;
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
);
272 VG_TRACK( die_mem_stack_signal
,
273 (Addr
)frame
- VG_STACK_REDZONE_SZB
,
274 sizeof(struct hacky_sigframe
) );
277 VG_TRACK( post_deliver_signal
, tid
, sigNo
);
280 #endif // defined(VGP_amd64_darwin)
282 /*--------------------------------------------------------------------*/
283 /*--- end sigframe-amd64-darwin.c ---*/
284 /*--------------------------------------------------------------------*/