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-2013 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 
49 
50 /* Cheap-ass hack copied from ppc32-aix5 code, just to get started.
51    Produce a frame with layout entirely of our own choosing. */
52 
53 /* This module creates and removes signal frames for signal deliveries
54    on amd64-darwin.  Kludgey; the machine state ought to be saved in a
55    ucontext and retrieved from it later, so the handler can modify it
56    and return.  However .. for now .. just stick the vex guest state
57    in the frame and snarf it again later.
58 
59    Also, don't bother with creating siginfo and ucontext in the
60    handler, although do point them somewhere non-faulting.
61 
62    Frame should have a 16-aligned size, just in case that turns out to
63    be important for Darwin.  (be conservative)
64 */
65 struct hacky_sigframe {
66    /* first word looks like a call to a 3-arg amd64-ELF function */
67    ULong               returnAddr;
68    UChar               lower_guardzone[512];  // put nothing here
69    VexGuestAMD64State  gst;
70    VexGuestAMD64State  gshadow1;
71    VexGuestAMD64State  gshadow2;
72    vki_siginfo_t       fake_siginfo;
73    struct vki_ucontext fake_ucontext;
74    UInt                magicPI;
75    UInt                sigNo_private;
76    vki_sigset_t        mask; // saved sigmask; restore when hdlr returns
77    UInt                __pad[2];
78    UChar               upper_guardzone[512]; // put nothing here
79    // and don't zero it, since that might overwrite the client's
80    // stack redzone, at least on archs which have one
81 };
82 
83 
84 /* Create a signal frame for thread 'tid'.  Make a 3-arg frame
85    regardless of whether the client originally requested a 1-arg
86    version (no SA_SIGINFO) or a 3-arg one (SA_SIGINFO) since in the
87    former case, the amd64 calling conventions will simply cause the
88    extra 2 args to be ignored (inside the handler).  (We hope!) */
VG_(sigframe_create)89 void VG_(sigframe_create) ( ThreadId tid,
90                             Addr sp_top_of_frame,
91                             const vki_siginfo_t *siginfo,
92                             const struct vki_ucontext *siguc,
93                             void *handler,
94                             UInt flags,
95                             const vki_sigset_t *mask,
96                             void *restorer )
97 {
98    ThreadState* tst;
99    Addr rsp;
100    struct hacky_sigframe* frame;
101    Int sigNo = siginfo->si_signo;
102 
103    vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
104 
105    sp_top_of_frame &= ~0xfUL;
106    rsp = sp_top_of_frame - sizeof(struct hacky_sigframe);
107    rsp -= 8; /* ELF ABI says that rsp+8 must be 16 aligned on
108                 entry to a function. */
109 
110    tst = VG_(get_ThreadState)(tid);
111    if (! ML_(sf_maybe_extend_stack)(tst, rsp, sp_top_of_frame - rsp, flags))
112       return;
113 
114    vg_assert(VG_IS_16_ALIGNED(rsp+8));
115 
116    frame = (struct hacky_sigframe *) rsp;
117 
118    /* clear it (very conservatively) (why so conservatively??) */
119    VG_(memset)(&frame->lower_guardzone, 0, sizeof frame->lower_guardzone);
120    VG_(memset)(&frame->gst,      0, sizeof(VexGuestAMD64State));
121    VG_(memset)(&frame->gshadow1, 0, sizeof(VexGuestAMD64State));
122    VG_(memset)(&frame->gshadow2, 0, sizeof(VexGuestAMD64State));
123    VG_(memset)(&frame->fake_siginfo,  0, sizeof(frame->fake_siginfo));
124    VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext));
125 
126    /* save stuff in frame */
127    frame->gst           = tst->arch.vex;
128    frame->gshadow1      = tst->arch.vex_shadow1;
129    frame->gshadow2      = tst->arch.vex_shadow2;
130    frame->sigNo_private = sigNo;
131    frame->mask          = tst->sig_mask;
132    frame->magicPI       = 0x31415927;
133 
134    /* Minimally fill in the siginfo and ucontext.  Note, utter
135       lameness prevails.  Be underwhelmed, be very underwhelmed. */
136    frame->fake_siginfo.si_signo = sigNo;
137    frame->fake_siginfo.si_code  = siginfo->si_code;
138 
139    /* Set up stack pointer */
140    vg_assert(rsp == (Addr)&frame->returnAddr);
141    VG_(set_SP)(tid, rsp);
142    VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(ULong));
143 
144    /* Set up program counter */
145    VG_(set_IP)(tid, (ULong)handler);
146    VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(ULong));
147 
148    /* Set up RA and args for the frame */
149    VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
150              (Addr)frame, 1*sizeof(ULong) );
151    frame->returnAddr  = (ULong)&VG_(amd64_darwin_SUBST_FOR_sigreturn);
152 
153    /* XXX should tell the tool that these regs got written */
154    tst->arch.vex.guest_RDI = (ULong) sigNo;
155    tst->arch.vex.guest_RSI = (Addr)  &frame->fake_siginfo;/* oh well */
156    tst->arch.vex.guest_RDX = (Addr)  &frame->fake_ucontext; /* oh well */
157 
158    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
159              (Addr)frame, 1*sizeof(ULong) );
160    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
161              (Addr)&frame->fake_siginfo, sizeof(frame->fake_siginfo));
162    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
163              (Addr)&frame->fake_ucontext, sizeof(frame->fake_ucontext));
164 
165    if (VG_(clo_trace_signals))
166       VG_(message)(Vg_DebugMsg,
167                    "sigframe_create (thread %d): "
168                    "next EIP=%#lx, next ESP=%#lx\n",
169                    tid, (Addr)handler, (Addr)frame );
170 }
171 
172 
173 /* Remove a signal frame from thread 'tid's stack, and restore the CPU
174    state from it.  Note, isRT is irrelevant here. */
VG_(sigframe_destroy)175 void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
176 {
177    ThreadState *tst;
178    Addr rsp;
179    Int sigNo;
180    struct hacky_sigframe* frame;
181 
182    vg_assert(VG_(is_valid_tid)(tid));
183    tst = VG_(get_ThreadState)(tid);
184 
185    /* Check that the stack frame looks valid */
186    rsp = VG_(get_SP)(tid);
187 
188    /* why -8 ? because the signal handler's return will have popped
189       the return address off the stack; and the return address is the
190       lowest-addressed element of hacky_sigframe. */
191    frame = (struct hacky_sigframe*)(rsp - 8);
192    vg_assert(frame->magicPI == 0x31415927);
193 
194    /* This +8 is because of the -8 referred to in the ELF ABI comment
195       in VG_(sigframe_create) just above. */
196    vg_assert(VG_IS_16_ALIGNED((Addr)frame + 8));
197 
198    /* restore the entire guest state, and shadows, from the
199       frame.  Note, as per comments above, this is a kludge - should
200       restore it from saved ucontext.  Oh well. */
201    tst->arch.vex = frame->gst;
202    tst->arch.vex_shadow1 = frame->gshadow1;
203    tst->arch.vex_shadow2 = frame->gshadow2;
204    tst->sig_mask = frame->mask;
205    tst->tmp_sig_mask = frame->mask;
206    sigNo = frame->sigNo_private;
207 
208    if (VG_(clo_trace_signals))
209       VG_(message)(Vg_DebugMsg,
210                    "sigframe_destroy (thread %d): "
211                    "valid magic; next RIP=%#llx\n",
212                    tid, tst->arch.vex.guest_RIP);
213 
214    VG_TRACK( die_mem_stack_signal,
215              (Addr)frame - VG_STACK_REDZONE_SZB,
216              sizeof(struct hacky_sigframe) );
217 
218    /* tell the tools */
219    VG_TRACK( post_deliver_signal, tid, sigNo );
220 }
221 
222 #endif // defined(VGP_amd64_darwin)
223 
224 /*--------------------------------------------------------------------*/
225 /*--- end                                  sigframe-amd64-darwin.c ---*/
226 /*--------------------------------------------------------------------*/
227