• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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