blob: fd89bde39836524418aa5cae7882b9155d457713 [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
307 handlers. */
sewardj2e93c502002-04-12 11:12:52 +0000308void 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
325 if (!found) return;
326
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 );
sewardjde4a1d02002-03-22 01:27:54 +0000354 return;
355}
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
368 if (VG_(clo_trace_signals)) {
369 VG_(start_msg)(Vg_DebugMsg);
370 VG_(add_to_msg)("signal %d arrived ... ", sigNo );
371 }
372 vg_assert(sigNo >= 1 && sigNo < VKI_KNSIG);
373
374 /* Sanity check. Ensure we're really running on the signal stack
375 we asked for. */
376 if ( !(
sewardj2e93c502002-04-12 11:12:52 +0000377 ((Char*)(&(VG_(sigstack)[0])) <= (Char*)(&dummy_local))
sewardjde4a1d02002-03-22 01:27:54 +0000378 &&
sewardj2e93c502002-04-12 11:12:52 +0000379 ((Char*)(&dummy_local) < (Char*)(&(VG_(sigstack)[10000])))
sewardjde4a1d02002-03-22 01:27:54 +0000380 )
381 ) {
sewardj2e93c502002-04-12 11:12:52 +0000382 VG_(message)(Vg_DebugMsg,
383 "FATAL: signal delivered on the wrong stack?!");
384 VG_(message)(Vg_DebugMsg,
385 "A possible workaround follows. Please tell me");
386 VG_(message)(Vg_DebugMsg,
387 "(jseward@acm.org) if the suggested workaround doesn't help.");
sewardjde4a1d02002-03-22 01:27:54 +0000388 VG_(unimplemented)
sewardj2e93c502002-04-12 11:12:52 +0000389 ("support for progs compiled with -p/-pg; "
390 "rebuild your prog without -p/-pg");
sewardjde4a1d02002-03-22 01:27:54 +0000391 }
392
sewardj2e93c502002-04-12 11:12:52 +0000393 vg_assert((Char*)(&(VG_(sigstack)[0])) <= (Char*)(&dummy_local));
394 vg_assert((Char*)(&dummy_local) < (Char*)(&(VG_(sigstack)[10000])));
sewardjde4a1d02002-03-22 01:27:54 +0000395
396 if (sigNo == VKI_SIGABRT && VG_(sighandler)[sigNo] == NULL) {
397 /* We get here if SIGABRT is delivered and the client hasn't
398 asked to catch it. The aim is to exit in a controlled
399 manner. */
400 if (VG_(clo_trace_signals)) {
401 VG_(add_to_msg)("catching SIGABRT");
402 VG_(end_msg)();
403 }
404 VG_(ksignal)(VKI_SIGABRT, VKI_SIG_DFL);
sewardjde4a1d02002-03-22 01:27:54 +0000405 VG_(longjmpd_on_signal) = VKI_SIGABRT;
sewardj2e93c502002-04-12 11:12:52 +0000406 __builtin_longjmp(VG_(scheduler_jmpbuf),1);
sewardjde4a1d02002-03-22 01:27:54 +0000407 }
408
sewardj2e93c502002-04-12 11:12:52 +0000409 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000410
411 if (VG_(sighandler)[sigNo] == NULL) {
412 if (VG_(clo_trace_signals)) {
413 VG_(add_to_msg)("unexpected!");
414 VG_(end_msg)();
415 }
sewardj2e93c502002-04-12 11:12:52 +0000416 /* Note: we panic with all signals blocked here. Don't think
417 that matters. */
sewardjde4a1d02002-03-22 01:27:54 +0000418 VG_(panic)("vg_oursignalhandler: unexpected signal");
419 }
420
421 /* Decide what to do with it. */
422 if (VG_(sigpending)[sigNo] == VG_SIGRUNNING) {
423 /* Already running; ignore it. */
424 if (VG_(clo_trace_signals)) {
425 VG_(add_to_msg)("already running; discarded" );
426 VG_(end_msg)();
427 }
428 }
429 else
430 if (VG_(sigpending)[sigNo] != VG_SIGRUNNING &&
431 VG_(sigpending)[sigNo] != VG_SIGIDLE) {
432 /* Not running and not idle == pending; ignore it. */
433 if (VG_(clo_trace_signals)) {
434 VG_(add_to_msg)("already pending; discarded" );
435 VG_(end_msg)();
436 }
437 }
438 else {
sewardj2e93c502002-04-12 11:12:52 +0000439 /* Ok, we'd better deliver it to the client. */
sewardjde4a1d02002-03-22 01:27:54 +0000440 vg_assert(VG_(sigpending)[sigNo] == VG_SIGIDLE);
sewardj2e93c502002-04-12 11:12:52 +0000441 /* Queue it up for delivery at some point in the future. */
442 VG_(sigpending)[sigNo] = VG_(sighandler)[sigNo];
443 if (VG_(clo_trace_signals)) {
444 VG_(add_to_msg)("queued" );
445 VG_(end_msg)();
sewardjde4a1d02002-03-22 01:27:54 +0000446 }
447 }
448
sewardj2e93c502002-04-12 11:12:52 +0000449 /* We've finished messing with the queue, so re-enable host
450 signals. */
451 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000452
sewardjde4a1d02002-03-22 01:27:54 +0000453 if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS
454 || sigNo == VKI_SIGFPE || sigNo == VKI_SIGILL) {
sewardj2e93c502002-04-12 11:12:52 +0000455 /* Can't continue; must longjmp back to the scheduler and thus
456 enter the sighandler immediately. */
sewardjde4a1d02002-03-22 01:27:54 +0000457 VG_(longjmpd_on_signal) = sigNo;
sewardj2e93c502002-04-12 11:12:52 +0000458 __builtin_longjmp(VG_(scheduler_jmpbuf),1);
sewardjde4a1d02002-03-22 01:27:54 +0000459 }
460}
461
462
463/* The outer insn loop calls here to reenable a host signal if
464 vg_oursighandler longjmp'd.
465*/
466void VG_(unblock_host_signal) ( Int sigNo )
467{
468 Int ret;
469 vki_ksigset_t set;
470 VG_(ksigemptyset)(&set);
471 ret = VG_(ksigaddset)(&set,sigNo);
472 vg_assert(ret == 0);
473 ret = VG_(ksigprocmask)(VKI_SIG_UNBLOCK,&set,NULL);
474 vg_assert(ret == 0);
475}
476
477
478static __attribute((unused))
479void pp_vg_ksigaction ( vki_ksigaction* sa )
480{
481 Int i;
482 VG_(printf)("vg_ksigaction: handler %p, flags 0x%x, restorer %p\n",
sewardj9a199dc2002-04-14 13:01:38 +0000483 sa->ksa_handler, (UInt)sa->ksa_flags, sa->ksa_restorer);
sewardjde4a1d02002-03-22 01:27:54 +0000484 VG_(printf)("vg_ksigaction: { ");
485 for (i = 1; i < VKI_KNSIG; i++)
486 if (VG_(ksigismember(&(sa->ksa_mask),i)))
487 VG_(printf)("%d ", i);
488 VG_(printf)("}\n");
489}
490
491
492/* Copy the process' real signal state to the sim state. Whilst
493 doing this, block all real signals.
494*/
495void VG_(sigstartup_actions) ( void )
496{
497 Int i, ret;
498
sewardjde4a1d02002-03-22 01:27:54 +0000499 vki_ksigset_t saved_procmask;
500 vki_kstack_t altstack_info;
501 vki_ksigaction sa;
502
sewardj2e93c502002-04-12 11:12:52 +0000503 /* VG_(printf)("SIGSTARTUP\n"); */
sewardjde4a1d02002-03-22 01:27:54 +0000504 /* Block all signals.
505 saved_procmask remembers the previous mask. */
sewardj2e93c502002-04-12 11:12:52 +0000506 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000507
508 /* Register an alternative stack for our own signal handler to run
509 on. */
510 altstack_info.ss_sp = &(VG_(sigstack)[0]);
511 altstack_info.ss_size = 10000 * sizeof(UInt);
512 altstack_info.ss_flags = 0;
513 ret = VG_(ksigaltstack)(&altstack_info, NULL);
514 if (ret != 0) {
515 VG_(panic)(
516 "vg_sigstartup_actions: couldn't install alternative sigstack");
517 }
518 if (VG_(clo_trace_signals)) {
519 VG_(message)(Vg_DebugExtraMsg,
520 "vg_sigstartup_actions: sigstack installed ok");
521 }
522
523 /* Set initial state for the signal simulation. */
sewardj77e466c2002-04-14 02:29:29 +0000524 for (i = 1; i < VKI_KNSIG; i++) {
525 VG_(sighandler)[i] = NULL;
526 VG_(sigpending)[i] = NULL;
527 vg_sig_sarestart[i] = True; /* An easy default */
528 }
sewardjde4a1d02002-03-22 01:27:54 +0000529
530 for (i = 1; i < VKI_KNSIG; i++) {
531
532 /* Get the old host action */
533 ret = VG_(ksigaction)(i, NULL, &sa);
534 vg_assert(ret == 0);
535
536 /* If there's already a handler set, record it, then route the
537 signal through to our handler. */
538 if (sa.ksa_handler != VKI_SIG_IGN && sa.ksa_handler != VKI_SIG_DFL) {
539 if (VG_(clo_trace_signals))
540 VG_(printf)("snaffling handler 0x%x for signal %d\n",
541 (Addr)(sa.ksa_handler), i );
542 if ((sa.ksa_flags & VKI_SA_ONSTACK) != 0)
543 VG_(unimplemented)
544 ("signals on an alternative stack (SA_ONSTACK)");
sewardj77e466c2002-04-14 02:29:29 +0000545
546 VG_(sighandler)[i] = sa.ksa_handler;
sewardjde4a1d02002-03-22 01:27:54 +0000547 sa.ksa_handler = &VG_(oursignalhandler);
sewardj77e466c2002-04-14 02:29:29 +0000548 /* Save the restart status, then set it to restartable. */
549 vg_sig_sarestart[i]
550 = (sa.ksa_flags & VKI_SA_RESTART) ? True : False;
551 sa.ksa_flags |= VKI_SA_RESTART;
552
sewardjde4a1d02002-03-22 01:27:54 +0000553 ret = VG_(ksigaction)(i, &sa, NULL);
554 vg_assert(ret == 0);
555 }
556 }
557
558 VG_(ksignal)(VKI_SIGABRT, &VG_(oursignalhandler));
559
560 /* Finally, restore the blocking mask. */
sewardj2e93c502002-04-12 11:12:52 +0000561 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000562}
563
564
565/* Copy the process' sim signal state to the real state,
566 for when we transfer from the simulated to real CPU.
567 PROBLEM: what if we're running a signal handler when we
568 get here? Hmm.
569 I guess we wind up in vg_signalreturn_bogusRA, *or* the
570 handler has done/will do a longjmp, in which case we're ok.
571
572 It is important (see vg_startup.S) that this proc does not
573 change the state of the real FPU, since it is called when
574 running the program on the real CPU.
575*/
576void VG_(sigshutdown_actions) ( void )
577{
578 Int i, ret;
579
sewardjde4a1d02002-03-22 01:27:54 +0000580 vki_ksigset_t saved_procmask;
581 vki_ksigaction sa;
582
sewardj2e93c502002-04-12 11:12:52 +0000583 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000584
585 /* copy the sim signal actions to the real ones. */
sewardj77e466c2002-04-14 02:29:29 +0000586 /* Hmm, this isn't accurate. Doesn't properly restore the
587 SA_RESTART flag nor SA_ONSTACK. */
sewardjde4a1d02002-03-22 01:27:54 +0000588 for (i = 1; i < VKI_KNSIG; i++) {
589 if (i == VKI_SIGKILL || i == VKI_SIGSTOP) continue;
590 if (VG_(sighandler)[i] == NULL) continue;
591 ret = VG_(ksigaction)(i, NULL, &sa);
592 vg_assert(ret == 0);
593 sa.ksa_handler = VG_(sighandler)[i];
594 ret = VG_(ksigaction)(i, &sa, NULL);
595 }
596
sewardj2e93c502002-04-12 11:12:52 +0000597 VG_(restore_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +0000598}
599
600
601/* ---------------------------------------------------------------------
602 Handle signal-related syscalls from the simulatee.
603 ------------------------------------------------------------------ */
604
605/* Do more error checking? */
sewardj2e93c502002-04-12 11:12:52 +0000606void VG_(do__NR_sigaction) ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000607{
608 UInt res;
609 void* our_old_handler;
610 vki_ksigaction* new_action;
611 vki_ksigaction* old_action;
sewardj2e93c502002-04-12 11:12:52 +0000612 ThreadState* tst = VG_(get_thread_state)( tid );
613 UInt param1 = tst->m_ebx; /* int sigNo */
614 UInt param2 = tst->m_ecx; /* k_sigaction* new_action */
615 UInt param3 = tst->m_edx; /* k_sigaction* old_action */
sewardjde4a1d02002-03-22 01:27:54 +0000616 new_action = (vki_ksigaction*)param2;
617 old_action = (vki_ksigaction*)param3;
618
619 if (VG_(clo_trace_signals))
620 VG_(message)(Vg_DebugExtraMsg,
621 "__NR_sigaction: sigNo %d, "
622 "new 0x%x, old 0x%x, new flags 0x%x",
623 param1,(UInt)new_action,(UInt)old_action,
624 (UInt)(new_action ? new_action->ksa_flags : 0) );
625 /* VG_(ppSigProcMask)(); */
626
sewardj0ca2a6b2002-03-29 14:02:34 +0000627 /* Rule out various error conditions. The aim is to ensure that if
628 the call is passed to the kernel it will definitely succeed. */
629
630 /* Reject out-of-range signal numbers. */
631 if (param1 < 1 || param1 >= VKI_KNSIG) goto bad_signo;
632
633 /* Reject attempts to set a handler (or set ignore) for SIGKILL. */
634 if ( (param1 == VKI_SIGKILL || param1 == VKI_SIGSTOP)
635 && new_action
636 && new_action->ksa_handler != VKI_SIG_DFL)
637 goto bad_sigkill;
sewardjde4a1d02002-03-22 01:27:54 +0000638
639 our_old_handler = VG_(sighandler)[param1];
640 /* VG_(printf)("old handler = 0x%x\n", our_old_handler); */
641 /* If a new handler has been specified, mess with its handler. */
642 if (new_action) {
643 if (new_action->ksa_handler == VKI_SIG_IGN ||
644 new_action->ksa_handler == VKI_SIG_DFL) {
645 VG_(sighandler)[param1] = NULL;
646 VG_(sigpending)[param1] = NULL;
647 /* Dangerous! Could lose signals like this. */
648 } else {
649 /* VG_(printf)("new handler = 0x%x\n", new_action->ksa_handler); */
650 /* The client isn't allowed to use an alternative signal
651 stack. We, however, must. */
652 if ((new_action->ksa_flags & VKI_SA_ONSTACK) != 0)
653 VG_(unimplemented)
654 ("signals on an alternative stack (SA_ONSTACK)");
655 new_action->ksa_flags |= VKI_SA_ONSTACK;
656 VG_(sighandler)[param1] = new_action->ksa_handler;
sewardj77e466c2002-04-14 02:29:29 +0000657 vg_sig_sarestart[param1]
658 = (new_action->ksa_flags & VKI_SA_RESTART) ? True : False;
659 new_action->ksa_flags |= VKI_SA_RESTART;
sewardjde4a1d02002-03-22 01:27:54 +0000660 new_action->ksa_handler = &VG_(oursignalhandler);
661 }
662 }
663
sewardj2e93c502002-04-12 11:12:52 +0000664 KERNEL_DO_SYSCALL(tid,res);
sewardjde4a1d02002-03-22 01:27:54 +0000665 /* VG_(printf)("RES = %d\n", res); */
sewardj0ca2a6b2002-03-29 14:02:34 +0000666
sewardjde4a1d02002-03-22 01:27:54 +0000667 /* If the client asks for the old handler, maintain our fiction
668 by stuffing in the handler it thought it asked for ... */
669 if (old_action) {
670 if (old_action->ksa_handler == VKI_SIG_IGN ||
671 old_action->ksa_handler == VKI_SIG_DFL) {
672 /* No old action; we should have a NULL handler. */
673 vg_assert(our_old_handler == NULL);
674 } else {
675 /* There's a handler. */
676 if (param1 != VKI_SIGKILL && param1 != VKI_SIGABRT) {
677 vg_assert(old_action->ksa_handler == &VG_(oursignalhandler));
678 vg_assert((old_action->ksa_flags & VKI_SA_ONSTACK) != 0);
679 }
680 old_action->ksa_handler = our_old_handler;
681 /* Since the client is not allowed to ask for an alternative
682 sig stack, unset the bit for anything we pass back to
683 it. */
684 old_action->ksa_flags &= ~VKI_SA_ONSTACK;
sewardj77e466c2002-04-14 02:29:29 +0000685 /* Restore the SA_RESTART flag to whatever we snaffled. */
686 if (vg_sig_sarestart[param1])
687 old_action->ksa_flags |= VKI_SA_RESTART;
688 else
689 old_action->ksa_flags &= ~VKI_SA_RESTART;
sewardjde4a1d02002-03-22 01:27:54 +0000690 }
691 }
692
693 VG_(ksignal)(VKI_SIGABRT, &VG_(oursignalhandler));
694 goto good;
695
696 good:
sewardj2e93c502002-04-12 11:12:52 +0000697 tst->m_eax = (UInt)0;
sewardjde4a1d02002-03-22 01:27:54 +0000698 return;
699
sewardj0ca2a6b2002-03-29 14:02:34 +0000700 bad_signo:
sewardjde4a1d02002-03-22 01:27:54 +0000701 VG_(message)(Vg_UserMsg,
702 "Warning: bad signal number %d in __NR_sigaction.",
703 param1);
sewardj0ca2a6b2002-03-29 14:02:34 +0000704 VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-VKI_EINVAL);
705 return;
706
707 bad_sigkill:
708 VG_(message)(Vg_UserMsg,
709 "Warning: attempt to set SIGKILL handler in __NR_sigaction.",
710 param1);
711 VG_(baseBlock)[VGOFF_(m_eax)] = (UInt)(-VKI_EINVAL);
sewardjde4a1d02002-03-22 01:27:54 +0000712 return;
713}
714
715
716/* The kernel handles sigprocmask in the usual way, but we also need
717 to inspect it, so as to spot requests to unblock signals. We then
718 inspect vg_sigpending, which records the current state of signal
719 delivery to the client. The problematic case is when a signal is
720 delivered to the client, in which case the relevant vg_sigpending
721 slot is set to VG_SIGRUNNING. This inhibits further signal
722 deliveries. This mechanism implements the POSIX requirement that a
723 signal is blocked in its own handler.
724
725 If the handler returns normally, the slot is changed back to
726 VG_SIGIDLE, so that further instances of the signal can be
727 delivered. The problem occurs when the handler never returns, but
728 longjmps. POSIX mandates that you then have to do an explicit
729 setprocmask to re-enable the signal. That is what we try and spot
730 here. Although the call is passed to the kernel, we also need to
731 spot unblocked signals whose state is VG_SIGRUNNING, and change it
732 back to VG_SIGIDLE.
733*/
734void VG_(do__NR_sigprocmask) ( Int how, vki_ksigset_t* set )
735{
736 Int i;
737 if (VG_(clo_trace_signals))
738 VG_(message)(Vg_DebugMsg,
739 "vg_do__NR_sigprocmask: how = %d (%s), set = %p",
740 how,
741 how==VKI_SIG_BLOCK ? "SIG_BLOCK" : (
742 how==VKI_SIG_UNBLOCK ? "SIG_UNBLOCK" : (
743 how==VKI_SIG_SETMASK ? "SIG_SETMASK" : "???")),
744 set
745 );
746
747 /* Sometimes this happens. I don't know what it signifies. */
748 if (set == NULL)
749 return;
750
751 /* Not interested in blocking of signals. */
752 if (how == VKI_SIG_BLOCK)
753 return;
754
755 /* Detect and ignore unknown action. */
756 if (how != VKI_SIG_UNBLOCK && how != VKI_SIG_SETMASK) {
757 VG_(message)(Vg_DebugMsg,
758 "sigprocmask: unknown `how' field %d", how);
759 return;
760 }
761
762 for (i = 1; i < VKI_KNSIG; i++) {
763 Bool unblock_me = False;
764 if (how == VKI_SIG_SETMASK) {
765 if (!VG_(ksigismember)(set,i))
766 unblock_me = True;
767 } else { /* how == SIG_UNBLOCK */
768 if (VG_(ksigismember)(set,i))
769 unblock_me = True;
770 }
771 if (unblock_me && VG_(sigpending)[i] == VG_SIGRUNNING) {
772 VG_(sigpending)[i] = VG_SIGIDLE;
773 if (VG_(clo_verbosity) > 1)
774 VG_(message)(Vg_UserMsg,
775 "Warning: unblocking signal %d "
776 "due to sigprocmask", i );
777 }
778 }
779}
780
781
782
783/*--------------------------------------------------------------------*/
784/*--- end vg_signals.c ---*/
785/*--------------------------------------------------------------------*/