• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-2010 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 /* Extend the stack segment downwards if needed so as to ensure the
85    new signal frames are mapped to something.  Return a Bool
86    indicating whether or not the operation was successful.
87 */
extend(ThreadState * tst,Addr addr,SizeT size)88 static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
89 {
90    ThreadId tid = tst->tid;
91    /* For tracking memory events, indicate the entire frame has been
92       allocated.  Except, don't mess with the area which
93       overlaps the previous frame's redzone. */
94    /* XXX is the following call really right?  compared with the
95       amd64-linux version, this doesn't appear to handle the redzone
96       in the same way. */
97    VG_TRACK( new_mem_stack_signal,
98              addr - VG_STACK_REDZONE_SZB, size, tid );
99    return True;
100 }
101 
102 
103 /* Create a signal frame for thread 'tid'.  Make a 3-arg frame
104    regardless of whether the client originally requested a 1-arg
105    version (no SA_SIGINFO) or a 3-arg one (SA_SIGINFO) since in the
106    former case, the amd64 calling conventions will simply cause the
107    extra 2 args to be ignored (inside the handler).  (We hope!) */
VG_(sigframe_create)108 void VG_(sigframe_create) ( ThreadId tid,
109                             Addr sp_top_of_frame,
110                             const vki_siginfo_t *siginfo,
111                             const struct vki_ucontext *siguc,
112                             void *handler,
113                             UInt flags,
114                             const vki_sigset_t *mask,
115                             void *restorer )
116 {
117    ThreadState* tst;
118    Addr rsp;
119    struct hacky_sigframe* frame;
120    Int sigNo = siginfo->si_signo;
121 
122    vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
123 
124    sp_top_of_frame &= ~0xfUL;
125    rsp = sp_top_of_frame - sizeof(struct hacky_sigframe);
126 
127    tst = VG_(get_ThreadState)(tid);
128    if (!extend(tst, rsp, sp_top_of_frame - rsp))
129       return;
130 
131    vg_assert(VG_IS_16_ALIGNED(rsp));
132 
133    frame = (struct hacky_sigframe *) rsp;
134 
135    /* clear it (very conservatively) (why so conservatively??) */
136    VG_(memset)(&frame->lower_guardzone, 0, 512);
137    VG_(memset)(&frame->gst,      0, sizeof(VexGuestAMD64State));
138    VG_(memset)(&frame->gshadow1, 0, sizeof(VexGuestAMD64State));
139    VG_(memset)(&frame->gshadow2, 0, sizeof(VexGuestAMD64State));
140    VG_(memset)(&frame->fake_siginfo,  0, sizeof(frame->fake_siginfo));
141    VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext));
142 
143    /* save stuff in frame */
144    frame->gst           = tst->arch.vex;
145    frame->gshadow1      = tst->arch.vex_shadow1;
146    frame->gshadow2      = tst->arch.vex_shadow2;
147    frame->sigNo_private = sigNo;
148    frame->mask          = tst->sig_mask;
149    frame->magicPI       = 0x31415927;
150 
151    /* Minimally fill in the siginfo and ucontext.  Note, utter
152       lameness prevails.  Be underwhelmed, be very underwhelmed. */
153    frame->fake_siginfo.si_signo = sigNo;
154    frame->fake_siginfo.si_code  = siginfo->si_code;
155 
156    /* Set up stack pointer */
157    vg_assert(rsp == (Addr)&frame->returnAddr);
158    VG_(set_SP)(tid, rsp);
159    VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(ULong));
160 
161    /* Set up program counter */
162    VG_(set_IP)(tid, (ULong)handler);
163    VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(ULong));
164 
165    /* Set up RA and args for the frame */
166    VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
167              (Addr)frame, 1*sizeof(ULong) );
168    frame->returnAddr  = (ULong)&VG_(amd64_darwin_SUBST_FOR_sigreturn);
169 
170    /* XXX should tell the tool that these regs got written */
171    tst->arch.vex.guest_RDI = (ULong) sigNo;
172    tst->arch.vex.guest_RSI = (Addr)  &frame->fake_siginfo;/* oh well */
173    tst->arch.vex.guest_RDX = (Addr)  &frame->fake_ucontext; /* oh well */
174 
175    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
176              (Addr)frame, 1*sizeof(ULong) );
177    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
178              (Addr)&frame->fake_siginfo, sizeof(frame->fake_siginfo));
179    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
180              (Addr)&frame->fake_ucontext, sizeof(frame->fake_ucontext));
181 
182    if (VG_(clo_trace_signals))
183       VG_(message)(Vg_DebugMsg,
184                    "sigframe_create (thread %d): next EIP=%#lx, next ESP=%#lx",
185                    tid, (Addr)handler, (Addr)frame );
186 }
187 
188 
189 /* Remove a signal frame from thread 'tid's stack, and restore the CPU
190    state from it.  Note, isRT is irrelevant here. */
VG_(sigframe_destroy)191 void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
192 {
193    ThreadState *tst;
194    Addr rsp;
195    Int sigNo;
196    struct hacky_sigframe* frame;
197 
198    vg_assert(VG_(is_valid_tid)(tid));
199    tst = VG_(get_ThreadState)(tid);
200 
201    /* Check that the stack frame looks valid */
202    rsp = VG_(get_SP)(tid);
203 
204    /* why -8 ? because the signal handler's return will have popped
205       the return address of the stack; and the return address is the
206       lowest-addressed element of hacky_sigframe. */
207    frame = (struct hacky_sigframe*)(rsp - 8);
208    vg_assert(frame->magicPI == 0x31415927);
209    vg_assert(VG_IS_16_ALIGNED(frame));
210 
211    /* restore the entire guest state, and shadows, from the
212       frame.  Note, as per comments above, this is a kludge - should
213       restore it from saved ucontext.  Oh well. */
214    tst->arch.vex = frame->gst;
215    tst->arch.vex_shadow1 = frame->gshadow1;
216    tst->arch.vex_shadow2 = frame->gshadow2;
217    tst->sig_mask = frame->mask;
218    tst->tmp_sig_mask = frame->mask;
219    sigNo = frame->sigNo_private;
220 
221    if (VG_(clo_trace_signals))
222       VG_(message)(Vg_DebugMsg,
223                    "sigframe_destroy (thread %d): valid magic; next RIP=%#llx",
224                    tid, tst->arch.vex.guest_RIP);
225 
226    VG_TRACK( die_mem_stack_signal,
227              (Addr)frame - VG_STACK_REDZONE_SZB,
228              sizeof(struct hacky_sigframe) );
229 
230    /* tell the tools */
231    VG_TRACK( post_deliver_signal, tid, sigNo );
232 }
233 
234 #endif // defined(VGP_amd64_darwin)
235 
236 /*--------------------------------------------------------------------*/
237 /*--- end                                  sigframe-amd64-darwin.c ---*/
238 /*--------------------------------------------------------------------*/
239