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-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_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#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 x86-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 four words look like a call to a 3-arg x86 function */ 63 UInt returnAddr; 64 UInt a1_signo; 65 UInt a2_siginfo; 66 UInt a3_ucontext; 67 UChar lower_guardzone[512]; // put nothing here 68 VexGuestX86State vex; 69 VexGuestX86State vex_shadow1; 70 VexGuestX86State vex_shadow2; 71 vki_siginfo_t fake_siginfo; 72 struct vki_ucontext fake_ucontext; 73 UInt magicPI; 74 UInt sigNo_private; 75 vki_sigset_t mask; // saved sigmask; restore when hdlr returns 76 UInt __pad[3]; 77 UChar upper_guardzone[512]; // put nothing here 78 // and don't zero it, since that might overwrite the client's 79 // stack redzone, at least on archs which have one 80}; 81 82/* Create a plausible-looking sigcontext from the thread's 83 Vex guest state. NOTE: does not fill in the FP or SSE 84 bits of sigcontext at the moment. 85 */ 86static void synthesize_ucontext(ThreadState *tst, 87 struct vki_ucontext *uc, 88 const struct vki_ucontext *siguc) 89{ 90 VG_(memset)(uc, 0, sizeof(*uc)); 91 92 if (siguc) uc->uc_sigmask = siguc->uc_sigmask; 93 uc->uc_stack = tst->altstack; 94 uc->uc_mcontext = &uc->__mcontext_data; 95 96# define SC2(reg,REG) uc->__mcontext_data.__ss.reg = tst->arch.vex.guest_##REG 97 SC2(__edi,EDI); 98 SC2(__esi,ESI); 99 SC2(__ebp,EBP); 100 SC2(__ebx,EBX); 101 SC2(__edx,EDX); 102 SC2(__eax,EAX); 103 SC2(__ecx,ECX); 104 SC2(__esp,ESP); 105 SC2(__eip,EIP); 106 uc->__mcontext_data.__ss.__eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex); 107 108 if (siguc) 109 uc->__mcontext_data.__es = siguc->__mcontext_data.__es; 110# undef SC2 111} 112 113static void restore_from_ucontext(ThreadState *tst, 114 const struct vki_ucontext *uc) 115{ 116# define SC2(REG,reg) tst->arch.vex.guest_##REG = uc->__mcontext_data.__ss.reg 117 SC2(EDI,__edi); 118 SC2(ESI,__esi); 119 SC2(EBP,__ebp); 120 SC2(EBX,__ebx); 121 SC2(EDX,__edx); 122 SC2(EAX,__eax); 123 SC2(ECX,__ecx); 124 SC2(ESP,__esp); 125 SC2(EIP,__eip); 126 /* There doesn't seem to be an easy way to restore eflags */ 127# undef SC2 128} 129 130/* Create a signal frame for thread 'tid'. Make a 3-arg frame 131 regardless of whether the client originally requested a 1-arg 132 version (no SA_SIGINFO) or a 3-arg one (SA_SIGINFO) since in the 133 former case, the x86 calling conventions will simply cause the 134 extra 2 args to be ignored (inside the handler). */ 135void VG_(sigframe_create) ( ThreadId tid, 136 Bool on_altstack, 137 Addr sp_top_of_frame, 138 const vki_siginfo_t *siginfo, 139 const struct vki_ucontext *siguc, 140 void *handler, 141 UInt flags, 142 const vki_sigset_t *mask, 143 void *restorer ) 144{ 145 ThreadState* tst; 146 Addr esp; 147 struct hacky_sigframe* frame; 148 Int sigNo = siginfo->si_signo; 149 150 vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe))); 151 152 sp_top_of_frame &= ~0xf; 153 esp = sp_top_of_frame - sizeof(struct hacky_sigframe); 154 esp -= 4; /* ELF ABI says that esp+4 must be 16 aligned on 155 entry to a function. */ 156 157 tst = VG_(get_ThreadState)(tid); 158 if (! ML_(sf_maybe_extend_stack)(tst, esp, sp_top_of_frame - esp, flags)) 159 return; 160 161 vg_assert(VG_IS_16_ALIGNED(esp+4)); 162 163 frame = (struct hacky_sigframe *) esp; 164 165 /* clear it (very conservatively) */ 166 VG_(memset)(&frame->lower_guardzone, 0, sizeof frame->lower_guardzone); 167 VG_(memset)(&frame->vex, 0, sizeof(VexGuestX86State)); 168 VG_(memset)(&frame->vex_shadow1, 0, sizeof(VexGuestX86State)); 169 VG_(memset)(&frame->vex_shadow2, 0, sizeof(VexGuestX86State)); 170 VG_(memset)(&frame->fake_siginfo, 0, sizeof(frame->fake_siginfo)); 171 VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext)); 172 173 /* save stuff in frame */ 174 frame->vex = tst->arch.vex; 175 frame->vex_shadow1 = tst->arch.vex_shadow1; 176 frame->vex_shadow2 = tst->arch.vex_shadow2; 177 frame->sigNo_private = sigNo; 178 frame->mask = tst->sig_mask; 179 frame->magicPI = 0x31415927; 180 181 /* Fill in the siginfo and ucontext. */ 182 synthesize_ucontext(tst, &frame->fake_ucontext, siguc); 183 frame->fake_siginfo = *siginfo; 184 185 /* Set up stack pointer */ 186 vg_assert(esp == (Addr)&frame->returnAddr); 187 VG_(set_SP)(tid, esp); 188 VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(UInt)); 189 190 /* Set up program counter */ 191 VG_(set_IP)(tid, (UInt)handler); 192 VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(UInt)); 193 194 /* Set up RA and args for the frame */ 195 VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame", 196 (Addr)frame, 4*sizeof(UInt) ); 197 frame->returnAddr = (UInt)&VG_(x86_darwin_SUBST_FOR_sigreturn); 198 199 frame->a1_signo = sigNo; 200 frame->a2_siginfo = (UInt) &frame->fake_siginfo; 201 frame->a3_ucontext = (UInt) &frame->fake_ucontext; 202 203 VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 204 (Addr)frame, 4*sizeof(UInt) ); 205 VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 206 (Addr)&frame->fake_siginfo, sizeof(frame->fake_siginfo)); 207 VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 208 (Addr)&frame->fake_ucontext, sizeof(frame->fake_ucontext)); 209 210 if (VG_(clo_trace_signals)) 211 VG_(message)(Vg_DebugMsg, 212 "sigframe_create (thread %u): " 213 "next EIP=%#lx, next ESP=%#lx\n", 214 tid, (Addr)handler, (Addr)frame ); 215} 216 217 218/* Remove a signal frame from thread 'tid's stack, and restore the CPU 219 state from it. Note, isRT is irrelevant here. */ 220void VG_(sigframe_destroy)( ThreadId tid, Bool isRT ) 221{ 222 ThreadState *tst; 223 Addr esp; 224 Int sigNo; 225 struct hacky_sigframe* frame; 226 227 vg_assert(VG_(is_valid_tid)(tid)); 228 tst = VG_(get_ThreadState)(tid); 229 230 /* Check that the stack frame looks valid */ 231 esp = VG_(get_SP)(tid); 232 233 /* why -4 ? because the signal handler's return will have popped 234 the return address off the stack; and the return address is the 235 lowest-addressed element of hacky_sigframe. */ 236 frame = (struct hacky_sigframe*)(esp - 4); 237 vg_assert(frame->magicPI == 0x31415927); 238 239 /* This +4 is because of the -4 referred to in the ELF ABI comment 240 in VG_(sigframe_create) just above. */ 241 vg_assert(VG_IS_16_ALIGNED((Addr)frame + 4)); 242 243 /* restore the entire guest state, and shadows, from the frame. */ 244 tst->arch.vex = frame->vex; 245 tst->arch.vex_shadow1 = frame->vex_shadow1; 246 tst->arch.vex_shadow2 = frame->vex_shadow2; 247 restore_from_ucontext(tst, &frame->fake_ucontext); 248 249 tst->sig_mask = frame->mask; 250 tst->tmp_sig_mask = frame->mask; 251 sigNo = frame->sigNo_private; 252 253 if (VG_(clo_trace_signals)) 254 VG_(message)(Vg_DebugMsg, 255 "sigframe_destroy (thread %u): " 256 "valid magic; next EIP=%#x\n", 257 tid, tst->arch.vex.guest_EIP); 258 259 VG_TRACK( die_mem_stack_signal, 260 (Addr)frame - VG_STACK_REDZONE_SZB, 261 sizeof(struct hacky_sigframe) ); 262 263 /* tell the tools */ 264 VG_TRACK( post_deliver_signal, tid, sigNo ); 265} 266 267#endif // defined(VGP_x86_darwin) 268 269/*--------------------------------------------------------------------*/ 270/*--- end ---*/ 271/*--------------------------------------------------------------------*/ 272