1 
2 /*--------------------------------------------------------------------*/
3 /*--- Create/destroy signal delivery frames.                       ---*/
4 /*---                                        sigframe-x86-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_x86_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 x86-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 four words look like a call to a 3-arg x86 function */
67    UInt             returnAddr;
68    UInt             a1_signo;
69    UInt             a2_siginfo;
70    UInt             a3_ucontext;
71    UChar            lower_guardzone[512];  // put nothing here
72    VexGuestX86State gst;
73    VexGuestX86State gshadow1;
74    VexGuestX86State gshadow2;
75    vki_siginfo_t    fake_siginfo;
76    struct vki_ucontext fake_ucontext;
77    UInt             magicPI;
78    UInt             sigNo_private;
79    vki_sigset_t     mask; // saved sigmask; restore when hdlr returns
80    UInt             __pad[1];
81    UChar            upper_guardzone[512]; // put nothing here
82    // and don't zero it, since that might overwrite the client's
83    // stack redzone, at least on archs which have one
84 };
85 
86 
87 /* Create a signal frame for thread 'tid'.  Make a 3-arg frame
88    regardless of whether the client originally requested a 1-arg
89    version (no SA_SIGINFO) or a 3-arg one (SA_SIGINFO) since in the
90    former case, the x86 calling conventions will simply cause the
91    extra 2 args to be ignored (inside the handler). */
VG_(sigframe_create)92 void VG_(sigframe_create) ( ThreadId tid,
93                             Addr sp_top_of_frame,
94                             const vki_siginfo_t *siginfo,
95                             const struct vki_ucontext *siguc,
96                             void *handler,
97                             UInt flags,
98                             const vki_sigset_t *mask,
99                             void *restorer )
100 {
101    ThreadState* tst;
102    Addr esp;
103    struct hacky_sigframe* frame;
104    Int sigNo = siginfo->si_signo;
105 
106    vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
107 
108    sp_top_of_frame &= ~0xf;
109    esp = sp_top_of_frame - sizeof(struct hacky_sigframe);
110    esp -= 4; /* ELF ABI says that esp+4 must be 16 aligned on
111                 entry to a function. */
112 
113    tst = VG_(get_ThreadState)(tid);
114    if (! ML_(sf_maybe_extend_stack)(tst, esp, sp_top_of_frame - esp, flags))
115       return;
116 
117    vg_assert(VG_IS_16_ALIGNED(esp+4));
118 
119    frame = (struct hacky_sigframe *) esp;
120 
121    /* clear it (very conservatively) (why so conservatively??) */
122    VG_(memset)(&frame->lower_guardzone, 0, sizeof frame->lower_guardzone);
123    VG_(memset)(&frame->gst,      0, sizeof(VexGuestX86State));
124    VG_(memset)(&frame->gshadow1, 0, sizeof(VexGuestX86State));
125    VG_(memset)(&frame->gshadow2, 0, sizeof(VexGuestX86State));
126    VG_(memset)(&frame->fake_siginfo,  0, sizeof(frame->fake_siginfo));
127    VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext));
128 
129    /* save stuff in frame */
130    frame->gst           = tst->arch.vex;
131    frame->gshadow1      = tst->arch.vex_shadow1;
132    frame->gshadow2      = tst->arch.vex_shadow2;
133    frame->sigNo_private = sigNo;
134    frame->mask          = tst->sig_mask;
135    frame->magicPI       = 0x31415927;
136 
137    /* Minimally fill in the siginfo and ucontext.  Note, utter
138       lameness prevails.  Be underwhelmed, be very underwhelmed. */
139    frame->fake_siginfo.si_signo = sigNo;
140    frame->fake_siginfo.si_code  = siginfo->si_code;
141 
142    /* Set up stack pointer */
143    vg_assert(esp == (Addr)&frame->returnAddr);
144    VG_(set_SP)(tid, esp);
145    VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(UInt));
146 
147    /* Set up program counter */
148    VG_(set_IP)(tid, (UInt)handler);
149    VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(UInt));
150 
151    /* Set up RA and args for the frame */
152    VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
153              (Addr)frame, 4*sizeof(UInt) );
154    frame->returnAddr  = (UInt)&VG_(x86_darwin_SUBST_FOR_sigreturn);
155    frame->a1_signo    = sigNo;
156    frame->a2_siginfo  = (UInt)&frame->fake_siginfo;  /* oh well */
157    frame->a3_ucontext = (UInt)&frame->fake_ucontext; /* oh well */
158    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
159              (Addr)frame, 4*sizeof(UInt) );
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 esp;
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    esp = VG_(get_SP)(tid);
187 
188    /* why -4 ? 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*)(esp - 4);
192    vg_assert(frame->magicPI == 0x31415927);
193 
194    /* This +8 is because of the -4 referred to in the ELF ABI comment
195       in VG_(sigframe_create) just above. */
196    vg_assert(VG_IS_16_ALIGNED((Addr)frame + 4));
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 EIP=%#x\n",
212                    tid, tst->arch.vex.guest_EIP);
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_x86_darwin)
223 
224 /*--------------------------------------------------------------------*/
225 /*--- end                                                          ---*/
226 /*--------------------------------------------------------------------*/
227