sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [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 | |
Elliott Hughes | ed39800 | 2017-06-21 14:41:24 -0700 | [diff] [blame^] | 11 | Copyright (C) 2000-2017 Nicholas Nethercote |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 12 | njn@valgrind.org |
Elliott Hughes | ed39800 | 2017-06-21 14:41:24 -0700 | [diff] [blame^] | 13 | Copyright (C) 2004-2017 Paul Mackerras |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 14 | paulus@samba.org |
Elliott Hughes | ed39800 | 2017-06-21 14:41:24 -0700 | [diff] [blame^] | 15 | Copyright (C) 2008-2017 Evan Geller |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [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" |
| 41 | #include "pub_core_threadstate.h" |
| 42 | #include "pub_core_aspacemgr.h" |
| 43 | #include "pub_core_libcbase.h" |
| 44 | #include "pub_core_libcassert.h" |
| 45 | #include "pub_core_libcprint.h" |
| 46 | #include "pub_core_machine.h" |
| 47 | #include "pub_core_options.h" |
| 48 | #include "pub_core_sigframe.h" |
| 49 | #include "pub_core_signals.h" |
| 50 | #include "pub_core_tooliface.h" |
| 51 | #include "pub_core_trampoline.h" |
florian | 01fcf6a | 2015-04-18 10:33:54 +0000 | [diff] [blame] | 52 | #include "priv_sigframe.h" |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 53 | |
| 54 | |
sewardj | 320dee2 | 2011-09-10 09:10:03 +0000 | [diff] [blame] | 55 | /* This uses the hack of dumping the vex guest state along with both |
| 56 | shadows in the frame, and restoring it afterwards from there, |
| 57 | rather than pulling it out of the ucontext. That means that signal |
| 58 | handlers which modify the ucontext and then return, expecting their |
| 59 | modifications to take effect, will have those modifications |
| 60 | ignored. This could be fixed properly with an hour or so more |
| 61 | effort. */ |
| 62 | |
| 63 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 64 | struct vg_sig_private { |
| 65 | UInt magicPI; |
| 66 | UInt sigNo_private; |
sewardj | 320dee2 | 2011-09-10 09:10:03 +0000 | [diff] [blame] | 67 | VexGuestARMState vex; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 68 | VexGuestARMState vex_shadow1; |
| 69 | VexGuestARMState vex_shadow2; |
| 70 | }; |
| 71 | |
| 72 | struct sigframe { |
| 73 | struct vki_ucontext uc; |
| 74 | unsigned long retcode[2]; |
| 75 | struct vg_sig_private vp; |
| 76 | }; |
| 77 | |
| 78 | struct rt_sigframe { |
| 79 | vki_siginfo_t info; |
| 80 | struct sigframe sig; |
| 81 | }; |
| 82 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 83 | |
| 84 | static void synth_ucontext( ThreadId tid, const vki_siginfo_t *si, |
| 85 | UWord trapno, UWord err, const vki_sigset_t *set, |
| 86 | struct vki_ucontext *uc){ |
| 87 | |
| 88 | ThreadState *tst = VG_(get_ThreadState)(tid); |
| 89 | struct vki_sigcontext *sc = &uc->uc_mcontext; |
| 90 | |
| 91 | VG_(memset)(uc, 0, sizeof(*uc)); |
| 92 | |
| 93 | uc->uc_flags = 0; |
| 94 | uc->uc_link = 0; |
| 95 | uc->uc_sigmask = *set; |
| 96 | uc->uc_stack = tst->altstack; |
| 97 | |
| 98 | # define SC2(reg,REG) sc->arm_##reg = tst->arch.vex.guest_##REG |
| 99 | SC2(r0,R0); |
| 100 | SC2(r1,R1); |
| 101 | SC2(r2,R2); |
| 102 | SC2(r3,R3); |
| 103 | SC2(r4,R4); |
| 104 | SC2(r5,R5); |
| 105 | SC2(r6,R6); |
| 106 | SC2(r7,R7); |
| 107 | SC2(r8,R8); |
| 108 | SC2(r9,R9); |
| 109 | SC2(r10,R10); |
| 110 | SC2(fp,R11); |
| 111 | SC2(ip,R12); |
| 112 | SC2(sp,R13); |
| 113 | SC2(lr,R14); |
sewardj | 9dcfdff | 2010-08-22 12:00:40 +0000 | [diff] [blame] | 114 | SC2(pc,R15T); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 115 | # undef SC2 |
| 116 | |
| 117 | sc->trap_no = trapno; |
| 118 | sc->error_code = err; |
| 119 | sc->fault_address = (UInt)si->_sifields._sigfault._addr; |
| 120 | } |
| 121 | |
| 122 | |
| 123 | static void build_sigframe(ThreadState *tst, |
| 124 | struct sigframe *frame, |
| 125 | const vki_siginfo_t *siginfo, |
| 126 | const struct vki_ucontext *siguc, |
| 127 | void *handler, UInt flags, |
| 128 | const vki_sigset_t *mask, |
| 129 | void *restorer){ |
| 130 | |
| 131 | UWord trapno; |
| 132 | UWord err; |
| 133 | Int sigNo = siginfo->si_signo; |
| 134 | struct vg_sig_private *priv = &frame->vp; |
| 135 | |
| 136 | VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame", |
| 137 | (Addr)frame, offsetof(struct sigframe, vp)); |
| 138 | |
| 139 | if(siguc) { |
| 140 | trapno = siguc->uc_mcontext.trap_no; |
| 141 | err = siguc->uc_mcontext.error_code; |
| 142 | } else { |
| 143 | trapno = 0; |
| 144 | err = 0; |
| 145 | } |
| 146 | |
| 147 | synth_ucontext(tst->tid, siginfo, trapno, err, mask, &frame->uc); |
| 148 | |
| 149 | VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, |
| 150 | (Addr)frame, offsetof(struct sigframe, vp)); |
| 151 | |
| 152 | priv->magicPI = 0x31415927; |
| 153 | priv->sigNo_private = sigNo; |
sewardj | 320dee2 | 2011-09-10 09:10:03 +0000 | [diff] [blame] | 154 | priv->vex = tst->arch.vex; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 155 | priv->vex_shadow1 = tst->arch.vex_shadow1; |
| 156 | priv->vex_shadow2 = tst->arch.vex_shadow2; |
| 157 | |
| 158 | } |
| 159 | |
| 160 | |
| 161 | |
| 162 | /* EXPORTED */ |
| 163 | void VG_(sigframe_create)( ThreadId tid, |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 164 | Bool on_altstack, |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 165 | Addr sp_top_of_frame, |
| 166 | const vki_siginfo_t *siginfo, |
| 167 | const struct vki_ucontext *siguc, |
| 168 | void *handler, |
| 169 | UInt flags, |
| 170 | const vki_sigset_t *mask, |
| 171 | void *restorer ) |
| 172 | { |
| 173 | // struct vg_sig_private *priv; |
| 174 | Addr sp = sp_top_of_frame; |
| 175 | ThreadState *tst; |
| 176 | Int sigNo = siginfo->si_signo; |
| 177 | // Addr faultaddr; |
| 178 | UInt size; |
| 179 | |
| 180 | tst = VG_(get_ThreadState)(tid); |
| 181 | |
| 182 | size = flags & VKI_SA_SIGINFO ? sizeof(struct rt_sigframe) : |
| 183 | sizeof(struct sigframe); |
| 184 | |
| 185 | sp -= size; |
| 186 | sp = VG_ROUNDDN(sp, 16); |
| 187 | |
florian | 7d4a28b | 2015-04-23 15:20:00 +0000 | [diff] [blame] | 188 | if (! ML_(sf_maybe_extend_stack)(tst, sp, size, flags)) |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 189 | I_die_here; // XXX Incorrect behavior |
| 190 | |
| 191 | |
| 192 | if (flags & VKI_SA_SIGINFO){ |
| 193 | struct rt_sigframe *rsf = (struct rt_sigframe *)sp; |
| 194 | |
| 195 | /* Track our writes to siginfo */ |
| 196 | VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, /* VVVVV */ |
| 197 | "signal handler siginfo", (Addr)rsf, |
| 198 | offsetof(struct rt_sigframe, sig)); |
| 199 | |
| 200 | VG_(memcpy)(&rsf->info, siginfo, sizeof(vki_siginfo_t)); |
| 201 | |
| 202 | if(sigNo == VKI_SIGILL && siginfo->si_code > 0) { |
| 203 | rsf->info._sifields._sigfault._addr = (Addr *) (tst)->arch.vex.guest_R12; /* IP */ |
| 204 | } |
| 205 | VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, /* ^^^^^ */ |
| 206 | (Addr)rsf, offsetof(struct rt_sigframe, sig)); |
| 207 | |
| 208 | build_sigframe(tst, &rsf->sig, siginfo, siguc, |
| 209 | handler, flags, mask, restorer); |
| 210 | tst->arch.vex.guest_R1 = (Addr)&rsf->info; |
| 211 | tst->arch.vex.guest_R2 = (Addr)&rsf->sig.uc; |
| 212 | } |
sewardj | 9dcfdff | 2010-08-22 12:00:40 +0000 | [diff] [blame] | 213 | else { |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 214 | build_sigframe(tst, (struct sigframe *)sp, siginfo, siguc, |
| 215 | handler, flags, mask, restorer); |
sewardj | 9dcfdff | 2010-08-22 12:00:40 +0000 | [diff] [blame] | 216 | } |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 217 | |
| 218 | VG_(set_SP)(tid, sp); |
| 219 | VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, |
| 220 | sizeof(Addr)); |
sewardj | 9dcfdff | 2010-08-22 12:00:40 +0000 | [diff] [blame] | 221 | tst->arch.vex.guest_R0 = sigNo; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 222 | |
sewardj | 9dcfdff | 2010-08-22 12:00:40 +0000 | [diff] [blame] | 223 | if (flags & VKI_SA_RESTORER) |
sewardj | bc33be6 | 2011-11-20 09:35:51 +0000 | [diff] [blame] | 224 | tst->arch.vex.guest_R14 = (Addr)restorer; |
| 225 | else |
| 226 | tst->arch.vex.guest_R14 |
| 227 | = (flags & VKI_SA_SIGINFO) |
| 228 | ? (Addr)&VG_(arm_linux_SUBST_FOR_rt_sigreturn) |
| 229 | : (Addr)&VG_(arm_linux_SUBST_FOR_sigreturn); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 230 | |
sewardj | 9dcfdff | 2010-08-22 12:00:40 +0000 | [diff] [blame] | 231 | tst->arch.vex.guest_R15T = (Addr) handler; /* R15 == PC */ |
sewardj | 9bd3301 | 2015-03-05 11:24:05 +0000 | [diff] [blame] | 232 | |
| 233 | if (VG_(clo_trace_signals)) |
| 234 | VG_(message)(Vg_DebugMsg, |
sewardj | bba930d | 2015-06-05 10:03:56 +0000 | [diff] [blame] | 235 | "VG_(sigframe_create): continuing in handler with PC=%#lx\n", |
sewardj | 9bd3301 | 2015-03-05 11:24:05 +0000 | [diff] [blame] | 236 | (Addr)handler); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 237 | } |
| 238 | |
| 239 | |
| 240 | /*------------------------------------------------------------*/ |
| 241 | /*--- Destroying signal frames ---*/ |
| 242 | /*------------------------------------------------------------*/ |
| 243 | |
| 244 | /* EXPORTED */ |
| 245 | void VG_(sigframe_destroy)( ThreadId tid, Bool isRT ) |
| 246 | { |
| 247 | ThreadState *tst; |
| 248 | struct vg_sig_private *priv; |
| 249 | Addr sp; |
| 250 | UInt frame_size; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 251 | Int sigNo; |
| 252 | Bool has_siginfo = isRT; |
| 253 | |
| 254 | vg_assert(VG_(is_valid_tid)(tid)); |
| 255 | tst = VG_(get_ThreadState)(tid); |
| 256 | sp = tst->arch.vex.guest_R13; |
| 257 | |
| 258 | if (has_siginfo) { |
| 259 | struct rt_sigframe *frame = (struct rt_sigframe *)sp; |
| 260 | frame_size = sizeof(*frame); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 261 | priv = &frame->sig.vp; |
| 262 | vg_assert(priv->magicPI == 0x31415927); |
| 263 | tst->sig_mask = frame->sig.uc.uc_sigmask; |
| 264 | } else { |
| 265 | struct sigframe *frame = (struct sigframe *)sp; |
| 266 | frame_size = sizeof(*frame); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 267 | priv = &frame->vp; |
| 268 | vg_assert(priv->magicPI == 0x31415927); |
| 269 | tst->sig_mask = frame->uc.uc_sigmask; |
| 270 | /*tst->sig_mask.sig[0] = frame->uc.uc_mcontext.oldmask; |
| 271 | tst->sig_mask.sig[1] = frame->uc.uc_mcontext._unused[3]; |
| 272 | VG_(printf)("Setting signmask to %08x%08x\n",tst->sig_mask[0],tst->sig_mask[1]); |
| 273 | */ |
| 274 | } |
| 275 | tst->tmp_sig_mask = tst->sig_mask; |
| 276 | |
| 277 | sigNo = priv->sigNo_private; |
| 278 | |
florian | 486372b | 2015-08-06 09:34:20 +0000 | [diff] [blame] | 279 | //ZZ //XXX: restore regs |
| 280 | //ZZ # define REST(reg,REG) tst->arch.vex.guest_##REG = mc->arm_##reg; |
| 281 | //ZZ REST(r0,R0); |
| 282 | //ZZ REST(r1,R1); |
| 283 | //ZZ REST(r2,R2); |
| 284 | //ZZ REST(r3,R3); |
| 285 | //ZZ REST(r4,R4); |
| 286 | //ZZ REST(r5,R5); |
| 287 | //ZZ REST(r6,R6); |
| 288 | //ZZ REST(r7,R7); |
| 289 | //ZZ REST(r8,R8); |
| 290 | //ZZ REST(r9,R9); |
| 291 | //ZZ REST(r10,R10); |
| 292 | //ZZ REST(fp,R11); |
| 293 | //ZZ REST(ip,R12); |
| 294 | //ZZ REST(sp,R13); |
| 295 | //ZZ REST(lr,R14); |
| 296 | //ZZ REST(pc,R15T); |
| 297 | //ZZ # undef REST |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 298 | |
sewardj | 320dee2 | 2011-09-10 09:10:03 +0000 | [diff] [blame] | 299 | /* Uh, the next line makes all the REST() above pointless. */ |
| 300 | tst->arch.vex = priv->vex; |
| 301 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 302 | tst->arch.vex_shadow1 = priv->vex_shadow1; |
| 303 | tst->arch.vex_shadow2 = priv->vex_shadow2; |
| 304 | |
| 305 | VG_TRACK( die_mem_stack_signal, sp - VG_STACK_REDZONE_SZB, |
| 306 | frame_size + VG_STACK_REDZONE_SZB ); |
| 307 | |
| 308 | if (VG_(clo_trace_signals)) |
| 309 | VG_(message)(Vg_DebugMsg, |
florian | 97f1d33 | 2015-08-06 09:00:48 +0000 | [diff] [blame] | 310 | "vg_pop_signal_frame (thread %u): " |
sewardj | 320dee2 | 2011-09-10 09:10:03 +0000 | [diff] [blame] | 311 | "isRT=%d valid magic; PC=%#x\n", |
sewardj | 9dcfdff | 2010-08-22 12:00:40 +0000 | [diff] [blame] | 312 | tid, has_siginfo, tst->arch.vex.guest_R15T); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 313 | |
| 314 | /* tell the tools */ |
| 315 | VG_TRACK( post_deliver_signal, tid, sigNo ); |
| 316 | } |
| 317 | |
| 318 | #endif // defined(VGP_arm_linux) |
| 319 | |
| 320 | /*--------------------------------------------------------------------*/ |
| 321 | /*--- end sigframe-arm-linux.c ---*/ |
| 322 | /*--------------------------------------------------------------------*/ |