blob: c03ebd1efce6d57f5644c7b17e641f903246811e [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- Implementation of POSIX signals. ---*/
4/*--- vg_signals.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, an x86 protected-mode emulator
9 designed for debugging and profiling binaries on x86-Unixes.
10
11 Copyright (C) 2000-2002 Julian Seward
12 jseward@acm.org
13 Julian_Seward@muraroa.demon.co.uk
14
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
30 The GNU General Public License is contained in the file LICENSE.
31*/
32
33
34#include "vg_include.h"
35#include "vg_constants.h"
36#include "vg_unsafe.h"
sewardj54cacf02002-04-12 23:24:59 +000037#include "valgrind.h" /* for VALGRIND_MAGIC_SEQUENCE */
sewardjde4a1d02002-03-22 01:27:54 +000038
39/* ---------------------------------------------------------------------
sewardjde4a1d02002-03-22 01:27:54 +000040 Signal state for this process.
41 ------------------------------------------------------------------ */
42
43/* For each signal, the current action. Is NULL if the client hasn't
44 asked to handle the signal. Consequently, we expect never to
45 receive a signal for which the corresponding handler is NULL. */
46void* VG_(sighandler)[VKI_KNSIG];
47
sewardj77e466c2002-04-14 02:29:29 +000048
sewardjde4a1d02002-03-22 01:27:54 +000049/* For each signal, either:
50 -- VG_SIGIDLE if not pending and not running
51 -- Handler address if pending
52 -- VG_SIGRUNNING if the handler is running and hasn't (returned or
53 unblocked the signal using sigprocmask following a longjmp out
54 of the handler).
55 */
56#define VG_SIGIDLE ((void*)0)
57#define VG_SIGRUNNING ((void*)1)
58
59void* VG_(sigpending)[VKI_KNSIG];
60
sewardj2e93c502002-04-12 11:12:52 +000061
sewardj77e466c2002-04-14 02:29:29 +000062/* For each signal that we have a handler for (ie, for those for which
63 the VG_(sighandler) entry is non-NULL), record whether or not the
64 client asked for syscalls to be restartable (SA_RESTART) if
65 interrupted by this signal. We need to consult this when a signal
66 returns, if it should happen that the signal which we delivered has
67 interrupted a system call. */
68Bool vg_sig_sarestart[VKI_KNSIG];
69
70
sewardj2e93c502002-04-12 11:12:52 +000071/* ---------------------------------------------------------------------
72 Handy utilities to block/restore all host signals.
73 ------------------------------------------------------------------ */
74
75/* Block all host signals, dumping the old mask in *saved_mask. */
76void VG_(block_all_host_signals) ( /* OUT */ vki_ksigset_t* saved_mask )
77{
78 Int ret;
79 vki_ksigset_t block_procmask;
80 VG_(ksigfillset)(&block_procmask);
81 ret = VG_(ksigprocmask)
82 (VKI_SIG_SETMASK, &block_procmask, saved_mask);
83 vg_assert(ret == 0);
84}
85
86/* Restore the blocking mask using the supplied saved one. */
87void VG_(restore_host_signals) ( /* IN */ vki_ksigset_t* saved_mask )
88{
89 Int ret;
90 ret = VG_(ksigprocmask)(VKI_SIG_SETMASK, saved_mask, NULL);
91 vg_assert(ret == 0);
92}
sewardjde4a1d02002-03-22 01:27:54 +000093
94
95/* ---------------------------------------------------------------------
96 The signal simulation proper. A simplified version of what the
97 Linux kernel does.
98 ------------------------------------------------------------------ */
99
100/* A structure in which to save the application's registers
101 during the execution of signal handlers. */
102
103typedef
104 struct {
sewardj2e93c502002-04-12 11:12:52 +0000105 /* These are parameters to the signal handler. */
106 UInt retaddr; /* Sig handler's (bogus) return address */
107 Int sigNo; /* The arg to the sig handler. */
108 Addr psigInfo; /* ptr to siginfo_t; NULL for now. */
109 Addr puContext; /* ptr to ucontext; NULL for now. */
110 /* Sanity check word. */
sewardjde4a1d02002-03-22 01:27:54 +0000111 UInt magicPI;
sewardj2e93c502002-04-12 11:12:52 +0000112 /* Saved processor state. */
sewardjde4a1d02002-03-22 01:27:54 +0000113 UInt fpustate[VG_SIZE_OF_FPUSTATE_W];
114 UInt eax;
115 UInt ecx;
116 UInt edx;
117 UInt ebx;
118 UInt ebp;
119 UInt esp;
120 UInt esi;
121 UInt edi;
122 Addr eip;
123 UInt eflags;
sewardj2e93c502002-04-12 11:12:52 +0000124 /* Scheduler-private stuff: what was the thread's status prior to
125 delivering this signal? */
126 ThreadStatus status;
127 /* Sanity check word. Is the highest-addressed word; do not
128 move!*/
sewardjde4a1d02002-03-22 01:27:54 +0000129 UInt magicE;
130 }
sewardj2e93c502002-04-12 11:12:52 +0000131 VgSigFrame;
sewardjde4a1d02002-03-22 01:27:54 +0000132
133
134
sewardjde4a1d02002-03-22 01:27:54 +0000135/* Set up a stack frame (VgSigContext) for the client's signal
136 handler. This includes the signal number and a bogus return
137 address. */
138static
sewardj2e93c502002-04-12 11:12:52 +0000139void vg_push_signal_frame ( ThreadId tid, int sigNo )
sewardjde4a1d02002-03-22 01:27:54 +0000140{
141 Int i;
sewardj2e93c502002-04-12 11:12:52 +0000142 Addr esp;
143 VgSigFrame* frame;
144 ThreadState* tst;
145
146 tst = VG_(get_thread_state)(tid);
147 esp = tst->m_esp;
148
149 esp -= sizeof(VgSigFrame);
150 frame = (VgSigFrame*)esp;
151 /* Assert that the frame is placed correctly. */
152 vg_assert( (sizeof(VgSigFrame) & 0x3) == 0 );
153 vg_assert( ((Char*)(&frame->magicE)) + sizeof(UInt)
154 == ((Char*)(tst->m_esp)) );
155
156 frame->retaddr = (UInt)(&VG_(signalreturn_bogusRA));
157 frame->sigNo = sigNo;
158 frame->psigInfo = (Addr)NULL;
159 frame->puContext = (Addr)NULL;
160 frame->magicPI = 0x31415927;
161
sewardjde4a1d02002-03-22 01:27:54 +0000162 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj2e93c502002-04-12 11:12:52 +0000163 frame->fpustate[i] = tst->m_fpu[i];
sewardjde4a1d02002-03-22 01:27:54 +0000164
sewardj2e93c502002-04-12 11:12:52 +0000165 frame->eax = tst->m_eax;
166 frame->ecx = tst->m_ecx;
167 frame->edx = tst->m_edx;
168 frame->ebx = tst->m_ebx;
169 frame->ebp = tst->m_ebp;
170 frame->esp = tst->m_esp;
171 frame->esi = tst->m_esi;
172 frame->edi = tst->m_edi;
173 frame->eip = tst->m_eip;
174 frame->eflags = tst->m_eflags;
sewardjde4a1d02002-03-22 01:27:54 +0000175
sewardj2e93c502002-04-12 11:12:52 +0000176 frame->status = tst->status;
sewardjde4a1d02002-03-22 01:27:54 +0000177
sewardj2e93c502002-04-12 11:12:52 +0000178 frame->magicE = 0x27182818;
179
180 /* Set the thread so it will next run the handler. */
181 tst->m_esp = esp;
182 tst->m_eip = (Addr)VG_(sigpending)[sigNo];
183 /* This thread needs to be marked runnable, but we leave that the
184 caller to do. */
sewardjde4a1d02002-03-22 01:27:54 +0000185
186 /* Make sigNo and retaddr fields readable -- at 0(%ESP) and 4(%ESP) */
187 if (VG_(clo_instrument)) {
188 VGM_(make_readable) ( ((Addr)esp)+0 ,4 );
189 VGM_(make_readable) ( ((Addr)esp)+4 ,4 );
190 }
191
sewardjde4a1d02002-03-22 01:27:54 +0000192 /*
193 VG_(printf)("pushed signal frame; %%ESP now = %p, next %%EBP = %p\n",
sewardj2e93c502002-04-12 11:12:52 +0000194 esp, tst->m_eip);
sewardjde4a1d02002-03-22 01:27:54 +0000195 */
196}
197
198
199/* Clear the signal frame created by vg_push_signal_frame, restore the
200 simulated machine state, and return the signal number that the
201 frame was for. */
202static
sewardj2e93c502002-04-12 11:12:52 +0000203Int vg_pop_signal_frame ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000204{
sewardj2e93c502002-04-12 11:12:52 +0000205 Addr esp;
sewardjde4a1d02002-03-22 01:27:54 +0000206 Int sigNo, i;
sewardj2e93c502002-04-12 11:12:52 +0000207 VgSigFrame* frame;
208 ThreadState* tst;
sewardjde4a1d02002-03-22 01:27:54 +0000209
sewardj2e93c502002-04-12 11:12:52 +0000210 tst = VG_(get_thread_state)(tid);
211
sewardj54cacf02002-04-12 23:24:59 +0000212 /* Correctly reestablish the frame base address. */
sewardj2e93c502002-04-12 11:12:52 +0000213 esp = tst->m_esp;
sewardj54cacf02002-04-12 23:24:59 +0000214 frame = (VgSigFrame*)
215 (esp -4 /* because the handler's RET pops the RA */
216 +20 /* because signalreturn_bogusRA pushes 5 words */);
sewardj2e93c502002-04-12 11:12:52 +0000217
218 vg_assert(frame->magicPI == 0x31415927);
219 vg_assert(frame->magicE == 0x27182818);
sewardjde4a1d02002-03-22 01:27:54 +0000220 if (VG_(clo_trace_signals))
221 VG_(message)(Vg_DebugMsg, "vg_pop_signal_frame: valid magic");
222
223 /* restore machine state */
224 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj2e93c502002-04-12 11:12:52 +0000225 tst->m_fpu[i] = frame->fpustate[i];
sewardjde4a1d02002-03-22 01:27:54 +0000226
sewardj2e93c502002-04-12 11:12:52 +0000227 /* Mark the frame structure as nonaccessible. Has to happen
228 _before_ vg_m_state.m_esp is given a new value.
229 handle_esp_assignment reads %ESP from baseBlock, so we park it
230 there first. Re-place the junk there afterwards. */
231 if (VG_(clo_instrument)) {
232 vg_assert(VG_(baseBlock)[VGOFF_(m_esp)] == 0xDEADBEEF);
233 VG_(baseBlock)[VGOFF_(m_esp)] = tst->m_esp;
234 VGM_(handle_esp_assignment) ( frame->esp );
235 VG_(baseBlock)[VGOFF_(m_esp)] = 0xDEADBEEF;
236 }
sewardjde4a1d02002-03-22 01:27:54 +0000237
238 /* Restore machine state from the saved context. */
sewardj2e93c502002-04-12 11:12:52 +0000239 tst->m_eax = frame->eax;
240 tst->m_ecx = frame->ecx;
241 tst->m_edx = frame->edx;
242 tst->m_ebx = frame->ebx;
243 tst->m_ebp = frame->ebp;
244 tst->m_esp = frame->esp;
245 tst->m_esi = frame->esi;
246 tst->m_edi = frame->edi;
247 tst->m_eflags = frame->eflags;
248 tst->m_eip = frame->eip;
249 sigNo = frame->sigNo;
250
251 /* And restore the thread's status to what it was before the signal
252 was delivered. */
253 tst->status = frame->status;
254
sewardjde4a1d02002-03-22 01:27:54 +0000255 return sigNo;
256}
257
258
259/* A handler is returning. Restore the machine state from the stacked
260 VgSigContext and continue with whatever was going on before the
sewardj77e466c2002-04-14 02:29:29 +0000261 handler ran. Returns the SA_RESTART syscall-restartability-status
262 of the delivered signal. */
sewardjde4a1d02002-03-22 01:27:54 +0000263
sewardj77e466c2002-04-14 02:29:29 +0000264Bool VG_(signal_returns) ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000265{
sewardj2e93c502002-04-12 11:12:52 +0000266 Int sigNo;
sewardjde4a1d02002-03-22 01:27:54 +0000267 vki_ksigset_t saved_procmask;
268
269 /* Block host signals ... */
sewardj2e93c502002-04-12 11:12:52 +0000270 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000271
sewardj2e93c502002-04-12 11:12:52 +0000272 /* Pop the signal frame and restore tid's status to what it was
273 before the signal was delivered. */
274 sigNo = vg_pop_signal_frame(tid);
sewardjde4a1d02002-03-22 01:27:54 +0000275
276 /* You would have thought that the following assertion made sense
277 here:
278
279 vg_assert(vg_sigpending[sigNo] == VG_SIGRUNNING);
280
281 Alas, you would be wrong. If a sigprocmask has been intercepted
282 and it unblocks this signal, then vg_sigpending[sigNo] will
283 either be VG_SIGIDLE, or (worse) another instance of it will
284 already have arrived, so that the stored value is that of the
285 handler.
286
287 Note that these anomalies can only occur when a signal handler
288 unblocks its own signal inside itself AND THEN RETURNS anyway
289 (which seems a bizarre thing to do).
290
291 Ho Hum. This seems like a race condition which surely isn't
292 handled correctly. */
293
294 vg_assert(sigNo >= 1 && sigNo < VKI_KNSIG);
295 VG_(sigpending)[sigNo] = VG_SIGIDLE;
296
297 /* Unlock and return. */
sewardj2e93c502002-04-12 11:12:52 +0000298 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000299
sewardj77e466c2002-04-14 02:29:29 +0000300 /* Scheduler now can resume this thread, or perhaps some other.
301 Tell the scheduler whether or not any syscall interrupted by
302 this signal should be restarted, if possible, or no. */
303 return vg_sig_sarestart[sigNo];
sewardjde4a1d02002-03-22 01:27:54 +0000304}
305
306
307/* Deliver all pending signals, by building stack frames for their
308 handlers. */
sewardj2e93c502002-04-12 11:12:52 +0000309void VG_(deliver_signals) ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000310{
sewardjde4a1d02002-03-22 01:27:54 +0000311 vki_ksigset_t saved_procmask;
sewardj2e93c502002-04-12 11:12:52 +0000312 Int sigNo;
sewardjde4a1d02002-03-22 01:27:54 +0000313 Bool found;
314
315 /* A cheap check. We don't need to have exclusive access
316 to the queue, because in the worst case, vg_oursignalhandler
317 will add signals, causing us to return, thinking there
318 are no signals to deliver, when in fact there are some.
319 A subsequent call here will handle the signal(s) we missed.
320 */
321 found = False;
322 for (sigNo = 1; sigNo < VKI_KNSIG; sigNo++)
323 if (VG_(sigpending)[sigNo] != VG_SIGIDLE &&
324 VG_(sigpending)[sigNo] != VG_SIGRUNNING) found = True;
325
326 if (!found) return;
327
328 /* Now we have to do it properly. Get exclusive access by
329 blocking all the host's signals. That means vg_oursignalhandler
330 can't run whilst we are messing with stuff.
331 */
sewardj2e93c502002-04-12 11:12:52 +0000332 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000333
sewardj2e93c502002-04-12 11:12:52 +0000334 /* Look for signals to deliver ... */
sewardjde4a1d02002-03-22 01:27:54 +0000335 for (sigNo = 1; sigNo < VKI_KNSIG; sigNo++) {
336 if (VG_(sigpending)[sigNo] == VG_SIGIDLE ||
337 VG_(sigpending)[sigNo] == VG_SIGRUNNING) continue;
338
339 if (VG_(clo_trace_signals))
340 VG_(message)(Vg_DebugMsg,"delivering signal %d", sigNo );
341
342 /* Create a signal delivery frame, and set the client's %ESP and
343 %EIP so that when execution continues, we will enter the
344 signal handler with the frame on top of the client's stack,
345 as it expects. */
sewardj2e93c502002-04-12 11:12:52 +0000346 vg_push_signal_frame ( tid, sigNo );
347 VG_(get_thread_state)(tid)->status = VgTs_Runnable;
348
sewardjde4a1d02002-03-22 01:27:54 +0000349 /* Signify that the signal has been delivered. */
350 VG_(sigpending)[sigNo] = VG_SIGRUNNING;
351 }
352
353 /* Unlock and return. */
sewardj2e93c502002-04-12 11:12:52 +0000354 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000355 return;
356}
357
358
sewardjde4a1d02002-03-22 01:27:54 +0000359/* Receive a signal from the host, and either discard it or park it in
360 the queue of pending signals. All other signals will be blocked
361 when this handler runs. Runs with all host signals blocked, so as
362 to have mutual exclusion when adding stuff to the queue. */
363
364static void VG_(oursignalhandler) ( Int sigNo )
365{
sewardj2e93c502002-04-12 11:12:52 +0000366 Int dummy_local;
sewardjde4a1d02002-03-22 01:27:54 +0000367 vki_ksigset_t saved_procmask;
368
369 if (VG_(clo_trace_signals)) {
370 VG_(start_msg)(Vg_DebugMsg);
371 VG_(add_to_msg)("signal %d arrived ... ", sigNo );
372 }
373 vg_assert(sigNo >= 1 && sigNo < VKI_KNSIG);
374
375 /* Sanity check. Ensure we're really running on the signal stack
376 we asked for. */
377 if ( !(
sewardj2e93c502002-04-12 11:12:52 +0000378 ((Char*)(&(VG_(sigstack)[0])) <= (Char*)(&dummy_local))
sewardjde4a1d02002-03-22 01:27:54 +0000379 &&
sewardj2e93c502002-04-12 11:12:52 +0000380 ((Char*)(&dummy_local) < (Char*)(&(VG_(sigstack)[10000])))
sewardjde4a1d02002-03-22 01:27:54 +0000381 )
382 ) {
sewardj2e93c502002-04-12 11:12:52 +0000383 VG_(message)(Vg_DebugMsg,
384 "FATAL: signal delivered on the wrong stack?!");
385 VG_(message)(Vg_DebugMsg,
386 "A possible workaround follows. Please tell me");
387 VG_(message)(Vg_DebugMsg,
388 "(jseward@acm.org) if the suggested workaround doesn't help.");
sewardjde4a1d02002-03-22 01:27:54 +0000389 VG_(unimplemented)
sewardj2e93c502002-04-12 11:12:52 +0000390 ("support for progs compiled with -p/-pg; "
391 "rebuild your prog without -p/-pg");
sewardjde4a1d02002-03-22 01:27:54 +0000392 }
393
sewardj2e93c502002-04-12 11:12:52 +0000394 vg_assert((Char*)(&(VG_(sigstack)[0])) <= (Char*)(&dummy_local));
395 vg_assert((Char*)(&dummy_local) < (Char*)(&(VG_(sigstack)[10000])));
sewardjde4a1d02002-03-22 01:27:54 +0000396
397 if (sigNo == VKI_SIGABRT && VG_(sighandler)[sigNo] == NULL) {
398 /* We get here if SIGABRT is delivered and the client hasn't
399 asked to catch it. The aim is to exit in a controlled
400 manner. */
401 if (VG_(clo_trace_signals)) {
402 VG_(add_to_msg)("catching SIGABRT");
403 VG_(end_msg)();
404 }
405 VG_(ksignal)(VKI_SIGABRT, VKI_SIG_DFL);
sewardjde4a1d02002-03-22 01:27:54 +0000406 VG_(longjmpd_on_signal) = VKI_SIGABRT;
sewardj2e93c502002-04-12 11:12:52 +0000407 __builtin_longjmp(VG_(scheduler_jmpbuf),1);
sewardjde4a1d02002-03-22 01:27:54 +0000408 }
409
sewardj2e93c502002-04-12 11:12:52 +0000410 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000411
412 if (VG_(sighandler)[sigNo] == NULL) {
413 if (VG_(clo_trace_signals)) {
414 VG_(add_to_msg)("unexpected!");
415 VG_(end_msg)();
416 }
sewardj2e93c502002-04-12 11:12:52 +0000417 /* Note: we panic with all signals blocked here. Don't think
418 that matters. */
sewardjde4a1d02002-03-22 01:27:54 +0000419 VG_(panic)("vg_oursignalhandler: unexpected signal");
420 }
421
422 /* Decide what to do with it. */
423 if (VG_(sigpending)[sigNo] == VG_SIGRUNNING) {
424 /* Already running; ignore it. */
425 if (VG_(clo_trace_signals)) {
426 VG_(add_to_msg)("already running; discarded" );
427 VG_(end_msg)();
428 }
429 }
430 else
431 if (VG_(sigpending)[sigNo] != VG_SIGRUNNING &&
432 VG_(sigpending)[sigNo] != VG_SIGIDLE) {
433 /* Not running and not idle == pending; ignore it. */
434 if (VG_(clo_trace_signals)) {
435 VG_(add_to_msg)("already pending; discarded" );
436 VG_(end_msg)();
437 }
438 }
439 else {
sewardj2e93c502002-04-12 11:12:52 +0000440 /* Ok, we'd better deliver it to the client. */
sewardjde4a1d02002-03-22 01:27:54 +0000441 vg_assert(VG_(sigpending)[sigNo] == VG_SIGIDLE);
sewardj2e93c502002-04-12 11:12:52 +0000442 /* Queue it up for delivery at some point in the future. */
443 VG_(sigpending)[sigNo] = VG_(sighandler)[sigNo];
444 if (VG_(clo_trace_signals)) {
445 VG_(add_to_msg)("queued" );
446 VG_(end_msg)();
sewardjde4a1d02002-03-22 01:27:54 +0000447 }
448 }
449
sewardj2e93c502002-04-12 11:12:52 +0000450 /* We've finished messing with the queue, so re-enable host
451 signals. */
452 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000453
sewardjde4a1d02002-03-22 01:27:54 +0000454 if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS
455 || sigNo == VKI_SIGFPE || sigNo == VKI_SIGILL) {
sewardj2e93c502002-04-12 11:12:52 +0000456 /* Can't continue; must longjmp back to the scheduler and thus
457 enter the sighandler immediately. */
sewardjde4a1d02002-03-22 01:27:54 +0000458 VG_(longjmpd_on_signal) = sigNo;
sewardj2e93c502002-04-12 11:12:52 +0000459 __builtin_longjmp(VG_(scheduler_jmpbuf),1);
sewardjde4a1d02002-03-22 01:27:54 +0000460 }
461}
462
463
464/* The outer insn loop calls here to reenable a host signal if
465 vg_oursighandler longjmp'd.
466*/
467void VG_(unblock_host_signal) ( Int sigNo )
468{
469 Int ret;
470 vki_ksigset_t set;
471 VG_(ksigemptyset)(&set);
472 ret = VG_(ksigaddset)(&set,sigNo);
473 vg_assert(ret == 0);
474 ret = VG_(ksigprocmask)(VKI_SIG_UNBLOCK,&set,NULL);
475 vg_assert(ret == 0);
476}
477
478
479static __attribute((unused))
480void pp_vg_ksigaction ( vki_ksigaction* sa )
481{
482 Int i;
483 VG_(printf)("vg_ksigaction: handler %p, flags 0x%x, restorer %p\n",
sewardj9a199dc2002-04-14 13:01:38 +0000484 sa->ksa_handler, (UInt)sa->ksa_flags, sa->ksa_restorer);
sewardjde4a1d02002-03-22 01:27:54 +0000485 VG_(printf)("vg_ksigaction: { ");
486 for (i = 1; i < VKI_KNSIG; i++)
487 if (VG_(ksigismember(&(sa->ksa_mask),i)))
488 VG_(printf)("%d ", i);
489 VG_(printf)("}\n");
490}
491
492
493/* Copy the process' real signal state to the sim state. Whilst
494 doing this, block all real signals.
495*/
496void VG_(sigstartup_actions) ( void )
497{
498 Int i, ret;
499
sewardjde4a1d02002-03-22 01:27:54 +0000500 vki_ksigset_t saved_procmask;
501 vki_kstack_t altstack_info;
502 vki_ksigaction sa;
503
sewardj2e93c502002-04-12 11:12:52 +0000504 /* VG_(printf)("SIGSTARTUP\n"); */
sewardjde4a1d02002-03-22 01:27:54 +0000505 /* Block all signals.
506 saved_procmask remembers the previous mask. */
sewardj2e93c502002-04-12 11:12:52 +0000507 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000508
509 /* Register an alternative stack for our own signal handler to run
510 on. */
511 altstack_info.ss_sp = &(VG_(sigstack)[0]);
512 altstack_info.ss_size = 10000 * sizeof(UInt);
513 altstack_info.ss_flags = 0;
514 ret = VG_(ksigaltstack)(&altstack_info, NULL);
515 if (ret != 0) {
516 VG_(panic)(
517 "vg_sigstartup_actions: couldn't install alternative sigstack");
518 }
519 if (VG_(clo_trace_signals)) {
520 VG_(message)(Vg_DebugExtraMsg,
521 "vg_sigstartup_actions: sigstack installed ok");
522 }
523
524 /* Set initial state for the signal simulation. */
sewardj77e466c2002-04-14 02:29:29 +0000525 for (i = 1; i < VKI_KNSIG; i++) {
526 VG_(sighandler)[i] = NULL;
527 VG_(sigpending)[i] = NULL;
528 vg_sig_sarestart[i] = True; /* An easy default */
529 }
sewardjde4a1d02002-03-22 01:27:54 +0000530
531 for (i = 1; i < VKI_KNSIG; i++) {
532
533 /* Get the old host action */
534 ret = VG_(ksigaction)(i, NULL, &sa);
535 vg_assert(ret == 0);
536
537 /* If there's already a handler set, record it, then route the
538 signal through to our handler. */
539 if (sa.ksa_handler != VKI_SIG_IGN && sa.ksa_handler != VKI_SIG_DFL) {
540 if (VG_(clo_trace_signals))
541 VG_(printf)("snaffling handler 0x%x for signal %d\n",
542 (Addr)(sa.ksa_handler), i );
543 if ((sa.ksa_flags & VKI_SA_ONSTACK) != 0)
544 VG_(unimplemented)
545 ("signals on an alternative stack (SA_ONSTACK)");
sewardj77e466c2002-04-14 02:29:29 +0000546
547 VG_(sighandler)[i] = sa.ksa_handler;
sewardjde4a1d02002-03-22 01:27:54 +0000548 sa.ksa_handler = &VG_(oursignalhandler);
sewardj77e466c2002-04-14 02:29:29 +0000549 /* Save the restart status, then set it to restartable. */
550 vg_sig_sarestart[i]
551 = (sa.ksa_flags & VKI_SA_RESTART) ? True : False;
552 sa.ksa_flags |= VKI_SA_RESTART;
553
sewardjde4a1d02002-03-22 01:27:54 +0000554 ret = VG_(ksigaction)(i, &sa, NULL);
555 vg_assert(ret == 0);
556 }
557 }
558
559 VG_(ksignal)(VKI_SIGABRT, &VG_(oursignalhandler));
560
561 /* Finally, restore the blocking mask. */
sewardj2e93c502002-04-12 11:12:52 +0000562 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000563}
564
565
566/* Copy the process' sim signal state to the real state,
567 for when we transfer from the simulated to real CPU.
568 PROBLEM: what if we're running a signal handler when we
569 get here? Hmm.
570 I guess we wind up in vg_signalreturn_bogusRA, *or* the
571 handler has done/will do a longjmp, in which case we're ok.
572
573 It is important (see vg_startup.S) that this proc does not
574 change the state of the real FPU, since it is called when
575 running the program on the real CPU.
576*/
577void VG_(sigshutdown_actions) ( void )
578{
579 Int i, ret;
580
sewardjde4a1d02002-03-22 01:27:54 +0000581 vki_ksigset_t saved_procmask;
582 vki_ksigaction sa;
583
sewardj2e93c502002-04-12 11:12:52 +0000584 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000585
586 /* copy the sim signal actions to the real ones. */
sewardj77e466c2002-04-14 02:29:29 +0000587 /* Hmm, this isn't accurate. Doesn't properly restore the
588 SA_RESTART flag nor SA_ONSTACK. */
sewardjde4a1d02002-03-22 01:27:54 +0000589 for (i = 1; i < VKI_KNSIG; i++) {
590 if (i == VKI_SIGKILL || i == VKI_SIGSTOP) continue;
591 if (VG_(sighandler)[i] == NULL) continue;
592 ret = VG_(ksigaction)(i, NULL, &sa);
593 vg_assert(ret == 0);
594 sa.ksa_handler = VG_(sighandler)[i];
595 ret = VG_(ksigaction)(i, &sa, NULL);
596 }
597
sewardj2e93c502002-04-12 11:12:52 +0000598 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000599}
600
601
602/* ---------------------------------------------------------------------
603 Handle signal-related syscalls from the simulatee.
604 ------------------------------------------------------------------ */
605
606/* Do more error checking? */
sewardj2e93c502002-04-12 11:12:52 +0000607void VG_(do__NR_sigaction) ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000608{
609 UInt res;
610 void* our_old_handler;
611 vki_ksigaction* new_action;
612 vki_ksigaction* old_action;
sewardj2e93c502002-04-12 11:12:52 +0000613 ThreadState* tst = VG_(get_thread_state)( tid );
614 UInt param1 = tst->m_ebx; /* int sigNo */
615 UInt param2 = tst->m_ecx; /* k_sigaction* new_action */
616 UInt param3 = tst->m_edx; /* k_sigaction* old_action */
sewardjde4a1d02002-03-22 01:27:54 +0000617 new_action = (vki_ksigaction*)param2;
618 old_action = (vki_ksigaction*)param3;
619
620 if (VG_(clo_trace_signals))
621 VG_(message)(Vg_DebugExtraMsg,
622 "__NR_sigaction: sigNo %d, "
623 "new 0x%x, old 0x%x, new flags 0x%x",
624 param1,(UInt)new_action,(UInt)old_action,
625 (UInt)(new_action ? new_action->ksa_flags : 0) );
626 /* VG_(ppSigProcMask)(); */
627
sewardj0ca2a6b2002-03-29 14:02:34 +0000628 /* Rule out various error conditions. The aim is to ensure that if
629 the call is passed to the kernel it will definitely succeed. */
630
631 /* Reject out-of-range signal numbers. */
632 if (param1 < 1 || param1 >= VKI_KNSIG) goto bad_signo;
633
634 /* Reject attempts to set a handler (or set ignore) for SIGKILL. */
635 if ( (param1 == VKI_SIGKILL || param1 == VKI_SIGSTOP)
636 && new_action
637 && new_action->ksa_handler != VKI_SIG_DFL)
638 goto bad_sigkill;
sewardjde4a1d02002-03-22 01:27:54 +0000639
640 our_old_handler = VG_(sighandler)[param1];
641 /* VG_(printf)("old handler = 0x%x\n", our_old_handler); */
642 /* If a new handler has been specified, mess with its handler. */
643 if (new_action) {
644 if (new_action->ksa_handler == VKI_SIG_IGN ||
645 new_action->ksa_handler == VKI_SIG_DFL) {
646 VG_(sighandler)[param1] = NULL;
647 VG_(sigpending)[param1] = NULL;
648 /* Dangerous! Could lose signals like this. */
649 } else {
650 /* VG_(printf)("new handler = 0x%x\n", new_action->ksa_handler); */
651 /* The client isn't allowed to use an alternative signal
652 stack. We, however, must. */
653 if ((new_action->ksa_flags & VKI_SA_ONSTACK) != 0)
654 VG_(unimplemented)
655 ("signals on an alternative stack (SA_ONSTACK)");
656 new_action->ksa_flags |= VKI_SA_ONSTACK;
657 VG_(sighandler)[param1] = new_action->ksa_handler;
sewardj77e466c2002-04-14 02:29:29 +0000658 vg_sig_sarestart[param1]
659 = (new_action->ksa_flags & VKI_SA_RESTART) ? True : False;
660 new_action->ksa_flags |= VKI_SA_RESTART;
sewardjde4a1d02002-03-22 01:27:54 +0000661 new_action->ksa_handler = &VG_(oursignalhandler);
662 }
663 }
664
sewardj2e93c502002-04-12 11:12:52 +0000665 KERNEL_DO_SYSCALL(tid,res);
sewardjde4a1d02002-03-22 01:27:54 +0000666 /* VG_(printf)("RES = %d\n", res); */
sewardj0ca2a6b2002-03-29 14:02:34 +0000667
sewardjde4a1d02002-03-22 01:27:54 +0000668 /* If the client asks for the old handler, maintain our fiction
669 by stuffing in the handler it thought it asked for ... */
670 if (old_action) {
671 if (old_action->ksa_handler == VKI_SIG_IGN ||
672 old_action->ksa_handler == VKI_SIG_DFL) {
673 /* No old action; we should have a NULL handler. */
674 vg_assert(our_old_handler == NULL);
675 } else {
676 /* There's a handler. */
677 if (param1 != VKI_SIGKILL && param1 != VKI_SIGABRT) {
678 vg_assert(old_action->ksa_handler == &VG_(oursignalhandler));
679 vg_assert((old_action->ksa_flags & VKI_SA_ONSTACK) != 0);
680 }
681 old_action->ksa_handler = our_old_handler;
682 /* Since the client is not allowed to ask for an alternative
683 sig stack, unset the bit for anything we pass back to
684 it. */
685 old_action->ksa_flags &= ~VKI_SA_ONSTACK;
sewardj77e466c2002-04-14 02:29:29 +0000686 /* Restore the SA_RESTART flag to whatever we snaffled. */
687 if (vg_sig_sarestart[param1])
688 old_action->ksa_flags |= VKI_SA_RESTART;
689 else
690 old_action->ksa_flags &= ~VKI_SA_RESTART;
sewardjde4a1d02002-03-22 01:27:54 +0000691 }
692 }
693
694 VG_(ksignal)(VKI_SIGABRT, &VG_(oursignalhandler));
695 goto good;
696
697 good:
sewardj2e93c502002-04-12 11:12:52 +0000698 tst->m_eax = (UInt)0;
sewardjde4a1d02002-03-22 01:27:54 +0000699 return;
700
sewardj0ca2a6b2002-03-29 14:02:34 +0000701 bad_signo:
sewardjde4a1d02002-03-22 01:27:54 +0000702 VG_(message)(Vg_UserMsg,
703 "Warning: bad signal number %d in __NR_sigaction.",
704 param1);
sewardj0ca2a6b2002-03-29 14:02:34 +0000705 VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-VKI_EINVAL);
706 return;
707
708 bad_sigkill:
709 VG_(message)(Vg_UserMsg,
710 "Warning: attempt to set SIGKILL handler in __NR_sigaction.",
711 param1);
712 VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-VKI_EINVAL);
sewardjde4a1d02002-03-22 01:27:54 +0000713 return;
714}
715
716
717/* The kernel handles sigprocmask in the usual way, but we also need
718 to inspect it, so as to spot requests to unblock signals. We then
719 inspect vg_sigpending, which records the current state of signal
720 delivery to the client. The problematic case is when a signal is
721 delivered to the client, in which case the relevant vg_sigpending
722 slot is set to VG_SIGRUNNING. This inhibits further signal
723 deliveries. This mechanism implements the POSIX requirement that a
724 signal is blocked in its own handler.
725
726 If the handler returns normally, the slot is changed back to
727 VG_SIGIDLE, so that further instances of the signal can be
728 delivered. The problem occurs when the handler never returns, but
729 longjmps. POSIX mandates that you then have to do an explicit
730 setprocmask to re-enable the signal. That is what we try and spot
731 here. Although the call is passed to the kernel, we also need to
732 spot unblocked signals whose state is VG_SIGRUNNING, and change it
733 back to VG_SIGIDLE.
734*/
735void VG_(do__NR_sigprocmask) ( Int how, vki_ksigset_t* set )
736{
737 Int i;
738 if (VG_(clo_trace_signals))
739 VG_(message)(Vg_DebugMsg,
740 "vg_do__NR_sigprocmask: how = %d (%s), set = %p",
741 how,
742 how==VKI_SIG_BLOCK ? "SIG_BLOCK" : (
743 how==VKI_SIG_UNBLOCK ? "SIG_UNBLOCK" : (
744 how==VKI_SIG_SETMASK ? "SIG_SETMASK" : "???")),
745 set
746 );
747
748 /* Sometimes this happens. I don't know what it signifies. */
749 if (set == NULL)
750 return;
751
752 /* Not interested in blocking of signals. */
753 if (how == VKI_SIG_BLOCK)
754 return;
755
756 /* Detect and ignore unknown action. */
757 if (how != VKI_SIG_UNBLOCK && how != VKI_SIG_SETMASK) {
758 VG_(message)(Vg_DebugMsg,
759 "sigprocmask: unknown `how' field %d", how);
760 return;
761 }
762
763 for (i = 1; i < VKI_KNSIG; i++) {
764 Bool unblock_me = False;
765 if (how == VKI_SIG_SETMASK) {
766 if (!VG_(ksigismember)(set,i))
767 unblock_me = True;
768 } else { /* how == SIG_UNBLOCK */
769 if (VG_(ksigismember)(set,i))
770 unblock_me = True;
771 }
772 if (unblock_me && VG_(sigpending)[i] == VG_SIGRUNNING) {
773 VG_(sigpending)[i] = VG_SIGIDLE;
774 if (VG_(clo_verbosity) > 1)
775 VG_(message)(Vg_UserMsg,
776 "Warning: unblocking signal %d "
777 "due to sigprocmask", i );
778 }
779 }
780}
781
782
783
784/*--------------------------------------------------------------------*/
785/*--- end vg_signals.c ---*/
786/*--------------------------------------------------------------------*/