2 /*--------------------------------------------------------------------*/
3 /*--- Create/destroy signal delivery frames. ---*/
4 /*--- sigframe-ppc64-linux.c ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Valgrind, a dynamic binary instrumentation
11 Copyright (C) 2000-2017 Nicholas Nethercote
13 Copyright (C) 2004-2017 Paul Mackerras
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.
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.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, see <http://www.gnu.org/licenses/>.
29 The GNU General Public License is contained in the file COPYING.
32 #if defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
34 #include "pub_core_basics.h"
35 #include "pub_core_vki.h"
36 #include "pub_core_vkiscnums.h"
37 #include "pub_core_threadstate.h"
38 #include "pub_core_aspacemgr.h"
39 #include "pub_core_libcbase.h"
40 #include "pub_core_libcassert.h"
41 #include "pub_core_libcprint.h"
42 #include "pub_core_machine.h"
43 #include "pub_core_options.h"
44 #include "pub_core_sigframe.h"
45 #include "pub_core_signals.h"
46 #include "pub_core_tooliface.h"
47 #include "pub_core_trampoline.h"
48 #include "pub_core_transtab.h" // VG_(discard_translations)
49 #include "priv_sigframe.h"
51 /* This module creates and removes signal frames for signal deliveries
54 Note, this file contains kernel-specific knowledge in the form of
55 'struct sigframe' and 'struct rt_sigframe'. How does that relate
56 to the vki kernel interface stuff?
58 Either a 'struct sigframe' or a 'struct rtsigframe' is pushed
59 onto the client's stack. This contains a subsidiary
60 vki_ucontext. That holds the vcpu's state across the signal,
61 so that the sighandler can mess with the vcpu state if it
64 FIXME: sigcontexting is basically broken for the moment. When
65 delivering a signal, the integer registers and %eflags are
66 correctly written into the sigcontext, however the FP and SSE state
67 is not. When returning from a signal, only the integer registers
68 are restored from the sigcontext; the rest of the CPU state is
69 restored to what it was before the signal.
75 /*------------------------------------------------------------*/
76 /*--- Signal frame layouts ---*/
77 /*------------------------------------------------------------*/
79 // A structure in which to save the application's registers
80 // during the execution of signal handlers.
82 // On ppc64-linux, rt_sigframe is used for all signals.
84 // In theory, so long as we get the arguments to the handler function
85 // right, it doesn't matter what the exact layout of the rest of the
86 // frame is. Unfortunately, things like gcc's exception unwinding
87 // make assumptions about the locations of various parts of the frame,
88 // so we need to duplicate it exactly.
90 /* Many of these byzantine details derived from
91 linux-2.6.13/arch/ppc64/kernel/signal.c */
93 #define TRAMP_SIZE 6 /* who knows why - it only needs to be 2. */
95 /* Structure containing bits of information that we want to save
96 on signal delivery. */
97 struct vg_sig_private
{
100 ULong _unused
; /* makes the struct size be zero % 16 */
101 VexGuestPPC64State vex_shadow1
;
102 VexGuestPPC64State vex_shadow2
;
105 /* Structure put on stack for all signal handlers. */
107 struct vki_ucontext uc
;
109 UInt tramp
[TRAMP_SIZE
];
110 struct vki_siginfo
* pinfo
;
113 struct vg_sig_private priv
;
114 UChar abigap
[288]; // unused
115 } __attribute__ ((aligned (16)));
117 #define SET_SIGNAL_LR(zztst, zzval) \
118 do { tst->arch.vex.guest_LR = (zzval); \
119 VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, \
120 offsetof(VexGuestPPC64State,guest_LR), \
124 #define SET_SIGNAL_GPR(zztst, zzn, zzval) \
125 do { tst->arch.vex.guest_GPR##zzn = (zzval); \
126 VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, \
127 offsetof(VexGuestPPC64State,guest_GPR##zzn), \
134 void VG_(sigframe_create
)( ThreadId tid
,
136 Addr sp_top_of_frame
,
137 const vki_siginfo_t
*siginfo
,
138 const struct vki_ucontext
*siguc
,
141 const vki_sigset_t
*mask
,
144 struct vg_sig_private
* priv
;
147 Int sigNo
= siginfo
->si_signo
;
148 /* Addr faultaddr; */ /* UNUSED */
149 struct rt_sigframe
* frame
;
151 /* Stack must be 16-byte aligned */
152 vg_assert(VG_IS_16_ALIGNED(sizeof(struct vg_sig_private
)));
153 vg_assert(VG_IS_16_ALIGNED(sizeof(struct rt_sigframe
)));
155 sp_top_of_frame
&= ~0xf;
156 sp
= sp_top_of_frame
- sizeof(struct rt_sigframe
);
158 tst
= VG_(get_ThreadState
)(tid
);
159 if (! ML_(sf_maybe_extend_stack
)(tst
, sp
, sp_top_of_frame
- sp
, flags
))
162 vg_assert(VG_IS_16_ALIGNED(sp
));
164 frame
= (struct rt_sigframe
*) sp
;
166 /* clear it (conservatively) */
167 VG_(memset
)(frame
, 0, sizeof(*frame
));
170 frame
->pinfo
= &frame
->info
;
171 frame
->puc
= &frame
->uc
;
173 frame
->uc
.uc_flags
= 0;
174 frame
->uc
.uc_link
= 0;
177 /* Set up the stack chain pointer */
178 VG_TRACK( pre_mem_write
, Vg_CoreSignal
, tid
, "signal handler frame",
180 *(Addr
*)sp
= tst
->arch
.vex
.guest_GPR1
;
181 VG_TRACK( post_mem_write
, Vg_CoreSignal
, tid
,
185 faultaddr = (Addr)siginfo->_sifields._sigfault._addr;
186 if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
187 faultaddr = tst->arch.vex.guest_CIA;
190 VG_(memcpy
)(&frame
->info
, siginfo
, sizeof(*siginfo
));
191 VG_TRACK( post_mem_write
, Vg_CoreSignal
, tid
,
192 (Addr
)&frame
->info
, sizeof(frame
->info
) );
194 frame
->uc
.uc_flags
= 0;
195 frame
->uc
.uc_link
= 0;
196 frame
->uc
.uc_stack
= tst
->altstack
;
197 frame
->uc
.uc_sigmask
= tst
->sig_mask
;
198 VG_TRACK( post_mem_write
, Vg_CoreSignal
, tid
,
199 (Addr
)(&frame
->uc
), sizeof(frame
->uc
) );
201 # define DO(gpr) frame->uc.uc_mcontext.gp_regs[VKI_PT_R0+gpr] \
202 = tst->arch.vex.guest_GPR##gpr
203 DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7);
204 DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
205 DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
206 DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
209 frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_NIP
] = tst
->arch
.vex
.guest_CIA
;
210 #ifdef VGP_ppc64le_linux
211 frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_MSR
] = 0xf033; /* pretty arbitrary */
213 frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_MSR
] = 0xf032; /* pretty arbitrary */
215 frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_ORIG_R3
] = tst
->arch
.vex
.guest_GPR3
;
216 frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_CTR
] = tst
->arch
.vex
.guest_CTR
;
217 frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_LNK
] = tst
->arch
.vex
.guest_LR
;
218 frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_XER
] = LibVEX_GuestPPC64_get_XER(
220 frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_CCR
] = LibVEX_GuestPPC64_get_CR(
222 //mc->mc_gregs[VKI_PT_MQ] = 0;
223 //mc->mc_gregs[VKI_PT_TRAP] = 0;
224 //mc->mc_gregs[VKI_PT_DAR] = fault_addr;
225 //mc->mc_gregs[VKI_PT_DSISR] = 0;
226 //mc->mc_gregs[VKI_PT_RESULT] = 0;
228 /* XXX should do FP and vector regs */
230 /* set up signal return trampoline */
231 /* NB. 5 Sept 07. mc->mc_pad[0..1] used to contain a the code to
232 which the signal handler returns, and it just did sys_sigreturn
233 or sys_rt_sigreturn. But this doesn't work if the stack is
234 non-executable, and it isn't consistent with the x86-linux and
235 amd64-linux scheme for removing the stack frame. So instead be
236 consistent and use a stub in m_trampoline. Then it doesn't
237 matter whether or not the (guest) stack is executable. This
238 fixes #149519 and #145837. */
239 frame
->tramp
[0] = 0; /* invalid */
240 frame
->tramp
[1] = 0; /* invalid */
241 VG_TRACK(post_mem_write
, Vg_CoreSignal
, tst
->tid
,
242 (Addr
)&frame
->tramp
, sizeof(frame
->tramp
));
244 /* invalidate any translation of this area */
245 VG_(discard_translations
)( (Addr
)&frame
->tramp
[0],
246 sizeof(frame
->tramp
), "stack_mcontext" );
248 /* set the signal handler to return to the trampoline */
249 SET_SIGNAL_LR(tst
, (Addr
)&VG_(ppc64_linux_SUBST_FOR_rt_sigreturn
));
251 /* Stack pointer for the handler .. (note, back chain set
253 SET_SIGNAL_GPR(tid
, 1, sp
);
255 /* Args for the handler .. */
256 SET_SIGNAL_GPR(tid
, 3, sigNo
);
257 SET_SIGNAL_GPR(tid
, 4, (Addr
) &frame
->info
);
258 SET_SIGNAL_GPR(tid
, 5, (Addr
) &frame
->uc
);
259 /* the kernel sets this, though it doesn't seem to be in the ABI */
260 SET_SIGNAL_GPR(tid
, 6, (Addr
) &frame
->info
);
262 /* Handler is in fact a standard ppc64-linux function descriptor,
263 so extract the function entry point and also the toc ptr to use. */
264 #if defined(VGP_ppc64be_linux)
265 SET_SIGNAL_GPR(tid
, 2, (Addr
) ((ULong
*)handler
)[1]);
266 tst
->arch
.vex
.guest_CIA
= (Addr
) ((ULong
*)handler
)[0];
268 SET_SIGNAL_GPR(tid
, 12, (Addr
) handler
);
269 tst
->arch
.vex
.guest_CIA
= (Addr
) handler
;
272 priv
->magicPI
= 0x31415927;
273 priv
->sigNo_private
= sigNo
;
274 priv
->vex_shadow1
= tst
->arch
.vex_shadow1
;
275 priv
->vex_shadow2
= tst
->arch
.vex_shadow2
;
278 VG_(printf
)("pushed signal frame; %%R1 now = %#lx, "
279 "next %%CIA = %#llx, status=%d\n",
280 sp
, tst
->arch
.vex
.guest_CIA
, (Int
)tst
->status
);
284 /*------------------------------------------------------------*/
285 /*--- Destroying signal frames ---*/
286 /*------------------------------------------------------------*/
289 void VG_(sigframe_destroy
)( ThreadId tid
, Bool isRT
)
292 struct vg_sig_private
*priv
;
295 struct rt_sigframe
*frame
;
297 Bool has_siginfo
= isRT
;
299 vg_assert(VG_(is_valid_tid
)(tid
));
300 tst
= VG_(get_ThreadState
)(tid
);
302 /* Check that the stack frame looks valid */
303 sp
= tst
->arch
.vex
.guest_GPR1
;
304 vg_assert(VG_IS_16_ALIGNED(sp
));
305 /* JRS 17 Nov 05: This code used to check that *sp -- which should
306 have been set by the stwu at the start of the handler -- points
307 to just above the frame (ie, the previous frame). However, that
308 isn't valid when delivering signals on alt stacks. So I removed
309 it. The frame is still sanity-checked using the priv->magicPI
312 frame
= (struct rt_sigframe
*)sp
;
313 frame_size
= sizeof(*frame
);
315 vg_assert(priv
->magicPI
== 0x31415927);
316 tst
->sig_mask
= frame
->uc
.uc_sigmask
;
317 tst
->tmp_sig_mask
= tst
->sig_mask
;
319 sigNo
= priv
->sigNo_private
;
321 # define DO(gpr) tst->arch.vex.guest_GPR##gpr \
322 = frame->uc.uc_mcontext.gp_regs[VKI_PT_R0+gpr]
323 DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7);
324 DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
325 DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
326 DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
329 tst
->arch
.vex
.guest_CIA
= frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_NIP
];
331 LibVEX_GuestPPC64_put_CR( frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_CCR
],
334 tst
->arch
.vex
.guest_LR
= frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_LNK
];
335 tst
->arch
.vex
.guest_CTR
= frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_CTR
];
336 LibVEX_GuestPPC64_put_XER( frame
->uc
.uc_mcontext
.gp_regs
[VKI_PT_XER
],
339 tst
->arch
.vex_shadow1
= priv
->vex_shadow1
;
340 tst
->arch
.vex_shadow2
= priv
->vex_shadow2
;
342 VG_TRACK(die_mem_stack_signal
, sp
, frame_size
);
344 if (VG_(clo_trace_signals
))
345 VG_(message
)(Vg_DebugMsg
,
346 "vg_pop_signal_frame (thread %u): isRT=%d "
347 "valid magic; EIP=%#llx\n",
348 tid
, has_siginfo
, tst
->arch
.vex
.guest_CIA
);
351 VG_TRACK( post_deliver_signal
, tid
, sigNo
);
354 #endif // defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
356 /*--------------------------------------------------------------------*/
358 /*--------------------------------------------------------------------*/