1 2/*--------------------------------------------------------------------*/ 3/*--- Create/destroy signal delivery frames. ---*/ 4/*--- sigframe-ppc64-linux.c ---*/ 5/*--------------------------------------------------------------------*/ 6 7/* 8 This file is part of Valgrind, a dynamic binary instrumentation 9 framework. 10 11 Copyright (C) 2000-2015 Nicholas Nethercote 12 njn@valgrind.org 13 Copyright (C) 2004-2015 Paul Mackerras 14 paulus@samba.org 15 16 This program is free software; you can redistribute it and/or 17 modify it under the terms of the GNU General Public License as 18 published by the Free Software Foundation; either version 2 of the 19 License, or (at your option) any later version. 20 21 This program is distributed in the hope that it will be useful, but 22 WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 General Public License for more details. 25 26 You should have received a copy of the GNU General Public License 27 along with this program; if not, write to the Free Software 28 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 29 02111-1307, USA. 30 31 The GNU General Public License is contained in the file COPYING. 32*/ 33 34#if defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) 35 36#include "pub_core_basics.h" 37#include "pub_core_vki.h" 38#include "pub_core_vkiscnums.h" 39#include "pub_core_threadstate.h" 40#include "pub_core_aspacemgr.h" 41#include "pub_core_libcbase.h" 42#include "pub_core_libcassert.h" 43#include "pub_core_libcprint.h" 44#include "pub_core_machine.h" 45#include "pub_core_options.h" 46#include "pub_core_sigframe.h" 47#include "pub_core_signals.h" 48#include "pub_core_tooliface.h" 49#include "pub_core_trampoline.h" 50#include "pub_core_transtab.h" // VG_(discard_translations) 51#include "priv_sigframe.h" 52 53/* This module creates and removes signal frames for signal deliveries 54 on ppc64-linux. 55 56 Note, this file contains kernel-specific knowledge in the form of 57 'struct sigframe' and 'struct rt_sigframe'. How does that relate 58 to the vki kernel interface stuff? 59 60 Either a 'struct sigframe' or a 'struct rtsigframe' is pushed 61 onto the client's stack. This contains a subsidiary 62 vki_ucontext. That holds the vcpu's state across the signal, 63 so that the sighandler can mess with the vcpu state if it 64 really wants. 65 66 FIXME: sigcontexting is basically broken for the moment. When 67 delivering a signal, the integer registers and %eflags are 68 correctly written into the sigcontext, however the FP and SSE state 69 is not. When returning from a signal, only the integer registers 70 are restored from the sigcontext; the rest of the CPU state is 71 restored to what it was before the signal. 72 73 This will be fixed. 74*/ 75 76 77/*------------------------------------------------------------*/ 78/*--- Signal frame layouts ---*/ 79/*------------------------------------------------------------*/ 80 81// A structure in which to save the application's registers 82// during the execution of signal handlers. 83 84// On ppc64-linux, rt_sigframe is used for all signals. 85 86// In theory, so long as we get the arguments to the handler function 87// right, it doesn't matter what the exact layout of the rest of the 88// frame is. Unfortunately, things like gcc's exception unwinding 89// make assumptions about the locations of various parts of the frame, 90// so we need to duplicate it exactly. 91 92/* Many of these byzantine details derived from 93 linux-2.6.13/arch/ppc64/kernel/signal.c */ 94 95#define TRAMP_SIZE 6 /* who knows why - it only needs to be 2. */ 96 97/* Structure containing bits of information that we want to save 98 on signal delivery. */ 99struct vg_sig_private { 100 UInt magicPI; 101 UInt sigNo_private; 102 ULong _unused; /* makes the struct size be zero % 16 */ 103 VexGuestPPC64State vex_shadow1; 104 VexGuestPPC64State vex_shadow2; 105}; 106 107/* Structure put on stack for all signal handlers. */ 108struct rt_sigframe { 109 struct vki_ucontext uc; 110 ULong _unused[2]; 111 UInt tramp[TRAMP_SIZE]; 112 struct vki_siginfo* pinfo; 113 void* puc; 114 vki_siginfo_t info; 115 struct vg_sig_private priv; 116 UChar abigap[288]; // unused 117}; 118 119#define SET_SIGNAL_LR(zztst, zzval) \ 120 do { tst->arch.vex.guest_LR = (zzval); \ 121 VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, \ 122 offsetof(VexGuestPPC64State,guest_LR), \ 123 sizeof(UWord) ); \ 124 } while (0) 125 126#define SET_SIGNAL_GPR(zztst, zzn, zzval) \ 127 do { tst->arch.vex.guest_GPR##zzn = (zzval); \ 128 VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, \ 129 offsetof(VexGuestPPC64State,guest_GPR##zzn), \ 130 sizeof(UWord) ); \ 131 } while (0) 132 133 134 135/* EXPORTED */ 136void VG_(sigframe_create)( ThreadId tid, 137 Bool on_altstack, 138 Addr sp_top_of_frame, 139 const vki_siginfo_t *siginfo, 140 const struct vki_ucontext *siguc, 141 void *handler, 142 UInt flags, 143 const vki_sigset_t *mask, 144 void *restorer ) 145{ 146 struct vg_sig_private* priv; 147 Addr sp; 148 ThreadState* tst; 149 Int sigNo = siginfo->si_signo; 150 /* Addr faultaddr; */ /* UNUSED */ 151 struct rt_sigframe* frame; 152 153 /* Stack must be 16-byte aligned */ 154 vg_assert(VG_IS_16_ALIGNED(sizeof(struct vg_sig_private))); 155 vg_assert(VG_IS_16_ALIGNED(sizeof(struct rt_sigframe))); 156 157 sp_top_of_frame &= ~0xf; 158 sp = sp_top_of_frame - sizeof(struct rt_sigframe); 159 160 tst = VG_(get_ThreadState)(tid); 161 if (! ML_(sf_maybe_extend_stack)(tst, sp, sp_top_of_frame - sp, flags)) 162 return; 163 164 vg_assert(VG_IS_16_ALIGNED(sp)); 165 166 frame = (struct rt_sigframe *) sp; 167 168 /* clear it (conservatively) */ 169 VG_(memset)(frame, 0, sizeof(*frame)); 170 171 ///////// 172 frame->pinfo = &frame->info; 173 frame->puc = &frame->uc; 174 175 frame->uc.uc_flags = 0; 176 frame->uc.uc_link = 0; 177 ///////// 178 179 /* Set up the stack chain pointer */ 180 VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame", 181 sp, sizeof(UWord) ); 182 *(Addr *)sp = tst->arch.vex.guest_GPR1; 183 VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 184 sp, sizeof(UWord) ); 185 186 /* UNUSED: 187 faultaddr = (Addr)siginfo->_sifields._sigfault._addr; 188 if (sigNo == VKI_SIGILL && siginfo->si_code > 0) 189 faultaddr = tst->arch.vex.guest_CIA; 190 */ 191 192 VG_(memcpy)(&frame->info, siginfo, sizeof(*siginfo)); 193 VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 194 (Addr)&frame->info, sizeof(frame->info) ); 195 196 frame->uc.uc_flags = 0; 197 frame->uc.uc_link = 0; 198 frame->uc.uc_stack = tst->altstack; 199 frame->uc.uc_sigmask = tst->sig_mask; 200 VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 201 (Addr)(&frame->uc), sizeof(frame->uc) ); 202 203# define DO(gpr) frame->uc.uc_mcontext.gp_regs[VKI_PT_R0+gpr] \ 204 = tst->arch.vex.guest_GPR##gpr 205 DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7); 206 DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15); 207 DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23); 208 DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31); 209# undef DO 210 211 frame->uc.uc_mcontext.gp_regs[VKI_PT_NIP] = tst->arch.vex.guest_CIA; 212#ifdef VGP_ppc64le_linux 213 frame->uc.uc_mcontext.gp_regs[VKI_PT_MSR] = 0xf033; /* pretty arbitrary */ 214#else 215 frame->uc.uc_mcontext.gp_regs[VKI_PT_MSR] = 0xf032; /* pretty arbitrary */ 216#endif 217 frame->uc.uc_mcontext.gp_regs[VKI_PT_ORIG_R3] = tst->arch.vex.guest_GPR3; 218 frame->uc.uc_mcontext.gp_regs[VKI_PT_CTR] = tst->arch.vex.guest_CTR; 219 frame->uc.uc_mcontext.gp_regs[VKI_PT_LNK] = tst->arch.vex.guest_LR; 220 frame->uc.uc_mcontext.gp_regs[VKI_PT_XER] = LibVEX_GuestPPC64_get_XER( 221 &tst->arch.vex); 222 frame->uc.uc_mcontext.gp_regs[VKI_PT_CCR] = LibVEX_GuestPPC64_get_CR( 223 &tst->arch.vex); 224 //mc->mc_gregs[VKI_PT_MQ] = 0; 225 //mc->mc_gregs[VKI_PT_TRAP] = 0; 226 //mc->mc_gregs[VKI_PT_DAR] = fault_addr; 227 //mc->mc_gregs[VKI_PT_DSISR] = 0; 228 //mc->mc_gregs[VKI_PT_RESULT] = 0; 229 230 /* XXX should do FP and vector regs */ 231 232 /* set up signal return trampoline */ 233 /* NB. 5 Sept 07. mc->mc_pad[0..1] used to contain a the code to 234 which the signal handler returns, and it just did sys_sigreturn 235 or sys_rt_sigreturn. But this doesn't work if the stack is 236 non-executable, and it isn't consistent with the x86-linux and 237 amd64-linux scheme for removing the stack frame. So instead be 238 consistent and use a stub in m_trampoline. Then it doesn't 239 matter whether or not the (guest) stack is executable. This 240 fixes #149519 and #145837. */ 241 frame->tramp[0] = 0; /* invalid */ 242 frame->tramp[1] = 0; /* invalid */ 243 VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid, 244 (Addr)&frame->tramp, sizeof(frame->tramp)); 245 246 /* invalidate any translation of this area */ 247 VG_(discard_translations)( (Addr)&frame->tramp[0], 248 sizeof(frame->tramp), "stack_mcontext" ); 249 250 /* set the signal handler to return to the trampoline */ 251 SET_SIGNAL_LR(tst, (Addr)&VG_(ppc64_linux_SUBST_FOR_rt_sigreturn)); 252 253 /* Stack pointer for the handler .. (note, back chain set 254 earlier) */ 255 SET_SIGNAL_GPR(tid, 1, sp); 256 257 /* Args for the handler .. */ 258 SET_SIGNAL_GPR(tid, 3, sigNo); 259 SET_SIGNAL_GPR(tid, 4, (Addr) &frame->info); 260 SET_SIGNAL_GPR(tid, 5, (Addr) &frame->uc); 261 /* the kernel sets this, though it doesn't seem to be in the ABI */ 262 SET_SIGNAL_GPR(tid, 6, (Addr) &frame->info); 263 264 /* Handler is in fact a standard ppc64-linux function descriptor, 265 so extract the function entry point and also the toc ptr to use. */ 266#if defined(VGP_ppc64be_linux) 267 SET_SIGNAL_GPR(tid, 2, (Addr) ((ULong*)handler)[1]); 268 tst->arch.vex.guest_CIA = (Addr) ((ULong*)handler)[0]; 269#else 270 SET_SIGNAL_GPR(tid, 12, (Addr) handler); 271 tst->arch.vex.guest_CIA = (Addr) handler; 272#endif 273 priv = &frame->priv; 274 priv->magicPI = 0x31415927; 275 priv->sigNo_private = sigNo; 276 priv->vex_shadow1 = tst->arch.vex_shadow1; 277 priv->vex_shadow2 = tst->arch.vex_shadow2; 278 279 if (0) 280 VG_(printf)("pushed signal frame; %%R1 now = %#lx, " 281 "next %%CIA = %#llx, status=%d\n", 282 sp, tst->arch.vex.guest_CIA, (Int)tst->status); 283} 284 285 286/*------------------------------------------------------------*/ 287/*--- Destroying signal frames ---*/ 288/*------------------------------------------------------------*/ 289 290/* EXPORTED */ 291void VG_(sigframe_destroy)( ThreadId tid, Bool isRT ) 292{ 293 ThreadState *tst; 294 struct vg_sig_private *priv; 295 Addr sp; 296 UInt frame_size; 297 struct rt_sigframe *frame; 298 Int sigNo; 299 Bool has_siginfo = isRT; 300 301 vg_assert(VG_(is_valid_tid)(tid)); 302 tst = VG_(get_ThreadState)(tid); 303 304 /* Check that the stack frame looks valid */ 305 sp = tst->arch.vex.guest_GPR1; 306 vg_assert(VG_IS_16_ALIGNED(sp)); 307 /* JRS 17 Nov 05: This code used to check that *sp -- which should 308 have been set by the stwu at the start of the handler -- points 309 to just above the frame (ie, the previous frame). However, that 310 isn't valid when delivering signals on alt stacks. So I removed 311 it. The frame is still sanity-checked using the priv->magicPI 312 field. */ 313 314 frame = (struct rt_sigframe *)sp; 315 frame_size = sizeof(*frame); 316 priv = &frame->priv; 317 vg_assert(priv->magicPI == 0x31415927); 318 tst->sig_mask = frame->uc.uc_sigmask; 319 tst->tmp_sig_mask = tst->sig_mask; 320 321 sigNo = priv->sigNo_private; 322 323# define DO(gpr) tst->arch.vex.guest_GPR##gpr \ 324 = frame->uc.uc_mcontext.gp_regs[VKI_PT_R0+gpr] 325 DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7); 326 DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15); 327 DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23); 328 DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31); 329# undef DO 330 331 tst->arch.vex.guest_CIA = frame->uc.uc_mcontext.gp_regs[VKI_PT_NIP]; 332 333 LibVEX_GuestPPC64_put_CR( frame->uc.uc_mcontext.gp_regs[VKI_PT_CCR], 334 &tst->arch.vex ); 335 336 tst->arch.vex.guest_LR = frame->uc.uc_mcontext.gp_regs[VKI_PT_LNK]; 337 tst->arch.vex.guest_CTR = frame->uc.uc_mcontext.gp_regs[VKI_PT_CTR]; 338 LibVEX_GuestPPC64_put_XER( frame->uc.uc_mcontext.gp_regs[VKI_PT_XER], 339 &tst->arch.vex ); 340 341 tst->arch.vex_shadow1 = priv->vex_shadow1; 342 tst->arch.vex_shadow2 = priv->vex_shadow2; 343 344 VG_TRACK(die_mem_stack_signal, sp, frame_size); 345 346 if (VG_(clo_trace_signals)) 347 VG_(message)(Vg_DebugMsg, 348 "vg_pop_signal_frame (thread %u): isRT=%d " 349 "valid magic; EIP=%#llx\n", 350 tid, has_siginfo, tst->arch.vex.guest_CIA); 351 352 /* tell the tools */ 353 VG_TRACK( post_deliver_signal, tid, sigNo ); 354} 355 356#endif // defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) 357 358/*--------------------------------------------------------------------*/ 359/*--- end ---*/ 360/*--------------------------------------------------------------------*/ 361