njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 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 | |
sewardj | 03f8d3f | 2012-08-05 15:46:46 +0000 | [diff] [blame] | 11 | Copyright (C) 2006-2012 OpenWorks Ltd |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 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 | |
njn | 8b68b64 | 2009-06-24 00:37:09 +0000 | [diff] [blame] | 32 | #if defined(VGP_amd64_darwin) |
| 33 | |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 34 | #include "pub_core_basics.h" |
| 35 | #include "pub_core_vki.h" |
| 36 | #include "pub_core_vkiscnums.h" |
sewardj | 38a2859 | 2011-04-11 22:08:06 +0000 | [diff] [blame] | 37 | #include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 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 | |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 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 amd64-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 | */ |
| 66 | struct hacky_sigframe { |
| 67 | /* first word looks like a call to a 3-arg amd64-ELF function */ |
| 68 | ULong returnAddr; |
| 69 | UChar lower_guardzone[512]; // put nothing here |
| 70 | VexGuestAMD64State gst; |
| 71 | VexGuestAMD64State gshadow1; |
| 72 | VexGuestAMD64State gshadow2; |
| 73 | vki_siginfo_t fake_siginfo; |
| 74 | struct vki_ucontext fake_ucontext; |
| 75 | UInt magicPI; |
| 76 | UInt sigNo_private; |
| 77 | vki_sigset_t mask; // saved sigmask; restore when hdlr returns |
| 78 | UInt __pad[2]; |
| 79 | UChar upper_guardzone[512]; // put nothing here |
| 80 | // and don't zero it, since that might overwrite the client's |
| 81 | // stack redzone, at least on archs which have one |
| 82 | }; |
| 83 | |
| 84 | |
| 85 | /* Extend the stack segment downwards if needed so as to ensure the |
| 86 | new signal frames are mapped to something. Return a Bool |
| 87 | indicating whether or not the operation was successful. |
| 88 | */ |
| 89 | static Bool extend ( ThreadState *tst, Addr addr, SizeT size ) |
| 90 | { |
| 91 | ThreadId tid = tst->tid; |
| 92 | /* For tracking memory events, indicate the entire frame has been |
| 93 | allocated. Except, don't mess with the area which |
| 94 | overlaps the previous frame's redzone. */ |
| 95 | /* XXX is the following call really right? compared with the |
| 96 | amd64-linux version, this doesn't appear to handle the redzone |
| 97 | in the same way. */ |
| 98 | VG_TRACK( new_mem_stack_signal, |
| 99 | addr - VG_STACK_REDZONE_SZB, size, tid ); |
| 100 | return True; |
| 101 | } |
| 102 | |
| 103 | |
| 104 | /* Create a signal frame for thread 'tid'. Make a 3-arg frame |
| 105 | regardless of whether the client originally requested a 1-arg |
| 106 | version (no SA_SIGINFO) or a 3-arg one (SA_SIGINFO) since in the |
| 107 | former case, the amd64 calling conventions will simply cause the |
| 108 | extra 2 args to be ignored (inside the handler). (We hope!) */ |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 109 | void VG_(sigframe_create) ( ThreadId tid, |
| 110 | Addr sp_top_of_frame, |
| 111 | const vki_siginfo_t *siginfo, |
| 112 | const struct vki_ucontext *siguc, |
| 113 | void *handler, |
| 114 | UInt flags, |
| 115 | const vki_sigset_t *mask, |
| 116 | void *restorer ) |
| 117 | { |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 118 | ThreadState* tst; |
| 119 | Addr rsp; |
| 120 | struct hacky_sigframe* frame; |
| 121 | Int sigNo = siginfo->si_signo; |
| 122 | |
| 123 | vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe))); |
| 124 | |
| 125 | sp_top_of_frame &= ~0xfUL; |
| 126 | rsp = sp_top_of_frame - sizeof(struct hacky_sigframe); |
sewardj | 06728c8 | 2012-03-27 09:24:54 +0000 | [diff] [blame] | 127 | rsp -= 8; /* ELF ABI says that rsp+8 must be 16 aligned on |
| 128 | entry to a function. */ |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 129 | |
| 130 | tst = VG_(get_ThreadState)(tid); |
| 131 | if (!extend(tst, rsp, sp_top_of_frame - rsp)) |
| 132 | return; |
| 133 | |
sewardj | 06728c8 | 2012-03-27 09:24:54 +0000 | [diff] [blame] | 134 | vg_assert(VG_IS_16_ALIGNED(rsp+8)); |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 135 | |
| 136 | frame = (struct hacky_sigframe *) rsp; |
| 137 | |
| 138 | /* clear it (very conservatively) (why so conservatively??) */ |
| 139 | VG_(memset)(&frame->lower_guardzone, 0, 512); |
| 140 | VG_(memset)(&frame->gst, 0, sizeof(VexGuestAMD64State)); |
| 141 | VG_(memset)(&frame->gshadow1, 0, sizeof(VexGuestAMD64State)); |
| 142 | VG_(memset)(&frame->gshadow2, 0, sizeof(VexGuestAMD64State)); |
| 143 | VG_(memset)(&frame->fake_siginfo, 0, sizeof(frame->fake_siginfo)); |
| 144 | VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext)); |
| 145 | |
| 146 | /* save stuff in frame */ |
| 147 | frame->gst = tst->arch.vex; |
| 148 | frame->gshadow1 = tst->arch.vex_shadow1; |
| 149 | frame->gshadow2 = tst->arch.vex_shadow2; |
| 150 | frame->sigNo_private = sigNo; |
| 151 | frame->mask = tst->sig_mask; |
| 152 | frame->magicPI = 0x31415927; |
| 153 | |
| 154 | /* Minimally fill in the siginfo and ucontext. Note, utter |
| 155 | lameness prevails. Be underwhelmed, be very underwhelmed. */ |
| 156 | frame->fake_siginfo.si_signo = sigNo; |
| 157 | frame->fake_siginfo.si_code = siginfo->si_code; |
| 158 | |
| 159 | /* Set up stack pointer */ |
| 160 | vg_assert(rsp == (Addr)&frame->returnAddr); |
| 161 | VG_(set_SP)(tid, rsp); |
| 162 | VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(ULong)); |
| 163 | |
| 164 | /* Set up program counter */ |
| 165 | VG_(set_IP)(tid, (ULong)handler); |
| 166 | VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(ULong)); |
| 167 | |
| 168 | /* Set up RA and args for the frame */ |
| 169 | VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame", |
| 170 | (Addr)frame, 1*sizeof(ULong) ); |
| 171 | frame->returnAddr = (ULong)&VG_(amd64_darwin_SUBST_FOR_sigreturn); |
| 172 | |
| 173 | /* XXX should tell the tool that these regs got written */ |
| 174 | tst->arch.vex.guest_RDI = (ULong) sigNo; |
| 175 | tst->arch.vex.guest_RSI = (Addr) &frame->fake_siginfo;/* oh well */ |
| 176 | tst->arch.vex.guest_RDX = (Addr) &frame->fake_ucontext; /* oh well */ |
| 177 | |
| 178 | VG_TRACK( post_mem_write, Vg_CoreSignal, tid, |
| 179 | (Addr)frame, 1*sizeof(ULong) ); |
| 180 | VG_TRACK( post_mem_write, Vg_CoreSignal, tid, |
| 181 | (Addr)&frame->fake_siginfo, sizeof(frame->fake_siginfo)); |
| 182 | VG_TRACK( post_mem_write, Vg_CoreSignal, tid, |
| 183 | (Addr)&frame->fake_ucontext, sizeof(frame->fake_ucontext)); |
| 184 | |
| 185 | if (VG_(clo_trace_signals)) |
| 186 | VG_(message)(Vg_DebugMsg, |
sewardj | 9d061d0 | 2012-03-27 09:39:04 +0000 | [diff] [blame] | 187 | "sigframe_create (thread %d): " |
| 188 | "next EIP=%#lx, next ESP=%#lx\n", |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 189 | tid, (Addr)handler, (Addr)frame ); |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 190 | } |
| 191 | |
| 192 | |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 193 | /* Remove a signal frame from thread 'tid's stack, and restore the CPU |
| 194 | state from it. Note, isRT is irrelevant here. */ |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 195 | void VG_(sigframe_destroy)( ThreadId tid, Bool isRT ) |
| 196 | { |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 197 | ThreadState *tst; |
| 198 | Addr rsp; |
| 199 | Int sigNo; |
| 200 | struct hacky_sigframe* frame; |
| 201 | |
| 202 | vg_assert(VG_(is_valid_tid)(tid)); |
| 203 | tst = VG_(get_ThreadState)(tid); |
| 204 | |
| 205 | /* Check that the stack frame looks valid */ |
| 206 | rsp = VG_(get_SP)(tid); |
| 207 | |
| 208 | /* why -8 ? because the signal handler's return will have popped |
sewardj | 06728c8 | 2012-03-27 09:24:54 +0000 | [diff] [blame] | 209 | the return address off the stack; and the return address is the |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 210 | lowest-addressed element of hacky_sigframe. */ |
| 211 | frame = (struct hacky_sigframe*)(rsp - 8); |
| 212 | vg_assert(frame->magicPI == 0x31415927); |
sewardj | 06728c8 | 2012-03-27 09:24:54 +0000 | [diff] [blame] | 213 | |
| 214 | /* This +8 is because of the -8 referred to in the ELF ABI comment |
| 215 | in VG_(sigframe_create) just above. */ |
| 216 | vg_assert(VG_IS_16_ALIGNED((Addr)frame + 8)); |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 217 | |
| 218 | /* restore the entire guest state, and shadows, from the |
| 219 | frame. Note, as per comments above, this is a kludge - should |
| 220 | restore it from saved ucontext. Oh well. */ |
| 221 | tst->arch.vex = frame->gst; |
| 222 | tst->arch.vex_shadow1 = frame->gshadow1; |
| 223 | tst->arch.vex_shadow2 = frame->gshadow2; |
| 224 | tst->sig_mask = frame->mask; |
| 225 | tst->tmp_sig_mask = frame->mask; |
| 226 | sigNo = frame->sigNo_private; |
| 227 | |
| 228 | if (VG_(clo_trace_signals)) |
| 229 | VG_(message)(Vg_DebugMsg, |
sewardj | 9d061d0 | 2012-03-27 09:39:04 +0000 | [diff] [blame] | 230 | "sigframe_destroy (thread %d): " |
| 231 | "valid magic; next RIP=%#llx\n", |
njn | ea2d6fd | 2010-07-01 00:20:20 +0000 | [diff] [blame] | 232 | tid, tst->arch.vex.guest_RIP); |
| 233 | |
| 234 | VG_TRACK( die_mem_stack_signal, |
| 235 | (Addr)frame - VG_STACK_REDZONE_SZB, |
| 236 | sizeof(struct hacky_sigframe) ); |
| 237 | |
| 238 | /* tell the tools */ |
| 239 | VG_TRACK( post_deliver_signal, tid, sigNo ); |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 240 | } |
| 241 | |
njn | 8b68b64 | 2009-06-24 00:37:09 +0000 | [diff] [blame] | 242 | #endif // defined(VGP_amd64_darwin) |
| 243 | |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 244 | /*--------------------------------------------------------------------*/ |
| 245 | /*--- end sigframe-amd64-darwin.c ---*/ |
| 246 | /*--------------------------------------------------------------------*/ |