sigframe-x86-darwin.c revision 7d4a28b986eaf98814c530a2074e117145b14d1f
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_libcsetjmp.h" // to keep _threadstate.h happy 38#include "pub_core_threadstate.h" 39#include "pub_core_aspacemgr.h" 40#include "pub_core_libcbase.h" 41#include "pub_core_libcassert.h" 42#include "pub_core_libcprint.h" 43#include "pub_core_machine.h" 44#include "pub_core_options.h" 45#include "pub_core_signals.h" 46#include "pub_core_tooliface.h" 47#include "pub_core_trampoline.h" 48#include "pub_core_sigframe.h" /* self */ 49 50 51/* Cheap-ass hack copied from ppc32-aix5 code, just to get started. 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. Kludgey; the machine state ought to be saved in a 56 ucontext and retrieved from it later, so the handler can modify it 57 and return. However .. for now .. just stick the vex guest state 58 in the frame and snarf it again later. 59 60 Also, don't bother with creating siginfo and ucontext in the 61 handler, although do point them somewhere non-faulting. 62 63 Frame should have a 16-aligned size, just in case that turns out to 64 be important for Darwin. (be conservative) 65*/ 66struct hacky_sigframe { 67 /* first four words look like a call to a 3-arg x86 function */ 68 UInt returnAddr; 69 UInt a1_signo; 70 UInt a2_siginfo; 71 UInt a3_ucontext; 72 UChar lower_guardzone[512]; // put nothing here 73 VexGuestX86State gst; 74 VexGuestX86State gshadow1; 75 VexGuestX86State gshadow2; 76 vki_siginfo_t fake_siginfo; 77 struct vki_ucontext fake_ucontext; 78 UInt magicPI; 79 UInt sigNo_private; 80 vki_sigset_t mask; // saved sigmask; restore when hdlr returns 81 UInt __pad[1]; 82 UChar upper_guardzone[512]; // put nothing here 83 // and don't zero it, since that might overwrite the client's 84 // stack redzone, at least on archs which have one 85}; 86 87 88/* Create a signal frame for thread 'tid'. Make a 3-arg frame 89 regardless of whether the client originally requested a 1-arg 90 version (no SA_SIGINFO) or a 3-arg one (SA_SIGINFO) since in the 91 former case, the x86 calling conventions will simply cause the 92 extra 2 args to be ignored (inside the handler). */ 93void VG_(sigframe_create) ( ThreadId tid, 94 Addr sp_top_of_frame, 95 const vki_siginfo_t *siginfo, 96 const struct vki_ucontext *siguc, 97 void *handler, 98 UInt flags, 99 const vki_sigset_t *mask, 100 void *restorer ) 101{ 102 ThreadState* tst; 103 Addr esp; 104 struct hacky_sigframe* frame; 105 Int sigNo = siginfo->si_signo; 106 107 vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe))); 108 109 sp_top_of_frame &= ~0xf; 110 esp = sp_top_of_frame - sizeof(struct hacky_sigframe); 111 esp -= 4; /* ELF ABI says that esp+4 must be 16 aligned on 112 entry to a function. */ 113 114 tst = VG_(get_ThreadState)(tid); 115 if (! ML_(sf_maybe_extend_stack)(tst, esp, sp_top_of_frame - esp, flags)) 116 return; 117 118 vg_assert(VG_IS_16_ALIGNED(esp+4)); 119 120 frame = (struct hacky_sigframe *) esp; 121 122 /* clear it (very conservatively) (why so conservatively??) */ 123 VG_(memset)(&frame->lower_guardzone, 0, sizeof frame->lower_guardzone); 124 VG_(memset)(&frame->gst, 0, sizeof(VexGuestX86State)); 125 VG_(memset)(&frame->gshadow1, 0, sizeof(VexGuestX86State)); 126 VG_(memset)(&frame->gshadow2, 0, sizeof(VexGuestX86State)); 127 VG_(memset)(&frame->fake_siginfo, 0, sizeof(frame->fake_siginfo)); 128 VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext)); 129 130 /* save stuff in frame */ 131 frame->gst = tst->arch.vex; 132 frame->gshadow1 = tst->arch.vex_shadow1; 133 frame->gshadow2 = tst->arch.vex_shadow2; 134 frame->sigNo_private = sigNo; 135 frame->mask = tst->sig_mask; 136 frame->magicPI = 0x31415927; 137 138 /* Minimally fill in the siginfo and ucontext. Note, utter 139 lameness prevails. Be underwhelmed, be very underwhelmed. */ 140 frame->fake_siginfo.si_signo = sigNo; 141 frame->fake_siginfo.si_code = siginfo->si_code; 142 143 /* Set up stack pointer */ 144 vg_assert(esp == (Addr)&frame->returnAddr); 145 VG_(set_SP)(tid, esp); 146 VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(UInt)); 147 148 /* Set up program counter */ 149 VG_(set_IP)(tid, (UInt)handler); 150 VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(UInt)); 151 152 /* Set up RA and args for the frame */ 153 VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame", 154 (Addr)frame, 4*sizeof(UInt) ); 155 frame->returnAddr = (UInt)&VG_(x86_darwin_SUBST_FOR_sigreturn); 156 frame->a1_signo = sigNo; 157 frame->a2_siginfo = (UInt)&frame->fake_siginfo; /* oh well */ 158 frame->a3_ucontext = (UInt)&frame->fake_ucontext; /* oh well */ 159 VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 160 (Addr)frame, 4*sizeof(UInt) ); 161 VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 162 (Addr)&frame->fake_siginfo, sizeof(frame->fake_siginfo)); 163 VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 164 (Addr)&frame->fake_ucontext, sizeof(frame->fake_ucontext)); 165 166 if (VG_(clo_trace_signals)) 167 VG_(message)(Vg_DebugMsg, 168 "sigframe_create (thread %d): " 169 "next EIP=%#lx, next ESP=%#lx\n", 170 tid, (Addr)handler, (Addr)frame ); 171} 172 173 174/* Remove a signal frame from thread 'tid's stack, and restore the CPU 175 state from it. Note, isRT is irrelevant here. */ 176void VG_(sigframe_destroy)( ThreadId tid, Bool isRT ) 177{ 178 ThreadState *tst; 179 Addr esp; 180 Int sigNo; 181 struct hacky_sigframe* frame; 182 183 vg_assert(VG_(is_valid_tid)(tid)); 184 tst = VG_(get_ThreadState)(tid); 185 186 /* Check that the stack frame looks valid */ 187 esp = VG_(get_SP)(tid); 188 189 /* why -4 ? because the signal handler's return will have popped 190 the return address off the stack; and the return address is the 191 lowest-addressed element of hacky_sigframe. */ 192 frame = (struct hacky_sigframe*)(esp - 4); 193 vg_assert(frame->magicPI == 0x31415927); 194 195 /* This +8 is because of the -4 referred to in the ELF ABI comment 196 in VG_(sigframe_create) just above. */ 197 vg_assert(VG_IS_16_ALIGNED((Addr)frame + 4)); 198 199 /* restore the entire guest state, and shadows, from the 200 frame. Note, as per comments above, this is a kludge - should 201 restore it from saved ucontext. Oh well. */ 202 tst->arch.vex = frame->gst; 203 tst->arch.vex_shadow1 = frame->gshadow1; 204 tst->arch.vex_shadow2 = frame->gshadow2; 205 tst->sig_mask = frame->mask; 206 tst->tmp_sig_mask = frame->mask; 207 sigNo = frame->sigNo_private; 208 209 if (VG_(clo_trace_signals)) 210 VG_(message)(Vg_DebugMsg, 211 "sigframe_destroy (thread %d): " 212 "valid magic; next EIP=%#x\n", 213 tid, tst->arch.vex.guest_EIP); 214 215 VG_TRACK( die_mem_stack_signal, 216 (Addr)frame - VG_STACK_REDZONE_SZB, 217 sizeof(struct hacky_sigframe) ); 218 219 /* tell the tools */ 220 VG_TRACK( post_deliver_signal, tid, sigNo ); 221} 222 223#endif // defined(VGP_x86_darwin) 224 225/*--------------------------------------------------------------------*/ 226/*--- end ---*/ 227/*--------------------------------------------------------------------*/ 228