1
2 /*--------------------------------------------------------------------*/
3 /*--- Create/destroy signal delivery frames. ---*/
4 /*--- sigframe-ppc32-aix5.c ---*/
5 /*--------------------------------------------------------------------*/
6
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
11 Copyright (C) 2006-2010 OpenWorks LLP
12 info@open-works.co.uk
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30
31 Neither the names of the U.S. Department of Energy nor the
32 University of California nor the names of its contributors may be
33 used to endorse or promote products derived from this software
34 without prior written permission.
35 */
36
37 #if defined(VGP_ppc32_aix5)
38
39 #include "pub_core_basics.h"
40 #include "pub_core_vki.h"
41 #include "pub_core_vkiscnums.h"
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_signals.h"
50 #include "pub_core_tooliface.h"
51 #include "pub_core_trampoline.h"
52 #include "pub_core_transtab.h" // VG_(discard_translations)
53 #include "pub_core_sigframe.h" /* self */
54
55
56 /* This module creates and removes signal frames for signal deliveries
57 on ppc32-aix5. Kludgey; the machine state ought to be saved in a
58 ucontext and retrieved from it later, so the handler can modify it
59 and return. However .. for now .. just stick the vex guest state
60 in the frame and snarf it again later.
61
62 Also, don't bother with creating siginfo and ucontext in the
63 handler, although do point them somewhere non-faulting.
64 */
65 struct hacky_sigframe {
66 UChar lower_guardzone[512]; // put nothing here
67 VexGuestPPC32State gst;
68 VexGuestPPC32State gshadow1;
69 VexGuestPPC32State gshadow2;
70 UInt magicPI;
71 UInt sigNo_private;
72 UInt tramp[2];
73 UChar upper_guardzone[512]; // put nothing here
74 };
75
76
77 /* Extend the stack segment downwards if needed so as to ensure the
78 new signal frames are mapped to something. Return a Bool
79 indicating whether or not the operation was successful.
80 */
extend(ThreadState * tst,Addr addr,SizeT size)81 static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
82 {
83 ThreadId tid = tst->tid;
84 /* For tracking memory events, indicate the entire frame has been
85 allocated. Except, don't mess with the area which
86 overlaps the previous frame's redzone. */
87 /* XXX is the following call really right? compared with the
88 amd64-linux version, this doesn't appear to handle the redzone
89 in the same way. */
90 VG_TRACK( new_mem_stack_signal,
91 addr, size - VG_STACK_REDZONE_SZB, tid );
92 return True;
93 }
94
95 #define SET_SIGNAL_LR(zztst, zzval) \
96 do { tst->arch.vex.guest_LR = (zzval); \
97 VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, \
98 offsetof(VexGuestPPC32State,guest_LR), \
99 sizeof(UWord) ); \
100 } while (0)
101
102 #define SET_SIGNAL_GPR(zztst, zzn, zzval) \
103 do { tst->arch.vex.guest_GPR##zzn = (zzval); \
104 VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, \
105 offsetof(VexGuestPPC32State,guest_GPR##zzn), \
106 sizeof(UWord) ); \
107 } while (0)
108
109
110 /* Create a signal frame for thread 'tid'. */
VG_(sigframe_create)111 void VG_(sigframe_create) ( ThreadId tid,
112 Addr sp_top_of_frame,
113 const vki_siginfo_t *siginfo,
114 const struct vki_ucontext *siguc,
115 void *handler,
116 UInt flags,
117 const vki_sigset_t *mask,
118 void *restorer )
119 {
120 ThreadState* tst;
121 Addr sp;
122 struct hacky_sigframe* frame;
123 Int sigNo = siginfo->si_signo;
124 Int __NR_FAKE_SIGRETURN = __NR_AIX5_FAKE_SIGRETURN;
125
126 vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
127
128 sp_top_of_frame &= ~0xf;
129 sp = sp_top_of_frame - sizeof(struct hacky_sigframe);
130
131 tst = VG_(get_ThreadState)(tid);
132 if (!extend(tst, sp, sp_top_of_frame - sp))
133 return;
134
135 vg_assert(VG_IS_16_ALIGNED(sp));
136
137 frame = (struct hacky_sigframe *) sp;
138
139 /* clear it (very conservatively) */
140 VG_(memset)(&frame->lower_guardzone, 0, 512);
141 VG_(memset)(&frame->gst, 0, sizeof(VexGuestPPC32State));
142 VG_(memset)(&frame->gshadow1, 0, sizeof(VexGuestPPC32State));
143 VG_(memset)(&frame->gshadow2, 0, sizeof(VexGuestPPC32State));
144
145 /* save stuff in frame */
146 frame->gst = tst->arch.vex;
147 frame->gshadow1 = tst->arch.vex_shadow1;
148 frame->gshadow2 = tst->arch.vex_shadow2;
149 frame->sigNo_private = sigNo;
150 frame->magicPI = 0x31415927;
151
152 /* Set up stack frame pointer */
153 sp += 256;
154 vg_assert(sp == (Addr)&frame->lower_guardzone[256]);
155 VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
156 sp, sizeof(UWord) );
157 *(Addr*)sp = tst->arch.vex.guest_GPR1;
158 VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
159 sp, sizeof(UWord) );
160
161 /* Set regs for the handler */
162 SET_SIGNAL_GPR(tid, 1, sp);
163 SET_SIGNAL_GPR(tid, 2, ((UWord*)handler)[1]);
164 SET_SIGNAL_GPR(tid, 3, sigNo);
165 SET_SIGNAL_GPR(tid, 4, 0); /* XXX: the siginfo* */
166 SET_SIGNAL_GPR(tid, 5, 0); /* XXX: the ucontext* */
167 tst->arch.vex.guest_CIA = ((UWord*)handler)[0];
168
169 /* set up return trampoline */
170 vg_assert(__NR_FAKE_SIGRETURN >= 10000);
171 vg_assert(__NR_FAKE_SIGRETURN <= 32767);
172 frame->tramp[0] = 0x38400000U
173 + __NR_FAKE_SIGRETURN; /* li 2,__NR_FAKE_SIGRETURN */
174 frame->tramp[1] = 0x44000002U; /* sc */
175
176 /* invalidate any translation of this area */
177 VG_(discard_translations)( (Addr64)(Addr)&frame->tramp[0],
178 sizeof(frame->tramp), "sigframe tramp" );
179 /* set the signal handler to return to the trampoline */
180 SET_SIGNAL_LR(tst, (Addr) &frame->tramp[0]);
181
182 VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid,
183 (Addr)&frame->tramp, sizeof(frame->tramp));
184
185 if (0) {
186 VG_(printf)("pushed signal frame for sig %d; R1 now = %#lx, "
187 "next %%CIA = %#x, status=%d\n",
188 sigNo,
189 sp, tst->arch.vex.guest_CIA, tst->status);
190 VG_(printf)("trampoline is at %p\n", &frame->tramp[0]);
191 }
192 }
193
194
195 /* Remove a signal frame from thread 'tid's stack, and restore the CPU
196 state from it. Note, isRT is irrelevant here. */
VG_(sigframe_destroy)197 void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
198 {
199 ThreadState *tst;
200 Addr sp;
201 Int sigNo;
202 struct hacky_sigframe* frame;
203
204 vg_assert(VG_(is_valid_tid)(tid));
205 tst = VG_(get_ThreadState)(tid);
206
207 /* Check that the stack frame looks valid */
208 sp = tst->arch.vex.guest_GPR1;
209 vg_assert(VG_IS_16_ALIGNED(sp));
210
211 frame = (struct hacky_sigframe*)(sp - 256);
212 vg_assert(frame->magicPI == 0x31415927);
213
214 /* restore the entire guest state, and shadows, from the
215 frame. Note, as per comments above, this is a kludge - should
216 restore it from saved ucontext. Oh well. */
217 tst->arch.vex = frame->gst;
218 tst->arch.vex_shadow1 = frame->gshadow1;
219 tst->arch.vex_shadow2 = frame->gshadow2;
220 sigNo = frame->sigNo_private;
221
222 if (VG_(clo_trace_signals))
223 VG_(message)(Vg_DebugMsg,
224 "vg_pop_signal_frame (thread %d): valid magic; CIA=%#x\n",
225 tid, tst->arch.vex.guest_CIA);
226
227 VG_TRACK( die_mem_stack_signal,
228 (Addr)frame,
229 sizeof(struct hacky_sigframe) - VG_STACK_REDZONE_SZB );
230
231 /* tell the tools */
232 VG_TRACK( post_deliver_signal, tid, sigNo );
233 }
234
235 #endif // defined(VGP_ppc32_aix5)
236
237 /*--------------------------------------------------------------------*/
238 /*--- end ---*/
239 /*--------------------------------------------------------------------*/
240