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