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*/
61struct 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 */
82static 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
117static 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!) */
147void 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. */
233void 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