blob: 51a2fe06bf1c5dc8a6caaf85138e565c0877d364 [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
sewardjde4a1d02002-03-22 01:27:54 +000013
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 LICENSE.
30*/
31
32
33#include "vg_include.h"
34#include "vg_constants.h"
35#include "vg_unsafe.h"
sewardj54cacf02002-04-12 23:24:59 +000036#include "valgrind.h" /* for VALGRIND_MAGIC_SEQUENCE */
sewardjde4a1d02002-03-22 01:27:54 +000037
38/* ---------------------------------------------------------------------
sewardjde4a1d02002-03-22 01:27:54 +000039 Signal state for this process.
40 ------------------------------------------------------------------ */
41
42/* For each signal, the current action. Is NULL if the client hasn't
43 asked to handle the signal. Consequently, we expect never to
44 receive a signal for which the corresponding handler is NULL. */
45void* VG_(sighandler)[VKI_KNSIG];
46
sewardj77e466c2002-04-14 02:29:29 +000047
sewardjde4a1d02002-03-22 01:27:54 +000048/* For each signal, either:
49 -- VG_SIGIDLE if not pending and not running
50 -- Handler address if pending
51 -- VG_SIGRUNNING if the handler is running and hasn't (returned or
52 unblocked the signal using sigprocmask following a longjmp out
53 of the handler).
54 */
55#define VG_SIGIDLE ((void*)0)
56#define VG_SIGRUNNING ((void*)1)
57
58void* VG_(sigpending)[VKI_KNSIG];
59
sewardj2e93c502002-04-12 11:12:52 +000060
sewardj77e466c2002-04-14 02:29:29 +000061/* For each signal that we have a handler for (ie, for those for which
62 the VG_(sighandler) entry is non-NULL), record whether or not the
63 client asked for syscalls to be restartable (SA_RESTART) if
64 interrupted by this signal. We need to consult this when a signal
65 returns, if it should happen that the signal which we delivered has
66 interrupted a system call. */
67Bool vg_sig_sarestart[VKI_KNSIG];
68
69
sewardj2e93c502002-04-12 11:12:52 +000070/* ---------------------------------------------------------------------
71 Handy utilities to block/restore all host signals.
72 ------------------------------------------------------------------ */
73
74/* Block all host signals, dumping the old mask in *saved_mask. */
75void VG_(block_all_host_signals) ( /* OUT */ vki_ksigset_t* saved_mask )
76{
77 Int ret;
78 vki_ksigset_t block_procmask;
79 VG_(ksigfillset)(&block_procmask);
80 ret = VG_(ksigprocmask)
81 (VKI_SIG_SETMASK, &block_procmask, saved_mask);
82 vg_assert(ret == 0);
83}
84
85/* Restore the blocking mask using the supplied saved one. */
86void VG_(restore_host_signals) ( /* IN */ vki_ksigset_t* saved_mask )
87{
88 Int ret;
89 ret = VG_(ksigprocmask)(VKI_SIG_SETMASK, saved_mask, NULL);
90 vg_assert(ret == 0);
91}
sewardjde4a1d02002-03-22 01:27:54 +000092
93
94/* ---------------------------------------------------------------------
95 The signal simulation proper. A simplified version of what the
96 Linux kernel does.
97 ------------------------------------------------------------------ */
98
99/* A structure in which to save the application's registers
100 during the execution of signal handlers. */
101
102typedef
103 struct {
sewardj2e93c502002-04-12 11:12:52 +0000104 /* These are parameters to the signal handler. */
105 UInt retaddr; /* Sig handler's (bogus) return address */
106 Int sigNo; /* The arg to the sig handler. */
107 Addr psigInfo; /* ptr to siginfo_t; NULL for now. */
108 Addr puContext; /* ptr to ucontext; NULL for now. */
109 /* Sanity check word. */
sewardjde4a1d02002-03-22 01:27:54 +0000110 UInt magicPI;
sewardj2e93c502002-04-12 11:12:52 +0000111 /* Saved processor state. */
sewardjde4a1d02002-03-22 01:27:54 +0000112 UInt fpustate[VG_SIZE_OF_FPUSTATE_W];
113 UInt eax;
114 UInt ecx;
115 UInt edx;
116 UInt ebx;
117 UInt ebp;
118 UInt esp;
119 UInt esi;
120 UInt edi;
121 Addr eip;
122 UInt eflags;
sewardj2e93c502002-04-12 11:12:52 +0000123 /* Scheduler-private stuff: what was the thread's status prior to
124 delivering this signal? */
125 ThreadStatus status;
126 /* Sanity check word. Is the highest-addressed word; do not
127 move!*/
sewardjde4a1d02002-03-22 01:27:54 +0000128 UInt magicE;
129 }
sewardj2e93c502002-04-12 11:12:52 +0000130 VgSigFrame;
sewardjde4a1d02002-03-22 01:27:54 +0000131
132
133
sewardjde4a1d02002-03-22 01:27:54 +0000134/* Set up a stack frame (VgSigContext) for the client's signal
135 handler. This includes the signal number and a bogus return
136 address. */
137static
sewardj2e93c502002-04-12 11:12:52 +0000138void vg_push_signal_frame ( ThreadId tid, int sigNo )
sewardjde4a1d02002-03-22 01:27:54 +0000139{
140 Int i;
sewardj2e93c502002-04-12 11:12:52 +0000141 Addr esp;
142 VgSigFrame* frame;
143 ThreadState* tst;
144
145 tst = VG_(get_thread_state)(tid);
146 esp = tst->m_esp;
147
148 esp -= sizeof(VgSigFrame);
149 frame = (VgSigFrame*)esp;
150 /* Assert that the frame is placed correctly. */
151 vg_assert( (sizeof(VgSigFrame) & 0x3) == 0 );
152 vg_assert( ((Char*)(&frame->magicE)) + sizeof(UInt)
153 == ((Char*)(tst->m_esp)) );
154
155 frame->retaddr = (UInt)(&VG_(signalreturn_bogusRA));
156 frame->sigNo = sigNo;
157 frame->psigInfo = (Addr)NULL;
158 frame->puContext = (Addr)NULL;
159 frame->magicPI = 0x31415927;
160
sewardjde4a1d02002-03-22 01:27:54 +0000161 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj2e93c502002-04-12 11:12:52 +0000162 frame->fpustate[i] = tst->m_fpu[i];
sewardjde4a1d02002-03-22 01:27:54 +0000163
sewardj2e93c502002-04-12 11:12:52 +0000164 frame->eax = tst->m_eax;
165 frame->ecx = tst->m_ecx;
166 frame->edx = tst->m_edx;
167 frame->ebx = tst->m_ebx;
168 frame->ebp = tst->m_ebp;
169 frame->esp = tst->m_esp;
170 frame->esi = tst->m_esi;
171 frame->edi = tst->m_edi;
172 frame->eip = tst->m_eip;
173 frame->eflags = tst->m_eflags;
sewardjde4a1d02002-03-22 01:27:54 +0000174
sewardj2e93c502002-04-12 11:12:52 +0000175 frame->status = tst->status;
sewardjde4a1d02002-03-22 01:27:54 +0000176
sewardj2e93c502002-04-12 11:12:52 +0000177 frame->magicE = 0x27182818;
178
179 /* Set the thread so it will next run the handler. */
180 tst->m_esp = esp;
181 tst->m_eip = (Addr)VG_(sigpending)[sigNo];
182 /* This thread needs to be marked runnable, but we leave that the
183 caller to do. */
sewardjde4a1d02002-03-22 01:27:54 +0000184
185 /* Make sigNo and retaddr fields readable -- at 0(%ESP) and 4(%ESP) */
186 if (VG_(clo_instrument)) {
187 VGM_(make_readable) ( ((Addr)esp)+0 ,4 );
188 VGM_(make_readable) ( ((Addr)esp)+4 ,4 );
189 }
190
sewardjde4a1d02002-03-22 01:27:54 +0000191 /*
192 VG_(printf)("pushed signal frame; %%ESP now = %p, next %%EBP = %p\n",
sewardj2e93c502002-04-12 11:12:52 +0000193 esp, tst->m_eip);
sewardjde4a1d02002-03-22 01:27:54 +0000194 */
195}
196
197
198/* Clear the signal frame created by vg_push_signal_frame, restore the
199 simulated machine state, and return the signal number that the
200 frame was for. */
201static
sewardj2e93c502002-04-12 11:12:52 +0000202Int vg_pop_signal_frame ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000203{
sewardj2e93c502002-04-12 11:12:52 +0000204 Addr esp;
sewardjde4a1d02002-03-22 01:27:54 +0000205 Int sigNo, i;
sewardj2e93c502002-04-12 11:12:52 +0000206 VgSigFrame* frame;
207 ThreadState* tst;
sewardjde4a1d02002-03-22 01:27:54 +0000208
sewardj2e93c502002-04-12 11:12:52 +0000209 tst = VG_(get_thread_state)(tid);
210
sewardj54cacf02002-04-12 23:24:59 +0000211 /* Correctly reestablish the frame base address. */
sewardj2e93c502002-04-12 11:12:52 +0000212 esp = tst->m_esp;
sewardj54cacf02002-04-12 23:24:59 +0000213 frame = (VgSigFrame*)
214 (esp -4 /* because the handler's RET pops the RA */
215 +20 /* because signalreturn_bogusRA pushes 5 words */);
sewardj2e93c502002-04-12 11:12:52 +0000216
217 vg_assert(frame->magicPI == 0x31415927);
218 vg_assert(frame->magicE == 0x27182818);
sewardjde4a1d02002-03-22 01:27:54 +0000219 if (VG_(clo_trace_signals))
220 VG_(message)(Vg_DebugMsg, "vg_pop_signal_frame: valid magic");
221
222 /* restore machine state */
223 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj2e93c502002-04-12 11:12:52 +0000224 tst->m_fpu[i] = frame->fpustate[i];
sewardjde4a1d02002-03-22 01:27:54 +0000225
sewardj2e93c502002-04-12 11:12:52 +0000226 /* Mark the frame structure as nonaccessible. Has to happen
227 _before_ vg_m_state.m_esp is given a new value.
228 handle_esp_assignment reads %ESP from baseBlock, so we park it
229 there first. Re-place the junk there afterwards. */
230 if (VG_(clo_instrument)) {
231 vg_assert(VG_(baseBlock)[VGOFF_(m_esp)] == 0xDEADBEEF);
232 VG_(baseBlock)[VGOFF_(m_esp)] = tst->m_esp;
233 VGM_(handle_esp_assignment) ( frame->esp );
234 VG_(baseBlock)[VGOFF_(m_esp)] = 0xDEADBEEF;
235 }
sewardjde4a1d02002-03-22 01:27:54 +0000236
237 /* Restore machine state from the saved context. */
sewardj2e93c502002-04-12 11:12:52 +0000238 tst->m_eax = frame->eax;
239 tst->m_ecx = frame->ecx;
240 tst->m_edx = frame->edx;
241 tst->m_ebx = frame->ebx;
242 tst->m_ebp = frame->ebp;
243 tst->m_esp = frame->esp;
244 tst->m_esi = frame->esi;
245 tst->m_edi = frame->edi;
246 tst->m_eflags = frame->eflags;
247 tst->m_eip = frame->eip;
248 sigNo = frame->sigNo;
249
250 /* And restore the thread's status to what it was before the signal
251 was delivered. */
252 tst->status = frame->status;
253
sewardjde4a1d02002-03-22 01:27:54 +0000254 return sigNo;
255}
256
257
258/* A handler is returning. Restore the machine state from the stacked
259 VgSigContext and continue with whatever was going on before the
sewardj77e466c2002-04-14 02:29:29 +0000260 handler ran. Returns the SA_RESTART syscall-restartability-status
261 of the delivered signal. */
sewardjde4a1d02002-03-22 01:27:54 +0000262
sewardj77e466c2002-04-14 02:29:29 +0000263Bool VG_(signal_returns) ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000264{
sewardj2e93c502002-04-12 11:12:52 +0000265 Int sigNo;
sewardjde4a1d02002-03-22 01:27:54 +0000266 vki_ksigset_t saved_procmask;
267
268 /* Block host signals ... */
sewardj2e93c502002-04-12 11:12:52 +0000269 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000270
sewardj2e93c502002-04-12 11:12:52 +0000271 /* Pop the signal frame and restore tid's status to what it was
272 before the signal was delivered. */
273 sigNo = vg_pop_signal_frame(tid);
sewardjde4a1d02002-03-22 01:27:54 +0000274
275 /* You would have thought that the following assertion made sense
276 here:
277
278 vg_assert(vg_sigpending[sigNo] == VG_SIGRUNNING);
279
280 Alas, you would be wrong. If a sigprocmask has been intercepted
281 and it unblocks this signal, then vg_sigpending[sigNo] will
282 either be VG_SIGIDLE, or (worse) another instance of it will
283 already have arrived, so that the stored value is that of the
284 handler.
285
286 Note that these anomalies can only occur when a signal handler
287 unblocks its own signal inside itself AND THEN RETURNS anyway
288 (which seems a bizarre thing to do).
289
290 Ho Hum. This seems like a race condition which surely isn't
291 handled correctly. */
292
293 vg_assert(sigNo >= 1 && sigNo < VKI_KNSIG);
294 VG_(sigpending)[sigNo] = VG_SIGIDLE;
295
296 /* Unlock and return. */
sewardj2e93c502002-04-12 11:12:52 +0000297 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000298
sewardj77e466c2002-04-14 02:29:29 +0000299 /* Scheduler now can resume this thread, or perhaps some other.
300 Tell the scheduler whether or not any syscall interrupted by
301 this signal should be restarted, if possible, or no. */
302 return vg_sig_sarestart[sigNo];
sewardjde4a1d02002-03-22 01:27:54 +0000303}
304
305
306/* Deliver all pending signals, by building stack frames for their
sewardj14e03422002-04-24 19:51:31 +0000307 handlers. Return True if any signals were delivered. */
308Bool VG_(deliver_signals) ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000309{
sewardjde4a1d02002-03-22 01:27:54 +0000310 vki_ksigset_t saved_procmask;
sewardj2e93c502002-04-12 11:12:52 +0000311 Int sigNo;
sewardjde4a1d02002-03-22 01:27:54 +0000312 Bool found;
313
314 /* A cheap check. We don't need to have exclusive access
315 to the queue, because in the worst case, vg_oursignalhandler
316 will add signals, causing us to return, thinking there
317 are no signals to deliver, when in fact there are some.
318 A subsequent call here will handle the signal(s) we missed.
319 */
320 found = False;
321 for (sigNo = 1; sigNo < VKI_KNSIG; sigNo++)
322 if (VG_(sigpending)[sigNo] != VG_SIGIDLE &&
323 VG_(sigpending)[sigNo] != VG_SIGRUNNING) found = True;
324
sewardj14e03422002-04-24 19:51:31 +0000325 if (!found) return False;
sewardjde4a1d02002-03-22 01:27:54 +0000326
327 /* Now we have to do it properly. Get exclusive access by
328 blocking all the host's signals. That means vg_oursignalhandler
329 can't run whilst we are messing with stuff.
330 */
sewardj2e93c502002-04-12 11:12:52 +0000331 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000332
sewardj2e93c502002-04-12 11:12:52 +0000333 /* Look for signals to deliver ... */
sewardjde4a1d02002-03-22 01:27:54 +0000334 for (sigNo = 1; sigNo < VKI_KNSIG; sigNo++) {
335 if (VG_(sigpending)[sigNo] == VG_SIGIDLE ||
336 VG_(sigpending)[sigNo] == VG_SIGRUNNING) continue;
337
338 if (VG_(clo_trace_signals))
339 VG_(message)(Vg_DebugMsg,"delivering signal %d", sigNo );
340
341 /* Create a signal delivery frame, and set the client's %ESP and
342 %EIP so that when execution continues, we will enter the
343 signal handler with the frame on top of the client's stack,
344 as it expects. */
sewardj2e93c502002-04-12 11:12:52 +0000345 vg_push_signal_frame ( tid, sigNo );
346 VG_(get_thread_state)(tid)->status = VgTs_Runnable;
347
sewardjde4a1d02002-03-22 01:27:54 +0000348 /* Signify that the signal has been delivered. */
349 VG_(sigpending)[sigNo] = VG_SIGRUNNING;
350 }
351
352 /* Unlock and return. */
sewardj2e93c502002-04-12 11:12:52 +0000353 VG_(restore_host_signals)( &saved_procmask );
sewardj14e03422002-04-24 19:51:31 +0000354 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000355}
356
357
sewardjde4a1d02002-03-22 01:27:54 +0000358/* Receive a signal from the host, and either discard it or park it in
359 the queue of pending signals. All other signals will be blocked
360 when this handler runs. Runs with all host signals blocked, so as
361 to have mutual exclusion when adding stuff to the queue. */
362
363static void VG_(oursignalhandler) ( Int sigNo )
364{
sewardj2e93c502002-04-12 11:12:52 +0000365 Int dummy_local;
sewardjde4a1d02002-03-22 01:27:54 +0000366 vki_ksigset_t saved_procmask;
367
sewardj7a61d912002-04-25 01:27:35 +0000368 /*
369 if (sigNo == VKI_SIGUSR1) {
370 VG_(printf)("YOWZA! SIGUSR1\n\n");
371 VG_(clo_trace_pthread_level) = 2;
372 VG_(clo_trace_sched) = True;
373 VG_(clo_trace_syscalls) = True;
374 VG_(clo_trace_signals) = True;
375 return;
376 }
377 */
378
sewardjde4a1d02002-03-22 01:27:54 +0000379 if (VG_(clo_trace_signals)) {
380 VG_(start_msg)(Vg_DebugMsg);
381 VG_(add_to_msg)("signal %d arrived ... ", sigNo );
382 }
383 vg_assert(sigNo >= 1 && sigNo < VKI_KNSIG);
384
385 /* Sanity check. Ensure we're really running on the signal stack
386 we asked for. */
387 if ( !(
sewardj2e93c502002-04-12 11:12:52 +0000388 ((Char*)(&(VG_(sigstack)[0])) <= (Char*)(&dummy_local))
sewardjde4a1d02002-03-22 01:27:54 +0000389 &&
sewardj2e93c502002-04-12 11:12:52 +0000390 ((Char*)(&dummy_local) < (Char*)(&(VG_(sigstack)[10000])))
sewardjde4a1d02002-03-22 01:27:54 +0000391 )
392 ) {
sewardj2e93c502002-04-12 11:12:52 +0000393 VG_(message)(Vg_DebugMsg,
394 "FATAL: signal delivered on the wrong stack?!");
395 VG_(message)(Vg_DebugMsg,
396 "A possible workaround follows. Please tell me");
397 VG_(message)(Vg_DebugMsg,
398 "(jseward@acm.org) if the suggested workaround doesn't help.");
sewardjde4a1d02002-03-22 01:27:54 +0000399 VG_(unimplemented)
sewardj2e93c502002-04-12 11:12:52 +0000400 ("support for progs compiled with -p/-pg; "
401 "rebuild your prog without -p/-pg");
sewardjde4a1d02002-03-22 01:27:54 +0000402 }
403
sewardj2e93c502002-04-12 11:12:52 +0000404 vg_assert((Char*)(&(VG_(sigstack)[0])) <= (Char*)(&dummy_local));
405 vg_assert((Char*)(&dummy_local) < (Char*)(&(VG_(sigstack)[10000])));
sewardjde4a1d02002-03-22 01:27:54 +0000406
sewardj2e93c502002-04-12 11:12:52 +0000407 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000408
409 if (VG_(sighandler)[sigNo] == NULL) {
410 if (VG_(clo_trace_signals)) {
411 VG_(add_to_msg)("unexpected!");
412 VG_(end_msg)();
413 }
sewardj2e93c502002-04-12 11:12:52 +0000414 /* Note: we panic with all signals blocked here. Don't think
415 that matters. */
sewardjde4a1d02002-03-22 01:27:54 +0000416 VG_(panic)("vg_oursignalhandler: unexpected signal");
417 }
418
419 /* Decide what to do with it. */
420 if (VG_(sigpending)[sigNo] == VG_SIGRUNNING) {
421 /* Already running; ignore it. */
422 if (VG_(clo_trace_signals)) {
423 VG_(add_to_msg)("already running; discarded" );
424 VG_(end_msg)();
425 }
426 }
427 else
428 if (VG_(sigpending)[sigNo] != VG_SIGRUNNING &&
429 VG_(sigpending)[sigNo] != VG_SIGIDLE) {
430 /* Not running and not idle == pending; ignore it. */
431 if (VG_(clo_trace_signals)) {
432 VG_(add_to_msg)("already pending; discarded" );
433 VG_(end_msg)();
434 }
435 }
436 else {
sewardj2e93c502002-04-12 11:12:52 +0000437 /* Ok, we'd better deliver it to the client. */
sewardjde4a1d02002-03-22 01:27:54 +0000438 vg_assert(VG_(sigpending)[sigNo] == VG_SIGIDLE);
sewardj2e93c502002-04-12 11:12:52 +0000439 /* Queue it up for delivery at some point in the future. */
440 VG_(sigpending)[sigNo] = VG_(sighandler)[sigNo];
441 if (VG_(clo_trace_signals)) {
442 VG_(add_to_msg)("queued" );
443 VG_(end_msg)();
sewardjde4a1d02002-03-22 01:27:54 +0000444 }
445 }
446
sewardj2e93c502002-04-12 11:12:52 +0000447 /* We've finished messing with the queue, so re-enable host
448 signals. */
449 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000450
sewardjd1e86492002-04-24 21:44:17 +0000451 if ((sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS
452 || sigNo == VKI_SIGFPE || sigNo == VKI_SIGILL)) {
sewardj2e93c502002-04-12 11:12:52 +0000453 /* Can't continue; must longjmp back to the scheduler and thus
454 enter the sighandler immediately. */
sewardjde4a1d02002-03-22 01:27:54 +0000455 VG_(longjmpd_on_signal) = sigNo;
sewardj2e93c502002-04-12 11:12:52 +0000456 __builtin_longjmp(VG_(scheduler_jmpbuf),1);
sewardjde4a1d02002-03-22 01:27:54 +0000457 }
458}
459
460
461/* The outer insn loop calls here to reenable a host signal if
462 vg_oursighandler longjmp'd.
463*/
464void VG_(unblock_host_signal) ( Int sigNo )
465{
466 Int ret;
467 vki_ksigset_t set;
468 VG_(ksigemptyset)(&set);
469 ret = VG_(ksigaddset)(&set,sigNo);
470 vg_assert(ret == 0);
471 ret = VG_(ksigprocmask)(VKI_SIG_UNBLOCK,&set,NULL);
472 vg_assert(ret == 0);
473}
474
475
476static __attribute((unused))
477void pp_vg_ksigaction ( vki_ksigaction* sa )
478{
479 Int i;
480 VG_(printf)("vg_ksigaction: handler %p, flags 0x%x, restorer %p\n",
sewardj9a199dc2002-04-14 13:01:38 +0000481 sa->ksa_handler, (UInt)sa->ksa_flags, sa->ksa_restorer);
sewardjde4a1d02002-03-22 01:27:54 +0000482 VG_(printf)("vg_ksigaction: { ");
483 for (i = 1; i < VKI_KNSIG; i++)
484 if (VG_(ksigismember(&(sa->ksa_mask),i)))
485 VG_(printf)("%d ", i);
486 VG_(printf)("}\n");
487}
488
489
490/* Copy the process' real signal state to the sim state. Whilst
491 doing this, block all real signals.
492*/
493void VG_(sigstartup_actions) ( void )
494{
495 Int i, ret;
496
sewardjde4a1d02002-03-22 01:27:54 +0000497 vki_ksigset_t saved_procmask;
498 vki_kstack_t altstack_info;
499 vki_ksigaction sa;
500
sewardj2e93c502002-04-12 11:12:52 +0000501 /* VG_(printf)("SIGSTARTUP\n"); */
sewardjde4a1d02002-03-22 01:27:54 +0000502 /* Block all signals.
503 saved_procmask remembers the previous mask. */
sewardj2e93c502002-04-12 11:12:52 +0000504 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000505
506 /* Register an alternative stack for our own signal handler to run
507 on. */
508 altstack_info.ss_sp = &(VG_(sigstack)[0]);
509 altstack_info.ss_size = 10000 * sizeof(UInt);
510 altstack_info.ss_flags = 0;
511 ret = VG_(ksigaltstack)(&altstack_info, NULL);
512 if (ret != 0) {
513 VG_(panic)(
514 "vg_sigstartup_actions: couldn't install alternative sigstack");
515 }
516 if (VG_(clo_trace_signals)) {
517 VG_(message)(Vg_DebugExtraMsg,
518 "vg_sigstartup_actions: sigstack installed ok");
519 }
520
521 /* Set initial state for the signal simulation. */
sewardj77e466c2002-04-14 02:29:29 +0000522 for (i = 1; i < VKI_KNSIG; i++) {
523 VG_(sighandler)[i] = NULL;
524 VG_(sigpending)[i] = NULL;
525 vg_sig_sarestart[i] = True; /* An easy default */
526 }
sewardjde4a1d02002-03-22 01:27:54 +0000527
528 for (i = 1; i < VKI_KNSIG; i++) {
529
530 /* Get the old host action */
531 ret = VG_(ksigaction)(i, NULL, &sa);
532 vg_assert(ret == 0);
533
534 /* If there's already a handler set, record it, then route the
535 signal through to our handler. */
536 if (sa.ksa_handler != VKI_SIG_IGN && sa.ksa_handler != VKI_SIG_DFL) {
537 if (VG_(clo_trace_signals))
538 VG_(printf)("snaffling handler 0x%x for signal %d\n",
539 (Addr)(sa.ksa_handler), i );
540 if ((sa.ksa_flags & VKI_SA_ONSTACK) != 0)
541 VG_(unimplemented)
542 ("signals on an alternative stack (SA_ONSTACK)");
sewardj77e466c2002-04-14 02:29:29 +0000543
544 VG_(sighandler)[i] = sa.ksa_handler;
sewardjde4a1d02002-03-22 01:27:54 +0000545 sa.ksa_handler = &VG_(oursignalhandler);
sewardj77e466c2002-04-14 02:29:29 +0000546 /* Save the restart status, then set it to restartable. */
547 vg_sig_sarestart[i]
548 = (sa.ksa_flags & VKI_SA_RESTART) ? True : False;
549 sa.ksa_flags |= VKI_SA_RESTART;
550
sewardjde4a1d02002-03-22 01:27:54 +0000551 ret = VG_(ksigaction)(i, &sa, NULL);
552 vg_assert(ret == 0);
553 }
554 }
555
sewardj7a61d912002-04-25 01:27:35 +0000556 /* DEBUGGING HACK */
557 /* VG_(ksignal)(VKI_SIGUSR1, &VG_(oursignalhandler)); */
558
sewardjde4a1d02002-03-22 01:27:54 +0000559 /* Finally, restore the blocking mask. */
sewardj2e93c502002-04-12 11:12:52 +0000560 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000561}
562
563
564/* Copy the process' sim signal state to the real state,
565 for when we transfer from the simulated to real CPU.
566 PROBLEM: what if we're running a signal handler when we
567 get here? Hmm.
568 I guess we wind up in vg_signalreturn_bogusRA, *or* the
569 handler has done/will do a longjmp, in which case we're ok.
570
571 It is important (see vg_startup.S) that this proc does not
572 change the state of the real FPU, since it is called when
573 running the program on the real CPU.
574*/
575void VG_(sigshutdown_actions) ( void )
576{
577 Int i, ret;
578
sewardjde4a1d02002-03-22 01:27:54 +0000579 vki_ksigset_t saved_procmask;
580 vki_ksigaction sa;
581
sewardj2e93c502002-04-12 11:12:52 +0000582 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000583
584 /* copy the sim signal actions to the real ones. */
sewardj77e466c2002-04-14 02:29:29 +0000585 /* Hmm, this isn't accurate. Doesn't properly restore the
586 SA_RESTART flag nor SA_ONSTACK. */
sewardjde4a1d02002-03-22 01:27:54 +0000587 for (i = 1; i < VKI_KNSIG; i++) {
588 if (i == VKI_SIGKILL || i == VKI_SIGSTOP) continue;
589 if (VG_(sighandler)[i] == NULL) continue;
590 ret = VG_(ksigaction)(i, NULL, &sa);
591 vg_assert(ret == 0);
592 sa.ksa_handler = VG_(sighandler)[i];
593 ret = VG_(ksigaction)(i, &sa, NULL);
594 }
595
sewardj2e93c502002-04-12 11:12:52 +0000596 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000597}
598
599
600/* ---------------------------------------------------------------------
601 Handle signal-related syscalls from the simulatee.
602 ------------------------------------------------------------------ */
603
604/* Do more error checking? */
sewardj2e93c502002-04-12 11:12:52 +0000605void VG_(do__NR_sigaction) ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000606{
607 UInt res;
608 void* our_old_handler;
609 vki_ksigaction* new_action;
610 vki_ksigaction* old_action;
sewardj2e93c502002-04-12 11:12:52 +0000611 ThreadState* tst = VG_(get_thread_state)( tid );
612 UInt param1 = tst->m_ebx; /* int sigNo */
613 UInt param2 = tst->m_ecx; /* k_sigaction* new_action */
614 UInt param3 = tst->m_edx; /* k_sigaction* old_action */
sewardjde4a1d02002-03-22 01:27:54 +0000615 new_action = (vki_ksigaction*)param2;
616 old_action = (vki_ksigaction*)param3;
617
618 if (VG_(clo_trace_signals))
619 VG_(message)(Vg_DebugExtraMsg,
620 "__NR_sigaction: sigNo %d, "
621 "new 0x%x, old 0x%x, new flags 0x%x",
622 param1,(UInt)new_action,(UInt)old_action,
623 (UInt)(new_action ? new_action->ksa_flags : 0) );
624 /* VG_(ppSigProcMask)(); */
625
sewardj0ca2a6b2002-03-29 14:02:34 +0000626 /* Rule out various error conditions. The aim is to ensure that if
627 the call is passed to the kernel it will definitely succeed. */
628
629 /* Reject out-of-range signal numbers. */
630 if (param1 < 1 || param1 >= VKI_KNSIG) goto bad_signo;
631
632 /* Reject attempts to set a handler (or set ignore) for SIGKILL. */
633 if ( (param1 == VKI_SIGKILL || param1 == VKI_SIGSTOP)
634 && new_action
635 && new_action->ksa_handler != VKI_SIG_DFL)
sewardjcfdf27c2002-04-24 21:25:46 +0000636 goto bad_sigkill_or_sigstop;
sewardjde4a1d02002-03-22 01:27:54 +0000637
638 our_old_handler = VG_(sighandler)[param1];
639 /* VG_(printf)("old handler = 0x%x\n", our_old_handler); */
640 /* If a new handler has been specified, mess with its handler. */
641 if (new_action) {
642 if (new_action->ksa_handler == VKI_SIG_IGN ||
643 new_action->ksa_handler == VKI_SIG_DFL) {
644 VG_(sighandler)[param1] = NULL;
645 VG_(sigpending)[param1] = NULL;
646 /* Dangerous! Could lose signals like this. */
647 } else {
648 /* VG_(printf)("new handler = 0x%x\n", new_action->ksa_handler); */
649 /* The client isn't allowed to use an alternative signal
650 stack. We, however, must. */
651 if ((new_action->ksa_flags & VKI_SA_ONSTACK) != 0)
652 VG_(unimplemented)
653 ("signals on an alternative stack (SA_ONSTACK)");
654 new_action->ksa_flags |= VKI_SA_ONSTACK;
655 VG_(sighandler)[param1] = new_action->ksa_handler;
sewardj77e466c2002-04-14 02:29:29 +0000656 vg_sig_sarestart[param1]
657 = (new_action->ksa_flags & VKI_SA_RESTART) ? True : False;
658 new_action->ksa_flags |= VKI_SA_RESTART;
sewardjde4a1d02002-03-22 01:27:54 +0000659 new_action->ksa_handler = &VG_(oursignalhandler);
660 }
661 }
662
sewardj2e93c502002-04-12 11:12:52 +0000663 KERNEL_DO_SYSCALL(tid,res);
sewardjde4a1d02002-03-22 01:27:54 +0000664 /* VG_(printf)("RES = %d\n", res); */
sewardj0ca2a6b2002-03-29 14:02:34 +0000665
sewardjde4a1d02002-03-22 01:27:54 +0000666 /* If the client asks for the old handler, maintain our fiction
667 by stuffing in the handler it thought it asked for ... */
668 if (old_action) {
669 if (old_action->ksa_handler == VKI_SIG_IGN ||
670 old_action->ksa_handler == VKI_SIG_DFL) {
671 /* No old action; we should have a NULL handler. */
672 vg_assert(our_old_handler == NULL);
673 } else {
674 /* There's a handler. */
sewardjcfdf27c2002-04-24 21:25:46 +0000675 if (param1 != VKI_SIGKILL && param1 != VKI_SIGSTOP) {
sewardjde4a1d02002-03-22 01:27:54 +0000676 vg_assert(old_action->ksa_handler == &VG_(oursignalhandler));
677 vg_assert((old_action->ksa_flags & VKI_SA_ONSTACK) != 0);
678 }
679 old_action->ksa_handler = our_old_handler;
680 /* Since the client is not allowed to ask for an alternative
681 sig stack, unset the bit for anything we pass back to
682 it. */
683 old_action->ksa_flags &= ~VKI_SA_ONSTACK;
sewardj77e466c2002-04-14 02:29:29 +0000684 /* Restore the SA_RESTART flag to whatever we snaffled. */
685 if (vg_sig_sarestart[param1])
686 old_action->ksa_flags |= VKI_SA_RESTART;
687 else
688 old_action->ksa_flags &= ~VKI_SA_RESTART;
sewardjde4a1d02002-03-22 01:27:54 +0000689 }
690 }
sewardjde4a1d02002-03-22 01:27:54 +0000691 goto good;
692
693 good:
sewardj2e93c502002-04-12 11:12:52 +0000694 tst->m_eax = (UInt)0;
sewardjde4a1d02002-03-22 01:27:54 +0000695 return;
696
sewardj0ca2a6b2002-03-29 14:02:34 +0000697 bad_signo:
sewardjde4a1d02002-03-22 01:27:54 +0000698 VG_(message)(Vg_UserMsg,
699 "Warning: bad signal number %d in __NR_sigaction.",
700 param1);
sewardj0ca2a6b2002-03-29 14:02:34 +0000701 VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-VKI_EINVAL);
702 return;
703
sewardjcfdf27c2002-04-24 21:25:46 +0000704 bad_sigkill_or_sigstop:
sewardj0ca2a6b2002-03-29 14:02:34 +0000705 VG_(message)(Vg_UserMsg,
sewardjcfdf27c2002-04-24 21:25:46 +0000706 "Warning: attempt to set %s handler in __NR_sigaction.",
707 param1 == VKI_SIGKILL ? "SIGKILL" : "SIGSTOP" );
708
sewardj0ca2a6b2002-03-29 14:02:34 +0000709 VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-VKI_EINVAL);
sewardjde4a1d02002-03-22 01:27:54 +0000710 return;
711}
712
713
714/* The kernel handles sigprocmask in the usual way, but we also need
715 to inspect it, so as to spot requests to unblock signals. We then
716 inspect vg_sigpending, which records the current state of signal
717 delivery to the client. The problematic case is when a signal is
718 delivered to the client, in which case the relevant vg_sigpending
719 slot is set to VG_SIGRUNNING. This inhibits further signal
720 deliveries. This mechanism implements the POSIX requirement that a
721 signal is blocked in its own handler.
722
723 If the handler returns normally, the slot is changed back to
724 VG_SIGIDLE, so that further instances of the signal can be
725 delivered. The problem occurs when the handler never returns, but
726 longjmps. POSIX mandates that you then have to do an explicit
727 setprocmask to re-enable the signal. That is what we try and spot
728 here. Although the call is passed to the kernel, we also need to
729 spot unblocked signals whose state is VG_SIGRUNNING, and change it
730 back to VG_SIGIDLE.
731*/
732void VG_(do__NR_sigprocmask) ( Int how, vki_ksigset_t* set )
733{
734 Int i;
735 if (VG_(clo_trace_signals))
736 VG_(message)(Vg_DebugMsg,
737 "vg_do__NR_sigprocmask: how = %d (%s), set = %p",
738 how,
739 how==VKI_SIG_BLOCK ? "SIG_BLOCK" : (
740 how==VKI_SIG_UNBLOCK ? "SIG_UNBLOCK" : (
741 how==VKI_SIG_SETMASK ? "SIG_SETMASK" : "???")),
742 set
743 );
744
745 /* Sometimes this happens. I don't know what it signifies. */
746 if (set == NULL)
747 return;
748
749 /* Not interested in blocking of signals. */
750 if (how == VKI_SIG_BLOCK)
751 return;
752
753 /* Detect and ignore unknown action. */
754 if (how != VKI_SIG_UNBLOCK && how != VKI_SIG_SETMASK) {
755 VG_(message)(Vg_DebugMsg,
756 "sigprocmask: unknown `how' field %d", how);
757 return;
758 }
759
760 for (i = 1; i < VKI_KNSIG; i++) {
761 Bool unblock_me = False;
762 if (how == VKI_SIG_SETMASK) {
763 if (!VG_(ksigismember)(set,i))
764 unblock_me = True;
765 } else { /* how == SIG_UNBLOCK */
766 if (VG_(ksigismember)(set,i))
767 unblock_me = True;
768 }
769 if (unblock_me && VG_(sigpending)[i] == VG_SIGRUNNING) {
770 VG_(sigpending)[i] = VG_SIGIDLE;
771 if (VG_(clo_verbosity) > 1)
772 VG_(message)(Vg_UserMsg,
773 "Warning: unblocking signal %d "
774 "due to sigprocmask", i );
775 }
776 }
777}
778
779
780
781/*--------------------------------------------------------------------*/
782/*--- end vg_signals.c ---*/
783/*--------------------------------------------------------------------*/