Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1 | |
| 2 | /*--------------------------------------------------------------------*/ |
| 3 | /*--- Create/destroy signal delivery frames. ---*/ |
| 4 | /*--- sigframe-arm-linux.c ---*/ |
| 5 | /*--------------------------------------------------------------------*/ |
| 6 | |
| 7 | /* |
| 8 | This file is part of Valgrind, a dynamic binary instrumentation |
| 9 | framework. |
| 10 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame^] | 11 | Copyright (C) 2000-2012 Nicholas Nethercote |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 12 | njn@valgrind.org |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame^] | 13 | Copyright (C) 2004-2012 Paul Mackerras |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 14 | paulus@samba.org |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame^] | 15 | Copyright (C) 2008-2012 Evan Geller |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 16 | gaze@bea.ms |
| 17 | |
| 18 | This program is free software; you can redistribute it and/or |
| 19 | modify it under the terms of the GNU General Public License as |
| 20 | published by the Free Software Foundation; either version 2 of the |
| 21 | License, or (at your option) any later version. |
| 22 | |
| 23 | This program is distributed in the hope that it will be useful, but |
| 24 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 26 | General Public License for more details. |
| 27 | |
| 28 | You should have received a copy of the GNU General Public License |
| 29 | along with this program; if not, write to the Free Software |
| 30 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 31 | 02111-1307, USA. |
| 32 | |
| 33 | The GNU General Public License is contained in the file COPYING. |
| 34 | */ |
| 35 | |
| 36 | #if defined(VGP_arm_linux) |
| 37 | |
| 38 | #include "pub_core_basics.h" |
| 39 | #include "pub_core_vki.h" |
| 40 | #include "pub_core_vkiscnums.h" |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 41 | #include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 42 | #include "pub_core_threadstate.h" |
| 43 | #include "pub_core_aspacemgr.h" |
| 44 | #include "pub_core_libcbase.h" |
| 45 | #include "pub_core_libcassert.h" |
| 46 | #include "pub_core_libcprint.h" |
| 47 | #include "pub_core_machine.h" |
| 48 | #include "pub_core_options.h" |
| 49 | #include "pub_core_sigframe.h" |
| 50 | #include "pub_core_signals.h" |
| 51 | #include "pub_core_tooliface.h" |
| 52 | #include "pub_core_trampoline.h" |
| 53 | #include "pub_core_transtab.h" // VG_(discard_translations) |
| 54 | |
| 55 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 56 | /* This uses the hack of dumping the vex guest state along with both |
| 57 | shadows in the frame, and restoring it afterwards from there, |
| 58 | rather than pulling it out of the ucontext. That means that signal |
| 59 | handlers which modify the ucontext and then return, expecting their |
| 60 | modifications to take effect, will have those modifications |
| 61 | ignored. This could be fixed properly with an hour or so more |
| 62 | effort. */ |
| 63 | |
| 64 | |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 65 | struct vg_sig_private { |
| 66 | UInt magicPI; |
| 67 | UInt sigNo_private; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 68 | VexGuestARMState vex; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 69 | VexGuestARMState vex_shadow1; |
| 70 | VexGuestARMState vex_shadow2; |
| 71 | }; |
| 72 | |
| 73 | struct sigframe { |
| 74 | struct vki_ucontext uc; |
| 75 | unsigned long retcode[2]; |
| 76 | struct vg_sig_private vp; |
| 77 | }; |
| 78 | |
| 79 | struct rt_sigframe { |
| 80 | vki_siginfo_t info; |
| 81 | struct sigframe sig; |
| 82 | }; |
| 83 | |
| 84 | static Bool extend ( ThreadState *tst, Addr addr, SizeT size ) |
| 85 | { |
| 86 | ThreadId tid = tst->tid; |
| 87 | NSegment const* stackseg = NULL; |
| 88 | |
| 89 | if (VG_(extend_stack)(addr, tst->client_stack_szB)) { |
| 90 | stackseg = VG_(am_find_nsegment)(addr); |
| 91 | if (0 && stackseg) |
| 92 | VG_(printf)("frame=%#lx seg=%#lx-%#lx\n", |
| 93 | addr, stackseg->start, stackseg->end); |
| 94 | } |
| 95 | |
| 96 | if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) { |
| 97 | VG_(message)( |
| 98 | Vg_UserMsg, |
| 99 | "Can't extend stack to %#lx during signal delivery for thread %d:", |
| 100 | addr, tid); |
| 101 | if (stackseg == NULL) |
| 102 | VG_(message)(Vg_UserMsg, " no stack segment"); |
| 103 | else |
| 104 | VG_(message)(Vg_UserMsg, " too small or bad protection modes"); |
| 105 | |
| 106 | /* set SIGSEGV to default handler */ |
| 107 | VG_(set_default_handler)(VKI_SIGSEGV); |
| 108 | VG_(synth_fault_mapping)(tid, addr); |
| 109 | |
| 110 | /* The whole process should be about to die, since the default |
| 111 | action of SIGSEGV to kill the whole process. */ |
| 112 | return False; |
| 113 | } |
| 114 | |
| 115 | /* For tracking memory events, indicate the entire frame has been |
| 116 | allocated. */ |
| 117 | VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB, |
| 118 | size + VG_STACK_REDZONE_SZB, tid ); |
| 119 | |
| 120 | return True; |
| 121 | } |
| 122 | |
| 123 | static void synth_ucontext( ThreadId tid, const vki_siginfo_t *si, |
| 124 | UWord trapno, UWord err, const vki_sigset_t *set, |
| 125 | struct vki_ucontext *uc){ |
| 126 | |
| 127 | ThreadState *tst = VG_(get_ThreadState)(tid); |
| 128 | struct vki_sigcontext *sc = &uc->uc_mcontext; |
| 129 | |
| 130 | VG_(memset)(uc, 0, sizeof(*uc)); |
| 131 | |
| 132 | uc->uc_flags = 0; |
| 133 | uc->uc_link = 0; |
| 134 | uc->uc_sigmask = *set; |
| 135 | uc->uc_stack = tst->altstack; |
| 136 | |
| 137 | # define SC2(reg,REG) sc->arm_##reg = tst->arch.vex.guest_##REG |
| 138 | SC2(r0,R0); |
| 139 | SC2(r1,R1); |
| 140 | SC2(r2,R2); |
| 141 | SC2(r3,R3); |
| 142 | SC2(r4,R4); |
| 143 | SC2(r5,R5); |
| 144 | SC2(r6,R6); |
| 145 | SC2(r7,R7); |
| 146 | SC2(r8,R8); |
| 147 | SC2(r9,R9); |
| 148 | SC2(r10,R10); |
| 149 | SC2(fp,R11); |
| 150 | SC2(ip,R12); |
| 151 | SC2(sp,R13); |
| 152 | SC2(lr,R14); |
| 153 | SC2(pc,R15T); |
| 154 | # undef SC2 |
| 155 | |
| 156 | sc->trap_no = trapno; |
| 157 | sc->error_code = err; |
| 158 | sc->fault_address = (UInt)si->_sifields._sigfault._addr; |
| 159 | } |
| 160 | |
| 161 | |
| 162 | static void build_sigframe(ThreadState *tst, |
| 163 | struct sigframe *frame, |
| 164 | const vki_siginfo_t *siginfo, |
| 165 | const struct vki_ucontext *siguc, |
| 166 | void *handler, UInt flags, |
| 167 | const vki_sigset_t *mask, |
| 168 | void *restorer){ |
| 169 | |
| 170 | UWord trapno; |
| 171 | UWord err; |
| 172 | Int sigNo = siginfo->si_signo; |
| 173 | struct vg_sig_private *priv = &frame->vp; |
| 174 | |
| 175 | VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame", |
| 176 | (Addr)frame, offsetof(struct sigframe, vp)); |
| 177 | |
| 178 | if(siguc) { |
| 179 | trapno = siguc->uc_mcontext.trap_no; |
| 180 | err = siguc->uc_mcontext.error_code; |
| 181 | } else { |
| 182 | trapno = 0; |
| 183 | err = 0; |
| 184 | } |
| 185 | |
| 186 | synth_ucontext(tst->tid, siginfo, trapno, err, mask, &frame->uc); |
| 187 | |
| 188 | VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, |
| 189 | (Addr)frame, offsetof(struct sigframe, vp)); |
| 190 | |
| 191 | priv->magicPI = 0x31415927; |
| 192 | priv->sigNo_private = sigNo; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 193 | priv->vex = tst->arch.vex; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 194 | priv->vex_shadow1 = tst->arch.vex_shadow1; |
| 195 | priv->vex_shadow2 = tst->arch.vex_shadow2; |
| 196 | |
| 197 | } |
| 198 | |
| 199 | |
| 200 | |
| 201 | /* EXPORTED */ |
| 202 | void VG_(sigframe_create)( ThreadId tid, |
| 203 | Addr sp_top_of_frame, |
| 204 | const vki_siginfo_t *siginfo, |
| 205 | const struct vki_ucontext *siguc, |
| 206 | void *handler, |
| 207 | UInt flags, |
| 208 | const vki_sigset_t *mask, |
| 209 | void *restorer ) |
| 210 | { |
| 211 | // struct vg_sig_private *priv; |
| 212 | Addr sp = sp_top_of_frame; |
| 213 | ThreadState *tst; |
| 214 | Int sigNo = siginfo->si_signo; |
| 215 | // Addr faultaddr; |
| 216 | UInt size; |
| 217 | |
| 218 | tst = VG_(get_ThreadState)(tid); |
| 219 | |
| 220 | size = flags & VKI_SA_SIGINFO ? sizeof(struct rt_sigframe) : |
| 221 | sizeof(struct sigframe); |
| 222 | |
| 223 | sp -= size; |
| 224 | sp = VG_ROUNDDN(sp, 16); |
| 225 | |
| 226 | if(!extend(tst, sp, size)) |
| 227 | I_die_here; // XXX Incorrect behavior |
| 228 | |
| 229 | |
| 230 | if (flags & VKI_SA_SIGINFO){ |
| 231 | struct rt_sigframe *rsf = (struct rt_sigframe *)sp; |
| 232 | |
| 233 | /* Track our writes to siginfo */ |
| 234 | VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, /* VVVVV */ |
| 235 | "signal handler siginfo", (Addr)rsf, |
| 236 | offsetof(struct rt_sigframe, sig)); |
| 237 | |
| 238 | VG_(memcpy)(&rsf->info, siginfo, sizeof(vki_siginfo_t)); |
| 239 | |
| 240 | if(sigNo == VKI_SIGILL && siginfo->si_code > 0) { |
| 241 | rsf->info._sifields._sigfault._addr = (Addr *) (tst)->arch.vex.guest_R12; /* IP */ |
| 242 | } |
| 243 | VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, /* ^^^^^ */ |
| 244 | (Addr)rsf, offsetof(struct rt_sigframe, sig)); |
| 245 | |
| 246 | build_sigframe(tst, &rsf->sig, siginfo, siguc, |
| 247 | handler, flags, mask, restorer); |
| 248 | tst->arch.vex.guest_R1 = (Addr)&rsf->info; |
| 249 | tst->arch.vex.guest_R2 = (Addr)&rsf->sig.uc; |
| 250 | } |
| 251 | else { |
| 252 | build_sigframe(tst, (struct sigframe *)sp, siginfo, siguc, |
| 253 | handler, flags, mask, restorer); |
| 254 | } |
| 255 | |
| 256 | VG_(set_SP)(tid, sp); |
| 257 | VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, |
| 258 | sizeof(Addr)); |
| 259 | tst->arch.vex.guest_R0 = sigNo; |
| 260 | |
| 261 | if (flags & VKI_SA_RESTORER) |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame^] | 262 | tst->arch.vex.guest_R14 = (Addr)restorer; |
| 263 | else |
| 264 | tst->arch.vex.guest_R14 |
| 265 | = (flags & VKI_SA_SIGINFO) |
| 266 | ? (Addr)&VG_(arm_linux_SUBST_FOR_rt_sigreturn) |
| 267 | : (Addr)&VG_(arm_linux_SUBST_FOR_sigreturn); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 268 | |
| 269 | tst->arch.vex.guest_R15T = (Addr) handler; /* R15 == PC */ |
| 270 | } |
| 271 | |
| 272 | |
| 273 | /*------------------------------------------------------------*/ |
| 274 | /*--- Destroying signal frames ---*/ |
| 275 | /*------------------------------------------------------------*/ |
| 276 | |
| 277 | /* EXPORTED */ |
| 278 | void VG_(sigframe_destroy)( ThreadId tid, Bool isRT ) |
| 279 | { |
| 280 | ThreadState *tst; |
| 281 | struct vg_sig_private *priv; |
| 282 | Addr sp; |
| 283 | UInt frame_size; |
| 284 | struct vki_sigcontext *mc; |
| 285 | Int sigNo; |
| 286 | Bool has_siginfo = isRT; |
| 287 | |
| 288 | vg_assert(VG_(is_valid_tid)(tid)); |
| 289 | tst = VG_(get_ThreadState)(tid); |
| 290 | sp = tst->arch.vex.guest_R13; |
| 291 | |
| 292 | if (has_siginfo) { |
| 293 | struct rt_sigframe *frame = (struct rt_sigframe *)sp; |
| 294 | frame_size = sizeof(*frame); |
| 295 | mc = &frame->sig.uc.uc_mcontext; |
| 296 | priv = &frame->sig.vp; |
| 297 | vg_assert(priv->magicPI == 0x31415927); |
| 298 | tst->sig_mask = frame->sig.uc.uc_sigmask; |
| 299 | } else { |
| 300 | struct sigframe *frame = (struct sigframe *)sp; |
| 301 | frame_size = sizeof(*frame); |
| 302 | mc = &frame->uc.uc_mcontext; |
| 303 | priv = &frame->vp; |
| 304 | vg_assert(priv->magicPI == 0x31415927); |
| 305 | tst->sig_mask = frame->uc.uc_sigmask; |
| 306 | /*tst->sig_mask.sig[0] = frame->uc.uc_mcontext.oldmask; |
| 307 | tst->sig_mask.sig[1] = frame->uc.uc_mcontext._unused[3]; |
| 308 | VG_(printf)("Setting signmask to %08x%08x\n",tst->sig_mask[0],tst->sig_mask[1]); |
| 309 | */ |
| 310 | } |
| 311 | tst->tmp_sig_mask = tst->sig_mask; |
| 312 | |
| 313 | sigNo = priv->sigNo_private; |
| 314 | |
| 315 | //XXX: restore regs |
| 316 | # define REST(reg,REG) tst->arch.vex.guest_##REG = mc->arm_##reg; |
| 317 | REST(r0,R0); |
| 318 | REST(r1,R1); |
| 319 | REST(r2,R2); |
| 320 | REST(r3,R3); |
| 321 | REST(r4,R4); |
| 322 | REST(r5,R5); |
| 323 | REST(r6,R6); |
| 324 | REST(r7,R7); |
| 325 | REST(r8,R8); |
| 326 | REST(r9,R9); |
| 327 | REST(r10,R10); |
| 328 | REST(fp,R11); |
| 329 | REST(ip,R12); |
| 330 | REST(sp,R13); |
| 331 | REST(lr,R14); |
| 332 | REST(pc,R15T); |
| 333 | # undef REST |
| 334 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 335 | /* Uh, the next line makes all the REST() above pointless. */ |
| 336 | tst->arch.vex = priv->vex; |
| 337 | |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 338 | tst->arch.vex_shadow1 = priv->vex_shadow1; |
| 339 | tst->arch.vex_shadow2 = priv->vex_shadow2; |
| 340 | |
| 341 | VG_TRACK( die_mem_stack_signal, sp - VG_STACK_REDZONE_SZB, |
| 342 | frame_size + VG_STACK_REDZONE_SZB ); |
| 343 | |
| 344 | if (VG_(clo_trace_signals)) |
| 345 | VG_(message)(Vg_DebugMsg, |
| 346 | "vg_pop_signal_frame (thread %d): " |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 347 | "isRT=%d valid magic; PC=%#x\n", |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 348 | tid, has_siginfo, tst->arch.vex.guest_R15T); |
| 349 | |
| 350 | /* tell the tools */ |
| 351 | VG_TRACK( post_deliver_signal, tid, sigNo ); |
| 352 | } |
| 353 | |
| 354 | #endif // defined(VGP_arm_linux) |
| 355 | |
| 356 | /*--------------------------------------------------------------------*/ |
| 357 | /*--- end sigframe-arm-linux.c ---*/ |
| 358 | /*--------------------------------------------------------------------*/ |