blob: 7cb89c5d8ce619cb4274f3a5d8c43f3b3f8bb727 [file] [log] [blame]
sewardj2c48c7b2005-11-29 13:05:56 +00001
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-2005 Nicholas Nethercote
12 njn@valgrind.org
13 Copyright (C) 2004-2005 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#include "pub_core_basics.h"
35#include "pub_core_threadstate.h"
36#include "pub_core_aspacemgr.h"
37#include "pub_core_libcbase.h"
38#include "pub_core_libcassert.h"
39#include "pub_core_libcprint.h"
40#include "pub_core_machine.h"
41#include "pub_core_options.h"
42#include "pub_core_sigframe.h"
43#include "pub_core_signals.h"
44#include "pub_core_tooliface.h"
45#include "pub_core_trampoline.h"
46#include "pub_core_transtab.h" // VG_(discard_translations)
47#include "vki_unistd-ppc64-linux.h" // __NR_rt_sigreturn
48
49
50/* This module creates and removes signal frames for signal deliveries
51 on ppc64-linux.
52
53 Note, this file contains kernel-specific knowledge in the form of
54 'struct sigframe' and 'struct rt_sigframe'. How does that relate
55 to the vki kernel interface stuff?
56
57 Either a 'struct sigframe' or a 'struct rtsigframe' is pushed
58 onto the client's stack. This contains a subsidiary
59 vki_ucontext. That holds the vcpu's state across the signal,
60 so that the sighandler can mess with the vcpu state if it
61 really wants.
62
63 FIXME: sigcontexting is basically broken for the moment. When
64 delivering a signal, the integer registers and %eflags are
65 correctly written into the sigcontext, however the FP and SSE state
66 is not. When returning from a signal, only the integer registers
67 are restored from the sigcontext; the rest of the CPU state is
68 restored to what it was before the signal.
69
70 This will be fixed.
71*/
72
73
74/*------------------------------------------------------------*/
75/*--- Signal frame layouts ---*/
76/*------------------------------------------------------------*/
77
78// A structure in which to save the application's registers
79// during the execution of signal handlers.
80
sewardj2c6502d2006-01-03 04:08:32 +000081// On ppc64-linux, rt_sigframe is used for all signals.
82
sewardj2c48c7b2005-11-29 13:05:56 +000083// In theory, so long as we get the arguments to the handler function
84// right, it doesn't matter what the exact layout of the rest of the
85// frame is. Unfortunately, things like gcc's exception unwinding
86// make assumptions about the locations of various parts of the frame,
87// so we need to duplicate it exactly.
88
sewardj2c6502d2006-01-03 04:08:32 +000089/* Many of these byzantine details derived from
90 linux-2.6.13/arch/ppc64/kernel/signal.c */
91
92#define TRAMP_SIZE 6 /* who knows why - it only needs to be 2. */
93
sewardj2c48c7b2005-11-29 13:05:56 +000094/* Structure containing bits of information that we want to save
95 on signal delivery. */
sewardj2c6502d2006-01-03 04:08:32 +000096struct vg_sig_private {
97 UInt magicPI;
98 UInt sigNo_private;
99 VexGuestPPC64State shadow;
100};
101
102/* Structure put on stack for all signal handlers. */
103struct rt_sigframe {
104 struct vki_ucontext uc;
105 ULong _unused[2];
106 UInt tramp[TRAMP_SIZE];
107 struct vki_siginfo* pinfo;
108 void* puc;
109 vki_siginfo_t info;
110 struct vg_sig_private priv;
111 UChar abigap[288];
112};
sewardj2c48c7b2005-11-29 13:05:56 +0000113
114#define SET_SIGNAL_LR(zztst, zzval) \
115 do { tst->arch.vex.guest_LR = (zzval); \
116 VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, \
sewardj2c6502d2006-01-03 04:08:32 +0000117 offsetof(VexGuestPPC64State,guest_LR), \
sewardj2c48c7b2005-11-29 13:05:56 +0000118 sizeof(UWord) ); \
119 } while (0)
120
121#define SET_SIGNAL_GPR(zztst, zzn, zzval) \
122 do { tst->arch.vex.guest_GPR##zzn = (zzval); \
123 VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, \
sewardj2c6502d2006-01-03 04:08:32 +0000124 offsetof(VexGuestPPC64State,guest_GPR##zzn), \
sewardj2c48c7b2005-11-29 13:05:56 +0000125 sizeof(UWord) ); \
126 } while (0)
127
128
sewardj2c48c7b2005-11-29 13:05:56 +0000129/* Extend the stack segment downwards if needed so as to ensure the
130 new signal frames are mapped to something. Return a Bool
131 indicating whether or not the operation was successful.
132*/
133static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
134{
sewardj2c6502d2006-01-03 04:08:32 +0000135 ThreadId tid = tst->tid;
136 NSegment *stackseg = NULL;
137
138 if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
139 stackseg = VG_(am_find_nsegment)(addr);
140 if (0 && stackseg)
141 VG_(printf)("frame=%p seg=%p-%p\n",
142 addr, stackseg->start, stackseg->end);
143 }
144
145 if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) {
146 VG_(message)(
147 Vg_UserMsg,
148 "Can't extend stack to %p during signal delivery for thread %d:",
149 addr, tid);
150 if (stackseg == NULL)
151 VG_(message)(Vg_UserMsg, " no stack segment");
152 else
153 VG_(message)(Vg_UserMsg, " too small or bad protection modes");
154
155 /* set SIGSEGV to default handler */
156 VG_(set_default_handler)(VKI_SIGSEGV);
157 VG_(synth_fault_mapping)(tid, addr);
158
159 /* The whole process should be about to die, since the default
160 action of SIGSEGV to kill the whole process. */
161 return False;
162 }
163
164 /* For tracking memory events, indicate the entire frame has been
165 allocated. */
166 VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB,
167 size + VG_STACK_REDZONE_SZB );
168
169 return True;
sewardj2c48c7b2005-11-29 13:05:56 +0000170}
171
172
173/* EXPORTED */
174void VG_(sigframe_create)( ThreadId tid,
175 Addr sp_top_of_frame,
176 const vki_siginfo_t *siginfo,
177 void *handler,
178 UInt flags,
179 const vki_sigset_t *mask,
180 void *restorer )
181{
sewardj2c6502d2006-01-03 04:08:32 +0000182 struct vg_sig_private* priv;
183 Addr sp;
184 ThreadState* tst;
185 Int sigNo = siginfo->si_signo;
186 Addr faultaddr;
187 struct rt_sigframe* frame;
188
189 /* Stack must be 16-byte aligned */
190 vg_assert(VG_IS_16_ALIGNED(sizeof(struct rt_sigframe)));
191
192 sp_top_of_frame &= ~0xf;
193 sp = sp_top_of_frame - sizeof(struct rt_sigframe);
194
195 tst = VG_(get_ThreadState)(tid);
196 if (!extend(tst, sp, sp_top_of_frame - sp))
197 return;
198
199 vg_assert(VG_IS_16_ALIGNED(sp));
200
201 frame = (struct rt_sigframe *) sp;
202
203 /* clear it (conservatively) */
204 VG_(memset)(frame, 0, sizeof(*frame));
205
206 /////////
207 frame->pinfo = &frame->info;
208 frame->puc = &frame->uc;
209
210 frame->uc.uc_flags = 0;
211 frame->uc.uc_link = 0;
212 /////////
213
214 /* Set up the stack chain pointer */
215 VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
216 sp, sizeof(UWord) );
217 *(Addr *)sp = tst->arch.vex.guest_GPR1;
218 VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
219 sp, sizeof(UWord) );
220
221 faultaddr = (Addr)siginfo->_sifields._sigfault._addr;
222 if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
223 faultaddr = tst->arch.vex.guest_CIA;
224
225 VG_(memcpy)(&frame->info, siginfo, sizeof(*siginfo));
226 VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
227 (Addr)&frame->info, sizeof(frame->info) );
228
229 frame->uc.uc_flags = 0;
230 frame->uc.uc_link = 0;
231 frame->uc.uc_stack = tst->altstack;
232 frame->uc.uc_sigmask = tst->sig_mask;
233 VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
234 (Addr)(&frame->uc), sizeof(frame->uc) );
235
236# define DO(gpr) frame->uc.uc_mcontext.gp_regs[VKI_PT_R0+gpr] \
237 = tst->arch.vex.guest_GPR##gpr
238 DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7);
239 DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
240 DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
241 DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
242# undef DO
243
244 frame->uc.uc_mcontext.gp_regs[VKI_PT_NIP] = tst->arch.vex.guest_CIA;
245 frame->uc.uc_mcontext.gp_regs[VKI_PT_MSR] = 0xf032; /* pretty arbitrary */
246 frame->uc.uc_mcontext.gp_regs[VKI_PT_ORIG_R3] = tst->arch.vex.guest_GPR3;
247 frame->uc.uc_mcontext.gp_regs[VKI_PT_CTR] = tst->arch.vex.guest_CTR;
248 frame->uc.uc_mcontext.gp_regs[VKI_PT_LNK] = tst->arch.vex.guest_LR;
249 frame->uc.uc_mcontext.gp_regs[VKI_PT_XER] = LibVEX_GuestPPC64_get_XER(
250 &tst->arch.vex);
251 frame->uc.uc_mcontext.gp_regs[VKI_PT_CCR] = LibVEX_GuestPPC64_get_CR(
252 &tst->arch.vex);
253 //mc->mc_gregs[VKI_PT_MQ] = 0;
254 //mc->mc_gregs[VKI_PT_TRAP] = 0;
255 //mc->mc_gregs[VKI_PT_DAR] = fault_addr;
256 //mc->mc_gregs[VKI_PT_DSISR] = 0;
257 //mc->mc_gregs[VKI_PT_RESULT] = 0;
258
259 /* XXX should do FP and vector regs */
260
261 /* set up signal return trampoline */
262 frame->tramp[0] = 0x38000000U + __NR_rt_sigreturn; /* li 0,__NR_rt_sigreturn */
263 frame->tramp[1] = 0x44000002U; /* sc */
264 VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid,
265 (Addr)&frame->tramp, sizeof(frame->tramp));
266
267 /* invalidate any translation of this area */
268 VG_(discard_translations)( (Addr64)&frame->tramp[0],
269 sizeof(frame->tramp), "stack_mcontext" );
270
271 /* set the signal handler to return to the trampoline */
272 SET_SIGNAL_LR(tst, (Addr) &frame->tramp[0]);
273
274 /* Stack pointer for the handler .. (note, back chain set
275 earlier) */
276 SET_SIGNAL_GPR(tid, 1, sp);
277
278 /* Args for the handler .. */
279 SET_SIGNAL_GPR(tid, 3, sigNo);
280 SET_SIGNAL_GPR(tid, 4, (Addr) &frame->info);
281 SET_SIGNAL_GPR(tid, 5, (Addr) &frame->uc);
282 /* the kernel sets this, though it doesn't seem to be in the ABI */
283 SET_SIGNAL_GPR(tid, 6, (Addr) &frame->info);
284
285 /* Handler is in fact a standard ppc64-linux function descriptor,
286 so extract the function entry point and also the toc ptr to use. */
287 SET_SIGNAL_GPR(tid, 2, (Addr) ((ULong*)handler)[1]);
288 tst->arch.vex.guest_CIA = (Addr) ((ULong*)handler)[0];
289
290 priv = &frame->priv;
291 priv->magicPI = 0x31415927;
292 priv->sigNo_private = sigNo;
293 priv->shadow = tst->arch.vex_shadow;
294
295 if (0)
296 VG_(printf)("pushed signal frame; %R1 now = %p, "
297 "next %%CIA = %p, status=%d\n",
298 sp, tst->arch.vex.guest_CIA, tst->status);
sewardj2c48c7b2005-11-29 13:05:56 +0000299}
300
301
302/*------------------------------------------------------------*/
303/*--- Destroying signal frames ---*/
304/*------------------------------------------------------------*/
305
306/* EXPORTED */
307void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
308{
sewardj2c6502d2006-01-03 04:08:32 +0000309 ThreadState *tst;
310 struct vg_sig_private *priv;
311 Addr sp;
312 UInt frame_size;
313 struct rt_sigframe *frame;
314 Int sigNo;
315 Bool has_siginfo = isRT;
316
317 vg_assert(VG_(is_valid_tid)(tid));
318 tst = VG_(get_ThreadState)(tid);
319
320 /* Check that the stack frame looks valid */
321 sp = tst->arch.vex.guest_GPR1;
322 vg_assert(VG_IS_16_ALIGNED(sp));
323 /* JRS 17 Nov 05: This code used to check that *sp -- which should
324 have been set by the stwu at the start of the handler -- points
325 to just above the frame (ie, the previous frame). However, that
326 isn't valid when delivering signals on alt stacks. So I removed
327 it. The frame is still sanity-checked using the priv->magicPI
328 field. */
329
330 frame = (struct rt_sigframe *)sp;
331 frame_size = sizeof(*frame);
332 priv = &frame->priv;
333 vg_assert(priv->magicPI == 0x31415927);
334 tst->sig_mask = frame->uc.uc_sigmask;
335 tst->tmp_sig_mask = tst->sig_mask;
336
337 sigNo = priv->sigNo_private;
338
339# define DO(gpr) tst->arch.vex.guest_GPR##gpr \
340 = frame->uc.uc_mcontext.gp_regs[VKI_PT_R0+gpr]
341 DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7);
342 DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
343 DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
344 DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
345# undef DO
346
347 tst->arch.vex.guest_CIA = frame->uc.uc_mcontext.gp_regs[VKI_PT_NIP];
348
349 LibVEX_GuestPPC64_put_CR( frame->uc.uc_mcontext.gp_regs[VKI_PT_CCR],
350 &tst->arch.vex );
351
352 tst->arch.vex.guest_LR = frame->uc.uc_mcontext.gp_regs[VKI_PT_LNK];
353 tst->arch.vex.guest_CTR = frame->uc.uc_mcontext.gp_regs[VKI_PT_CTR];
354 LibVEX_GuestPPC64_put_XER( frame->uc.uc_mcontext.gp_regs[VKI_PT_XER],
355 &tst->arch.vex );
356
357 tst->arch.vex_shadow = priv->shadow;
358
359 VG_TRACK(die_mem_stack_signal, sp, frame_size);
360
361 if (VG_(clo_trace_signals))
362 VG_(message)(Vg_DebugMsg,
363 "vg_pop_signal_frame (thread %d): isRT=%d valid magic; EIP=%p",
364 tid, has_siginfo, tst->arch.vex.guest_CIA);
365
366 /* tell the tools */
367 VG_TRACK( post_deliver_signal, tid, sigNo );
sewardj2c48c7b2005-11-29 13:05:56 +0000368}
369
370/*--------------------------------------------------------------------*/
371/*--- end sigframe-ppc64-linux.c ---*/
372/*--------------------------------------------------------------------*/