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