blob: 7a8c737e0412098c2ca8b3e4c85662212b56926a [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
sewardj018f7622002-05-15 21:13:39 +000038/* Define to give more sanity checking for signals. */
39#define DEBUG_SIGNALS
40
41
sewardjfa356512002-05-24 00:00:59 +000042/* KNOWN BUGS 24 May 02:
43
44 - A signal is not masked in its own handler. Neither are the
45 signals in the signal's blocking mask.
46
47 - There is only one pending set for the entire process, whereas
48 POSIX seems to require each thread have its own pending set.
49 This means that a signal can only be pending for one thread at
50 a time.
51
52 - The following causes an infinite loop: start Hugs, Feb 2001
53 version, and do Control-C at the prompt. There is an infinite
54 series of sigints delivered (to the client); but also seemingly
55 to valgrind, which is very strange. I don't know why.
56
57 Probably a lot more bugs which I haven't discovered yet.
58*/
59
60
sewardj018f7622002-05-15 21:13:39 +000061/* ---------------------------------------------------------------------
62 Forwards decls.
63 ------------------------------------------------------------------ */
64
65static void vg_oursignalhandler ( Int sigNo );
66
67
68/* ---------------------------------------------------------------------
69 HIGH LEVEL STUFF TO DO WITH SIGNALS: POLICY (MOSTLY)
70 ------------------------------------------------------------------ */
71
sewardjde4a1d02002-03-22 01:27:54 +000072/* ---------------------------------------------------------------------
sewardjde4a1d02002-03-22 01:27:54 +000073 Signal state for this process.
74 ------------------------------------------------------------------ */
75
sewardj018f7622002-05-15 21:13:39 +000076
sewardjb48e5002002-05-13 00:16:03 +000077/* Base-ment of these arrays[VKI_KNSIG].
78
79 Valid signal numbers are 1 .. VKI_KNSIG inclusive.
80 Rather than subtracting 1 for indexing these arrays, which
81 is tedious and error-prone, they are simply dimensioned 1 larger,
82 and entry [0] is not used.
83 */
84
sewardjb48e5002002-05-13 00:16:03 +000085
sewardj018f7622002-05-15 21:13:39 +000086/* -----------------------------------------------------
87 Static client signal state (SCSS). This is the state
88 that the client thinks it has the kernel in.
89 SCSS records verbatim the client's settings. These
90 are mashed around only when SKSS is calculated from it.
91 -------------------------------------------------- */
sewardjb48e5002002-05-13 00:16:03 +000092
sewardj018f7622002-05-15 21:13:39 +000093typedef
94 struct {
95 void* scss_handler; /* VKI_SIG_DFL or VKI_SIG_IGN or ptr to
96 client's handler */
97 UInt scss_flags;
98 vki_ksigset_t scss_mask;
99 void* scss_restorer; /* god knows; we ignore it. */
100 }
101 SCSS_Per_Signal;
sewardjb48e5002002-05-13 00:16:03 +0000102
sewardj018f7622002-05-15 21:13:39 +0000103typedef
104 struct {
sewardj2342c972002-05-22 23:34:20 +0000105 /* per-signal info */
sewardj018f7622002-05-15 21:13:39 +0000106 SCSS_Per_Signal scss_per_sig[1+VKI_KNSIG];
sewardj2342c972002-05-22 23:34:20 +0000107
108 /* Signal delivery stack, if any. */
109 vki_kstack_t altstack;
110
sewardj018f7622002-05-15 21:13:39 +0000111 /* Additional elements to SCSS not stored here:
112 - for each thread, the thread's blocking mask
113 - for each thread in WaitSIG, the set of waited-on sigs
114 */
115 }
116 SCSS;
sewardjb48e5002002-05-13 00:16:03 +0000117
sewardj018f7622002-05-15 21:13:39 +0000118static SCSS vg_scss;
119
120
121/* -----------------------------------------------------
122 Static kernel signal state (SKSS). This is the state
123 that we have the kernel in. It is computed from SCSS.
124 -------------------------------------------------- */
125
126/* Let's do:
127 sigprocmask assigns to all thread masks
128 so that at least everything is always consistent
129 Flags:
130 SA_NOCLDSTOP -- passed to kernel
131 SA_ONESHOT or SA_RESETHAND -- required; abort if not set
132 SA_RESTART -- we observe this but set our handlers always to restart
133 SA_NOMASK or SA_NODEFER -- required to not be set; abort if set
134 SA_ONSTACK -- currently not supported; abort if set.
sewardjb48e5002002-05-13 00:16:03 +0000135*/
sewardjde4a1d02002-03-22 01:27:54 +0000136
sewardj77e466c2002-04-14 02:29:29 +0000137
sewardj018f7622002-05-15 21:13:39 +0000138typedef
139 struct {
140 void* skss_handler; /* VKI_SIG_DFL or VKI_SIG_IGN
141 or ptr to our handler */
142 UInt skss_flags;
143 /* There is no skss_mask, since we know that we will always ask
144 for all signals to be blocked in our one-and-only
145 sighandler. */
146 /* Also there is no skss_restorer. */
147 }
148 SKSS_Per_Signal;
sewardjde4a1d02002-03-22 01:27:54 +0000149
sewardj018f7622002-05-15 21:13:39 +0000150typedef
151 struct {
152 SKSS_Per_Signal skss_per_sig[1+VKI_KNSIG];
153 vki_ksigset_t skss_sigmask; /* process' blocked signal mask */
154 }
155 SKSS;
156
157static SKSS vg_skss;
sewardjde4a1d02002-03-22 01:27:54 +0000158
sewardj2e93c502002-04-12 11:12:52 +0000159
sewardj018f7622002-05-15 21:13:39 +0000160/* -----------------------------------------------------
161 Dynamic client signal state (DCSS). This holds transient
162 information about state of client signals.
163 -------------------------------------------------- */
sewardjb48e5002002-05-13 00:16:03 +0000164
sewardj018f7622002-05-15 21:13:39 +0000165typedef
166 struct {
167 /* True iff a signal has been received but not yet passed to
168 client. */
169 Bool dcss_sigpending[1+VKI_KNSIG];
170 /* If sigpending[] is True, has meaning:
171 VG_INVALID_THREADID -- to be passed to any suitable thread
172 other -- to be passed only to the specified thread. */
173 ThreadId dcss_destthread[1+VKI_KNSIG];
174 }
175 DCSS;
sewardjb48e5002002-05-13 00:16:03 +0000176
sewardj018f7622002-05-15 21:13:39 +0000177static DCSS vg_dcss;
sewardjb48e5002002-05-13 00:16:03 +0000178
179
sewardj018f7622002-05-15 21:13:39 +0000180/* ---------------------------------------------------------------------
181 Compute the SKSS required by the current SCSS.
182 ------------------------------------------------------------------ */
183
sewardj4f29ddf2002-05-03 22:29:04 +0000184static
sewardj018f7622002-05-15 21:13:39 +0000185void pp_SKSS ( void )
186{
187 Int sig;
188 VG_(printf)("\n\nSKSS:\n");
189 for (sig = 1; sig <= VKI_KNSIG; sig++) {
190 VG_(printf)("sig %d: handler 0x%x, flags 0x%x\n", sig,
191 vg_skss.skss_per_sig[sig].skss_handler,
192 vg_skss.skss_per_sig[sig].skss_flags );
sewardj77e466c2002-04-14 02:29:29 +0000193
sewardj018f7622002-05-15 21:13:39 +0000194 }
195 VG_(printf)("Global sigmask (63 .. 0) = 0x%x 0x%x\n",
196 vg_skss.skss_sigmask.ws[1],
197 vg_skss.skss_sigmask.ws[0] );
198}
199
200static __inline__
201Bool is_WaitSIGd_by_any_thread ( Int sig )
202{
203 ThreadId tid;
204 for (tid = 1; tid < VG_N_THREADS; tid++) {
205 if (VG_(threads)[tid].status != VgTs_WaitSIG)
206 continue;
207 if (VG_(ksigismember)( &VG_(threads)[tid].sigs_waited_for, sig ))
208 return True;
209 }
210 return False;
211}
212
213static __inline__
214Bool is_blocked_by_all_threads ( Int sig )
215{
216 ThreadId tid;
217 for (tid = 1; tid < VG_N_THREADS; tid++) {
218 if (VG_(threads)[tid].status == VgTs_Empty)
219 continue;
220 if (! VG_(ksigismember)( &VG_(threads)[tid].sig_mask, sig ))
221 return False;
222 }
223 return True;
224}
225
226
227/* This is the core, clever bit. Computation is as follows:
228
229 For each signal
230 handler = if client has a handler, then our handler
231 else if is WaitSIG'd by any thread, then our handler
232 else if client is DFL, then DFL
233 else (client must be IGN) IGN
234
235 blocked = if is blocked by all threads and not WaitSIG'd by
236 any thread
237 then BLOCKED
238 else UNBLOCKED
239*/
240static
241void calculate_SKSS_from_SCSS ( SKSS* dst )
242{
243 Int sig;
244 void* skss_handler;
245 void* scss_handler;
246 Bool iz_WaitSIGd_by_any_thread;
247 Bool iz_blocked_by_all_threads;
248 Bool skss_blocked;
249 UInt scss_flags;
250 UInt skss_flags;
251
252 VG_(ksigemptyset)( &dst->skss_sigmask );
253
254 for (sig = 1; sig <= VKI_KNSIG; sig++) {
255
256 /* Calculate kernel handler and blockedness for sig, as per rules
257 in above comment. */
258
259 iz_WaitSIGd_by_any_thread = is_WaitSIGd_by_any_thread(sig);
260 iz_blocked_by_all_threads = is_blocked_by_all_threads(sig);
261
262 scss_handler = vg_scss.scss_per_sig[sig].scss_handler;
263 scss_flags = vg_scss.scss_per_sig[sig].scss_flags;
264
265 /* Restorer */
266 /*
267 Doesn't seem like we can spin this one.
268 if (vg_scss.scss_per_sig[sig].scss_restorer != NULL)
269 VG_(unimplemented)
270 ("sigactions with non-NULL .sa_restorer field");
271 */
272
273 /* Handler */
274
275 if (scss_handler != VKI_SIG_DFL && scss_handler != VKI_SIG_IGN) {
276 skss_handler = &vg_oursignalhandler;
277 } else
278 if (iz_WaitSIGd_by_any_thread) {
279 skss_handler = &vg_oursignalhandler;
280 } else
281 if (scss_handler == VKI_SIG_DFL) {
282 skss_handler = VKI_SIG_DFL;
283 }
284 else {
285 vg_assert(scss_handler == VKI_SIG_IGN);
286 skss_handler = VKI_SIG_IGN;
287 }
288
289 /* Blockfulness */
290
291 skss_blocked
292 = iz_blocked_by_all_threads && !iz_WaitSIGd_by_any_thread;
293
294 /* Flags */
295
296 skss_flags = 0;
297 /* SA_NOCLDSTOP: pass to kernel */
298 if (scss_flags & VKI_SA_NOCLDSTOP)
299 skss_flags |= VKI_SA_NOCLDSTOP;
300 /* SA_ONESHOT: ignore client setting */
301 /*
302 if (!(scss_flags & VKI_SA_ONESHOT))
303 VG_(unimplemented)
304 ("sigactions without SA_ONESHOT");
305 vg_assert(scss_flags & VKI_SA_ONESHOT);
306 skss_flags |= VKI_SA_ONESHOT;
307 */
308 /* SA_RESTART: ignore client setting and set for us */
309 skss_flags |= VKI_SA_RESTART;
310 /* SA_NOMASK: not allowed */
311 /*
312 .. well, ignore it.
313 if (scss_flags & VKI_SA_NOMASK)
314 VG_(unimplemented)
315 ("sigactions with SA_NOMASK");
316 vg_assert(!(scss_flags & VKI_SA_NOMASK));
317 */
sewardj2342c972002-05-22 23:34:20 +0000318 /* SA_ONSTACK: client setting is irrelevant here */
319 /*
sewardj018f7622002-05-15 21:13:39 +0000320 if (scss_flags & VKI_SA_ONSTACK)
321 VG_(unimplemented)
322 ("signals on an alternative stack (SA_ONSTACK)");
323 vg_assert(!(scss_flags & VKI_SA_ONSTACK));
sewardj2342c972002-05-22 23:34:20 +0000324 */
sewardj018f7622002-05-15 21:13:39 +0000325 /* ... but WE ask for on-stack ourselves ... */
326 skss_flags |= VKI_SA_ONSTACK;
327
328 /* Create SKSS entry for this signal. */
329
330 if (skss_blocked
331 && sig != VKI_SIGKILL && sig != VKI_SIGSTOP)
332 VG_(ksigaddset)( &dst->skss_sigmask, sig );
333
sewardj6a3c26e2002-05-23 17:09:43 +0000334 if (sig != VKI_SIGKILL && sig != VKI_SIGSTOP)
335 dst->skss_per_sig[sig].skss_handler = skss_handler;
336 else
337 dst->skss_per_sig[sig].skss_handler = VKI_SIG_DFL;
338
sewardj018f7622002-05-15 21:13:39 +0000339 dst->skss_per_sig[sig].skss_flags = skss_flags;
340 }
341
342 /* Sanity checks. */
343 vg_assert(dst->skss_per_sig[VKI_SIGKILL].skss_handler
344 == VKI_SIG_DFL);
345 vg_assert(dst->skss_per_sig[VKI_SIGSTOP].skss_handler
346 == VKI_SIG_DFL);
347 vg_assert(!VG_(ksigismember)( &dst->skss_sigmask, VKI_SIGKILL ));
348 vg_assert(!VG_(ksigismember)( &dst->skss_sigmask, VKI_SIGSTOP ));
349
350 if (0)
351 pp_SKSS();
352}
353
354
355/* ---------------------------------------------------------------------
356 After a possible SCSS change, update SKSS and the kernel itself.
357 ------------------------------------------------------------------ */
358
359/* IMPORTANT NOTE: to avoid race conditions, we must always enter here
360 with ALL KERNEL SIGNALS BLOCKED !
361*/
362void VG_(handle_SCSS_change) ( Bool force_update )
363{
364 Int res, sig;
365 SKSS skss_old;
366 vki_ksigaction ksa, ksa_old;
367
368# ifdef DEBUG_SIGNALS
369 vki_ksigset_t test_sigmask;
370 res = VG_(ksigprocmask)( VKI_SIG_SETMASK /*irrelevant*/,
371 NULL, &test_sigmask );
372 vg_assert(res == 0);
373 /* The kernel never says that SIGKILL or SIGSTOP are masked. It is
374 correct! So we fake it here for the purposes only of
375 assertion. */
376 VG_(ksigaddset)( &test_sigmask, VKI_SIGKILL );
377 VG_(ksigaddset)( &test_sigmask, VKI_SIGSTOP );
378 vg_assert(VG_(kisfullsigset)( &test_sigmask ));
379# endif
380
381 /* Remember old SKSS and calculate new one. */
382 skss_old = vg_skss;
383 calculate_SKSS_from_SCSS ( &vg_skss );
384
385 /* Compare the new SKSS entries vs the old ones, and update kernel
386 where they differ. */
387 for (sig = 1; sig <= VKI_KNSIG; sig++) {
388
389 /* Trying to do anything with SIGKILL is pointless; just ignore
390 it. */
391 if (sig == VKI_SIGKILL || sig == VKI_SIGSTOP)
392 continue;
393
394 /* Aside: take the opportunity to clean up DCSS: forget about any
395 pending signals directed at dead threads. */
396 if (vg_dcss.dcss_sigpending[sig]
397 && vg_dcss.dcss_destthread[sig] != VG_INVALID_THREADID) {
398 ThreadId tid = vg_dcss.dcss_destthread[sig];
399 vg_assert(VG_(is_valid_or_empty_tid)(tid));
400 if (VG_(threads)[tid].status == VgTs_Empty) {
401 vg_dcss.dcss_sigpending[sig] = False;
402 vg_dcss.dcss_destthread[sig] = VG_INVALID_THREADID;
403 if (VG_(clo_trace_signals))
404 VG_(message)(Vg_DebugMsg,
405 "discarding pending signal %d due to thread %d exiting",
406 sig, tid );
407 }
408 }
409
410 /* End of the Aside. Now the Main Business. */
411
412 if (!force_update) {
413 if ((skss_old.skss_per_sig[sig].skss_handler
414 == vg_skss.skss_per_sig[sig].skss_handler)
415 && (skss_old.skss_per_sig[sig].skss_flags
416 == vg_skss.skss_per_sig[sig].skss_flags))
417 /* no difference */
418 continue;
419 }
420
421 ksa.ksa_handler = vg_skss.skss_per_sig[sig].skss_handler;
422 ksa.ksa_flags = vg_skss.skss_per_sig[sig].skss_flags;
423 vg_assert(ksa.ksa_flags & VKI_SA_ONSTACK);
424 VG_(ksigfillset)( &ksa.ksa_mask );
425 VG_(ksigdelset)( &ksa.ksa_mask, VKI_SIGKILL );
426 VG_(ksigdelset)( &ksa.ksa_mask, VKI_SIGSTOP );
427 ksa.ksa_restorer = NULL;
428
429 if (VG_(clo_trace_signals))
430 VG_(message)(Vg_DebugMsg,
431 "setting ksig %d to: hdlr 0x%x, flags 0x%x, "
432 "mask(63..0) 0x%x 0x%x",
433 sig, ksa.ksa_handler,
434 ksa.ksa_flags,
435 ksa.ksa_mask.ws[1],
436 ksa.ksa_mask.ws[0]
437 );
438
439 res = VG_(ksigaction)( sig, &ksa, &ksa_old );
440 vg_assert(res == 0);
441
442 /* Since we got the old sigaction more or less for free, might
443 as well extract the maximum sanity-check value from it. */
444 if (!force_update) {
445 vg_assert(ksa_old.ksa_handler
446 == skss_old.skss_per_sig[sig].skss_handler);
447 vg_assert(ksa_old.ksa_flags
448 == skss_old.skss_per_sig[sig].skss_flags);
449 vg_assert(ksa_old.ksa_restorer
450 == NULL);
451 VG_(ksigaddset)( &ksa_old.ksa_mask, VKI_SIGKILL );
452 VG_(ksigaddset)( &ksa_old.ksa_mask, VKI_SIGSTOP );
453 vg_assert(VG_(kisfullsigset)( &ksa_old.ksa_mask ));
454 }
455 }
456
457 /* Just set the new sigmask, even if it's no different from the
458 old, since we have to do this anyway, to unblock the host
459 signals. */
460 if (VG_(clo_trace_signals))
461 VG_(message)(Vg_DebugMsg,
462 "setting kmask(63..0) to 0x%x 0x%x",
463 vg_skss.skss_sigmask.ws[1],
464 vg_skss.skss_sigmask.ws[0]
465 );
466
467 VG_(restore_all_host_signals)( &vg_skss.skss_sigmask );
468}
469
470
471/* ---------------------------------------------------------------------
472 Update/query SCSS in accordance with client requests.
473 ------------------------------------------------------------------ */
474
sewardj2342c972002-05-22 23:34:20 +0000475/* Logic for this alt-stack stuff copied directly from do_sigaltstack
476 in kernel/signal.[ch] */
477
478/* True if we are on the alternate signal stack. */
479static Int on_sig_stack ( Addr m_esp )
480{
481 return (m_esp - (Addr)vg_scss.altstack.ss_sp
482 < vg_scss.altstack.ss_size);
483}
484
485static Int sas_ss_flags ( Addr m_esp )
486{
487 return (vg_scss.altstack.ss_size == 0
488 ? VKI_SS_DISABLE
489 : on_sig_stack(m_esp) ? VKI_SS_ONSTACK : 0);
490}
491
492
493void VG_(do__NR_sigaltstack) ( ThreadId tid )
494{
495 vki_kstack_t* ss;
496 vki_kstack_t* oss;
497 Addr m_esp;
498
499 vg_assert(VG_(is_valid_tid)(tid));
500 ss = (vki_kstack_t*)(VG_(threads)[tid].m_ebx);
501 oss = (vki_kstack_t*)(VG_(threads)[tid].m_ecx);
502 m_esp = VG_(threads)[tid].m_esp;
503
504 if (VG_(clo_trace_signals))
505 VG_(message)(Vg_DebugExtraMsg,
506 "__NR_sigaltstack: tid %d, "
507 "ss 0x%x, oss 0x%x (current %%esp %p)",
508 tid, (UInt)ss, (UInt)oss, (UInt)m_esp );
509
510 if (oss != NULL) {
511 oss->ss_sp = vg_scss.altstack.ss_sp;
512 oss->ss_size = vg_scss.altstack.ss_size;
513 oss->ss_flags = sas_ss_flags(m_esp);
514 }
515
516 if (ss != NULL) {
517 if (on_sig_stack(VG_(threads)[tid].m_esp)) {
518 SET_EAX(tid, -VKI_EPERM);
519 return;
520 }
521 if (ss->ss_flags != VKI_SS_DISABLE
522 && ss->ss_flags != VKI_SS_ONSTACK
523 && ss->ss_flags != 0) {
524 SET_EAX(tid, -VKI_EINVAL);
525 return;
526 }
527 if (ss->ss_flags == VKI_SS_DISABLE) {
528 vg_scss.altstack.ss_size = 0;
529 vg_scss.altstack.ss_sp = NULL;
530 } else {
531 if (ss->ss_size < VKI_MINSIGSTKSZ) {
532 SET_EAX(tid, -VKI_ENOMEM);
533 return;
534 }
535 }
536 vg_scss.altstack.ss_sp = ss->ss_sp;
537 vg_scss.altstack.ss_size = ss->ss_size;
538 }
539 SET_EAX(tid, 0);
540}
541
542
sewardj018f7622002-05-15 21:13:39 +0000543void VG_(do__NR_sigaction) ( ThreadId tid )
544{
545 Int signo;
546 vki_ksigaction* new_act;
547 vki_ksigaction* old_act;
548 vki_ksigset_t irrelevant_sigmask;
549
550 vg_assert(VG_(is_valid_tid)(tid));
551 signo = VG_(threads)[tid].m_ebx; /* int sigNo */
552 new_act = (vki_ksigaction*)(VG_(threads)[tid].m_ecx);
553 old_act = (vki_ksigaction*)(VG_(threads)[tid].m_edx);
554
555 if (VG_(clo_trace_signals))
556 VG_(message)(Vg_DebugExtraMsg,
557 "__NR_sigaction: tid %d, sigNo %d, "
558 "new 0x%x, old 0x%x, new flags 0x%x",
559 tid, signo, (UInt)new_act, (UInt)old_act,
560 (UInt)(new_act ? new_act->ksa_flags : 0) );
561
562 /* Rule out various error conditions. The aim is to ensure that if
563 when the call is passed to the kernel it will definitely
564 succeed. */
565
566 /* Reject out-of-range signal numbers. */
567 if (signo < 1 || signo > VKI_KNSIG) goto bad_signo;
568
569 /* Reject attempts to set a handler (or set ignore) for SIGKILL. */
570 if ( (signo == VKI_SIGKILL || signo == VKI_SIGSTOP)
571 && new_act
572 && new_act->ksa_handler != VKI_SIG_DFL)
573 goto bad_sigkill_or_sigstop;
574
575 /* If the client supplied non-NULL old_act, copy the relevant SCSS
576 entry into it. */
577 if (old_act) {
578 old_act->ksa_handler = vg_scss.scss_per_sig[signo].scss_handler;
579 old_act->ksa_flags = vg_scss.scss_per_sig[signo].scss_flags;
580 old_act->ksa_mask = vg_scss.scss_per_sig[signo].scss_mask;
581 old_act->ksa_restorer = vg_scss.scss_per_sig[signo].scss_restorer;
582 }
583
584 /* And now copy new SCSS entry from new_act. */
585 if (new_act) {
586 vg_scss.scss_per_sig[signo].scss_handler = new_act->ksa_handler;
587 vg_scss.scss_per_sig[signo].scss_flags = new_act->ksa_flags;
588 vg_scss.scss_per_sig[signo].scss_mask = new_act->ksa_mask;
589 vg_scss.scss_per_sig[signo].scss_restorer = new_act->ksa_restorer;
590 }
591
592 /* All happy bunnies ... */
593 if (new_act) {
594 VG_(block_all_host_signals)( &irrelevant_sigmask );
595 VG_(handle_SCSS_change)( False /* lazy update */ );
596 }
597 SET_EAX(tid, 0);
598 return;
599
600 bad_signo:
601 VG_(message)(Vg_UserMsg,
602 "Warning: bad signal number %d in __NR_sigaction.",
603 signo);
604 SET_EAX(tid, -VKI_EINVAL);
605 return;
606
607 bad_sigkill_or_sigstop:
608 VG_(message)(Vg_UserMsg,
609 "Warning: attempt to set %s handler in __NR_sigaction.",
610 signo == VKI_SIGKILL ? "SIGKILL" : "SIGSTOP" );
611
612 SET_EAX(tid, -VKI_EINVAL);
613 return;
614}
615
616
617static
618void do_sigprocmask_bitops ( Int vki_how,
619 vki_ksigset_t* orig_set,
620 vki_ksigset_t* modifier )
621{
622 switch (vki_how) {
623 case VKI_SIG_BLOCK:
624 VG_(ksigaddset_from_set)( orig_set, modifier );
625 break;
626 case VKI_SIG_UNBLOCK:
627 VG_(ksigdelset_from_set)( orig_set, modifier );
628 break;
629 case VKI_SIG_SETMASK:
630 *orig_set = *modifier;
631 break;
632 default:
633 VG_(panic)("do_sigprocmask_bitops");
634 break;
635 }
636}
637
638/* Handle blocking mask set/get uniformly for threads and process as a
639 whole. If tid==VG_INVALID_THREADID, this is really
640 __NR_sigprocmask, in which case we set the masks for all threads to
641 the "set" and return in "oldset" that from the root thread (1).
642 Otherwise, tid will denote a valid thread, in which case we just
643 set/get its mask.
644
645 Note that the thread signal masks are an implicit part of SCSS,
646 which is why this routine is allowed to mess with them.
647*/
648static
649void do_setmask ( ThreadId tid,
650 Int how,
651 vki_ksigset_t* newset,
652 vki_ksigset_t* oldset )
653{
654 vki_ksigset_t irrelevant_sigmask;
655
656 if (VG_(clo_trace_signals))
sewardja464e5c2002-05-23 17:34:49 +0000657 VG_(message)(Vg_DebugExtraMsg,
sewardj3a951cf2002-05-15 22:25:47 +0000658 "do_setmask: tid = %d (%d means ALL), how = %d (%s), set = %p",
sewardj018f7622002-05-15 21:13:39 +0000659 tid,
sewardj3a951cf2002-05-15 22:25:47 +0000660 VG_INVALID_THREADID,
sewardj018f7622002-05-15 21:13:39 +0000661 how,
662 how==VKI_SIG_BLOCK ? "SIG_BLOCK" : (
663 how==VKI_SIG_UNBLOCK ? "SIG_UNBLOCK" : (
664 how==VKI_SIG_SETMASK ? "SIG_SETMASK" : "???")),
665 newset
666 );
667
668 if (tid == VG_INVALID_THREADID) {
669 /* Behave as if __NR_sigprocmask. */
670 if (oldset) {
671 /* A bit fragile. Should do better here really. */
672 vg_assert(VG_(threads)[1].status != VgTs_Empty);
673 *oldset = VG_(threads)[1].sig_mask;
674 }
675 if (newset) {
676 ThreadId tidd;
677 for (tidd = 1; tidd < VG_N_THREADS; tidd++) {
678 if (VG_(threads)[tidd].status == VgTs_Empty)
679 continue;
680 do_sigprocmask_bitops (
681 how, &VG_(threads)[tidd].sig_mask, newset );
682 }
683 }
684 } else {
685 /* Just do this thread. */
686 vg_assert(VG_(is_valid_tid)(tid));
687 if (oldset)
688 *oldset = VG_(threads)[tid].sig_mask;
689 if (newset)
690 do_sigprocmask_bitops (
691 how, &VG_(threads)[tid].sig_mask, newset );
692 }
693
694 if (newset) {
695 VG_(block_all_host_signals)( &irrelevant_sigmask );
696 VG_(handle_SCSS_change)( False /* lazy update */ );
697 }
698}
699
700
701void VG_(do__NR_sigprocmask) ( ThreadId tid,
702 Int how,
703 vki_ksigset_t* set,
704 vki_ksigset_t* oldset )
705{
706 if (how == VKI_SIG_BLOCK || how == VKI_SIG_UNBLOCK
707 || how == VKI_SIG_SETMASK) {
708 vg_assert(VG_(is_valid_tid)(tid));
709 do_setmask ( VG_INVALID_THREADID, how, set, oldset );
710 /* Syscall returns 0 (success) to its thread. */
711 SET_EAX(tid, 0);
712 } else {
713 VG_(message)(Vg_DebugMsg,
714 "sigprocmask: unknown `how' field %d", how);
715 SET_EAX(tid, -VKI_EINVAL);
716 }
717}
718
719
720void VG_(do_pthread_sigmask_SCSS_upd) ( ThreadId tid,
721 Int how,
722 vki_ksigset_t* set,
723 vki_ksigset_t* oldset )
724{
725 /* Assume that how has been validated by caller. */
726 vg_assert(how == VKI_SIG_BLOCK || how == VKI_SIG_UNBLOCK
727 || how == VKI_SIG_SETMASK);
728 vg_assert(VG_(is_valid_tid)(tid));
729 do_setmask ( tid, how, set, oldset );
730 /* The request return code is set in do_pthread_sigmask */
731}
732
733
734void VG_(send_signal_to_thread) ( ThreadId thread, Int sig )
735{
736 Int res;
737 vg_assert(VG_(is_valid_tid)(thread));
738 vg_assert(sig >= 1 && sig <= VKI_KNSIG);
739
740 switch ((UInt)(vg_scss.scss_per_sig[sig].scss_handler)) {
741
sewardjc9792e32002-05-21 00:05:10 +0000742 case ((UInt)VKI_SIG_IGN):
sewardj018f7622002-05-15 21:13:39 +0000743 if (VG_(clo_trace_signals))
744 VG_(message)(Vg_DebugMsg,
745 "send_signal %d to_thread %d: IGN, ignored", sig, thread );
746 break;
747
sewardjc9792e32002-05-21 00:05:10 +0000748 case ((UInt)VKI_SIG_DFL):
sewardj018f7622002-05-15 21:13:39 +0000749 /* This is the tricky case. Since we don't handle default
750 actions, the simple thing is to send someone round to the
751 front door and signal there. Then the kernel will do
752 whatever it does with the default action. */
753 res = VG_(kill)( VG_(getpid)(), sig );
754 vg_assert(res == 0);
755 break;
756
757 default:
758 if (!vg_dcss.dcss_sigpending[sig]) {
759 vg_dcss.dcss_sigpending[sig] = True;
760 vg_dcss.dcss_destthread[sig] = thread;
761 if (VG_(clo_trace_signals))
762 VG_(message)(Vg_DebugMsg,
763 "send_signal %d to_thread %d: now pending", sig, thread );
764 } else {
765 if (vg_dcss.dcss_destthread[sig] == thread) {
766 if (VG_(clo_trace_signals))
767 VG_(message)(Vg_DebugMsg,
768 "send_signal %d to_thread %d: already pending ... "
769 "discarded", sig, thread );
770 } else {
771 if (VG_(clo_trace_signals))
772 VG_(message)(Vg_DebugMsg,
773 "send_signal %d to_thread %d: was pending for %d, "
774 "now pending for %d",
775 sig, thread, vg_dcss.dcss_destthread[sig], thread );
776 vg_dcss.dcss_destthread[sig] = thread;
777 }
778 }
779 }
780}
781
782
783/* ---------------------------------------------------------------------
784 LOW LEVEL STUFF TO DO WITH SIGNALS: IMPLEMENTATION
785 ------------------------------------------------------------------ */
sewardj77e466c2002-04-14 02:29:29 +0000786
sewardj2e93c502002-04-12 11:12:52 +0000787/* ---------------------------------------------------------------------
788 Handy utilities to block/restore all host signals.
789 ------------------------------------------------------------------ */
790
791/* Block all host signals, dumping the old mask in *saved_mask. */
792void VG_(block_all_host_signals) ( /* OUT */ vki_ksigset_t* saved_mask )
793{
794 Int ret;
795 vki_ksigset_t block_procmask;
796 VG_(ksigfillset)(&block_procmask);
797 ret = VG_(ksigprocmask)
798 (VKI_SIG_SETMASK, &block_procmask, saved_mask);
799 vg_assert(ret == 0);
800}
801
802/* Restore the blocking mask using the supplied saved one. */
sewardj018f7622002-05-15 21:13:39 +0000803void VG_(restore_all_host_signals) ( /* IN */ vki_ksigset_t* saved_mask )
sewardj2e93c502002-04-12 11:12:52 +0000804{
805 Int ret;
806 ret = VG_(ksigprocmask)(VKI_SIG_SETMASK, saved_mask, NULL);
807 vg_assert(ret == 0);
808}
sewardjde4a1d02002-03-22 01:27:54 +0000809
810
811/* ---------------------------------------------------------------------
812 The signal simulation proper. A simplified version of what the
813 Linux kernel does.
814 ------------------------------------------------------------------ */
815
816/* A structure in which to save the application's registers
817 during the execution of signal handlers. */
818
819typedef
820 struct {
sewardj2e93c502002-04-12 11:12:52 +0000821 /* These are parameters to the signal handler. */
822 UInt retaddr; /* Sig handler's (bogus) return address */
823 Int sigNo; /* The arg to the sig handler. */
824 Addr psigInfo; /* ptr to siginfo_t; NULL for now. */
825 Addr puContext; /* ptr to ucontext; NULL for now. */
826 /* Sanity check word. */
sewardjde4a1d02002-03-22 01:27:54 +0000827 UInt magicPI;
sewardj2e93c502002-04-12 11:12:52 +0000828 /* Saved processor state. */
sewardjde4a1d02002-03-22 01:27:54 +0000829 UInt fpustate[VG_SIZE_OF_FPUSTATE_W];
830 UInt eax;
831 UInt ecx;
832 UInt edx;
833 UInt ebx;
834 UInt ebp;
835 UInt esp;
836 UInt esi;
837 UInt edi;
838 Addr eip;
839 UInt eflags;
sewardj2e93c502002-04-12 11:12:52 +0000840 /* Scheduler-private stuff: what was the thread's status prior to
841 delivering this signal? */
842 ThreadStatus status;
843 /* Sanity check word. Is the highest-addressed word; do not
844 move!*/
sewardjde4a1d02002-03-22 01:27:54 +0000845 UInt magicE;
846 }
sewardj2e93c502002-04-12 11:12:52 +0000847 VgSigFrame;
sewardjde4a1d02002-03-22 01:27:54 +0000848
849
850
sewardjde4a1d02002-03-22 01:27:54 +0000851/* Set up a stack frame (VgSigContext) for the client's signal
852 handler. This includes the signal number and a bogus return
853 address. */
854static
sewardj2e93c502002-04-12 11:12:52 +0000855void vg_push_signal_frame ( ThreadId tid, int sigNo )
sewardjde4a1d02002-03-22 01:27:54 +0000856{
857 Int i;
sewardj2342c972002-05-22 23:34:20 +0000858 Addr esp, esp_top_of_frame;
sewardj2e93c502002-04-12 11:12:52 +0000859 VgSigFrame* frame;
860 ThreadState* tst;
861
sewardj2342c972002-05-22 23:34:20 +0000862 vg_assert(sigNo >= 1 && sigNo <= VKI_KNSIG);
sewardj018f7622002-05-15 21:13:39 +0000863 vg_assert(VG_(is_valid_tid)(tid));
864 tst = & VG_(threads)[tid];
sewardj2e93c502002-04-12 11:12:52 +0000865
sewardj2342c972002-05-22 23:34:20 +0000866 if (/* this signal asked to run on an alt stack */
867 (vg_scss.scss_per_sig[sigNo].scss_flags & VKI_SA_ONSTACK)
868 && /* there is a defined and enabled alt stack, which we're not
869 already using. Logic from get_sigframe in
870 arch/i386/kernel/signal.c. */
871 sas_ss_flags(tst->m_esp) == 0
872 ) {
873 esp_top_of_frame
874 = (Addr)(vg_scss.altstack.ss_sp) + vg_scss.altstack.ss_size;
875 if (VG_(clo_trace_signals))
876 VG_(message)(Vg_DebugMsg,
877 "delivering signal %d to thread %d: on ALT STACK",
878 sigNo, tid );
879 } else {
880 esp_top_of_frame = tst->m_esp;
881 }
882
883 esp = esp_top_of_frame;
sewardj2e93c502002-04-12 11:12:52 +0000884 esp -= sizeof(VgSigFrame);
885 frame = (VgSigFrame*)esp;
886 /* Assert that the frame is placed correctly. */
887 vg_assert( (sizeof(VgSigFrame) & 0x3) == 0 );
888 vg_assert( ((Char*)(&frame->magicE)) + sizeof(UInt)
sewardj2342c972002-05-22 23:34:20 +0000889 == ((Char*)(esp_top_of_frame)) );
sewardj2e93c502002-04-12 11:12:52 +0000890
891 frame->retaddr = (UInt)(&VG_(signalreturn_bogusRA));
892 frame->sigNo = sigNo;
893 frame->psigInfo = (Addr)NULL;
894 frame->puContext = (Addr)NULL;
895 frame->magicPI = 0x31415927;
896
sewardjde4a1d02002-03-22 01:27:54 +0000897 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj2e93c502002-04-12 11:12:52 +0000898 frame->fpustate[i] = tst->m_fpu[i];
sewardjde4a1d02002-03-22 01:27:54 +0000899
sewardj2e93c502002-04-12 11:12:52 +0000900 frame->eax = tst->m_eax;
901 frame->ecx = tst->m_ecx;
902 frame->edx = tst->m_edx;
903 frame->ebx = tst->m_ebx;
904 frame->ebp = tst->m_ebp;
905 frame->esp = tst->m_esp;
906 frame->esi = tst->m_esi;
907 frame->edi = tst->m_edi;
908 frame->eip = tst->m_eip;
909 frame->eflags = tst->m_eflags;
sewardjde4a1d02002-03-22 01:27:54 +0000910
sewardj2e93c502002-04-12 11:12:52 +0000911 frame->status = tst->status;
sewardjde4a1d02002-03-22 01:27:54 +0000912
sewardj2e93c502002-04-12 11:12:52 +0000913 frame->magicE = 0x27182818;
914
915 /* Set the thread so it will next run the handler. */
916 tst->m_esp = esp;
sewardj018f7622002-05-15 21:13:39 +0000917 tst->m_eip = (Addr)vg_scss.scss_per_sig[sigNo].scss_handler;
sewardj2e93c502002-04-12 11:12:52 +0000918 /* This thread needs to be marked runnable, but we leave that the
919 caller to do. */
sewardjde4a1d02002-03-22 01:27:54 +0000920
921 /* Make sigNo and retaddr fields readable -- at 0(%ESP) and 4(%ESP) */
922 if (VG_(clo_instrument)) {
923 VGM_(make_readable) ( ((Addr)esp)+0 ,4 );
924 VGM_(make_readable) ( ((Addr)esp)+4 ,4 );
925 }
926
sewardjde4a1d02002-03-22 01:27:54 +0000927 /*
928 VG_(printf)("pushed signal frame; %%ESP now = %p, next %%EBP = %p\n",
sewardj2e93c502002-04-12 11:12:52 +0000929 esp, tst->m_eip);
sewardjde4a1d02002-03-22 01:27:54 +0000930 */
931}
932
933
934/* Clear the signal frame created by vg_push_signal_frame, restore the
935 simulated machine state, and return the signal number that the
936 frame was for. */
937static
sewardj2e93c502002-04-12 11:12:52 +0000938Int vg_pop_signal_frame ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000939{
sewardj2e93c502002-04-12 11:12:52 +0000940 Addr esp;
sewardjde4a1d02002-03-22 01:27:54 +0000941 Int sigNo, i;
sewardj2e93c502002-04-12 11:12:52 +0000942 VgSigFrame* frame;
943 ThreadState* tst;
sewardjde4a1d02002-03-22 01:27:54 +0000944
sewardj018f7622002-05-15 21:13:39 +0000945 vg_assert(VG_(is_valid_tid)(tid));
946 tst = & VG_(threads)[tid];
sewardj2e93c502002-04-12 11:12:52 +0000947
sewardj54cacf02002-04-12 23:24:59 +0000948 /* Correctly reestablish the frame base address. */
sewardj2e93c502002-04-12 11:12:52 +0000949 esp = tst->m_esp;
sewardj54cacf02002-04-12 23:24:59 +0000950 frame = (VgSigFrame*)
951 (esp -4 /* because the handler's RET pops the RA */
952 +20 /* because signalreturn_bogusRA pushes 5 words */);
sewardj2e93c502002-04-12 11:12:52 +0000953
954 vg_assert(frame->magicPI == 0x31415927);
955 vg_assert(frame->magicE == 0x27182818);
sewardjde4a1d02002-03-22 01:27:54 +0000956 if (VG_(clo_trace_signals))
sewardjb48e5002002-05-13 00:16:03 +0000957 VG_(message)(Vg_DebugMsg,
958 "vg_pop_signal_frame (thread %d): valid magic", tid);
sewardjde4a1d02002-03-22 01:27:54 +0000959
960 /* restore machine state */
961 for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
sewardj2e93c502002-04-12 11:12:52 +0000962 tst->m_fpu[i] = frame->fpustate[i];
sewardjde4a1d02002-03-22 01:27:54 +0000963
sewardj2342c972002-05-22 23:34:20 +0000964 /* Mark the frame structure as nonaccessible. */
965 if (VG_(clo_instrument))
966 VGM_(make_noaccess)( (Addr)frame, sizeof(VgSigFrame) );
sewardjde4a1d02002-03-22 01:27:54 +0000967
968 /* Restore machine state from the saved context. */
sewardj2e93c502002-04-12 11:12:52 +0000969 tst->m_eax = frame->eax;
970 tst->m_ecx = frame->ecx;
971 tst->m_edx = frame->edx;
972 tst->m_ebx = frame->ebx;
973 tst->m_ebp = frame->ebp;
974 tst->m_esp = frame->esp;
975 tst->m_esi = frame->esi;
976 tst->m_edi = frame->edi;
977 tst->m_eflags = frame->eflags;
978 tst->m_eip = frame->eip;
979 sigNo = frame->sigNo;
980
981 /* And restore the thread's status to what it was before the signal
982 was delivered. */
983 tst->status = frame->status;
984
sewardjde4a1d02002-03-22 01:27:54 +0000985 return sigNo;
986}
987
988
989/* A handler is returning. Restore the machine state from the stacked
990 VgSigContext and continue with whatever was going on before the
sewardj77e466c2002-04-14 02:29:29 +0000991 handler ran. Returns the SA_RESTART syscall-restartability-status
992 of the delivered signal. */
sewardjde4a1d02002-03-22 01:27:54 +0000993
sewardj77e466c2002-04-14 02:29:29 +0000994Bool VG_(signal_returns) ( ThreadId tid )
sewardjde4a1d02002-03-22 01:27:54 +0000995{
sewardj2e93c502002-04-12 11:12:52 +0000996 Int sigNo;
sewardjde4a1d02002-03-22 01:27:54 +0000997 vki_ksigset_t saved_procmask;
998
999 /* Block host signals ... */
sewardj2e93c502002-04-12 11:12:52 +00001000 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +00001001
sewardj2e93c502002-04-12 11:12:52 +00001002 /* Pop the signal frame and restore tid's status to what it was
1003 before the signal was delivered. */
1004 sigNo = vg_pop_signal_frame(tid);
sewardjde4a1d02002-03-22 01:27:54 +00001005
sewardjb48e5002002-05-13 00:16:03 +00001006 vg_assert(sigNo >= 1 && sigNo <= VKI_KNSIG);
sewardjde4a1d02002-03-22 01:27:54 +00001007
1008 /* Unlock and return. */
sewardj018f7622002-05-15 21:13:39 +00001009 VG_(restore_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +00001010
sewardj77e466c2002-04-14 02:29:29 +00001011 /* Scheduler now can resume this thread, or perhaps some other.
1012 Tell the scheduler whether or not any syscall interrupted by
1013 this signal should be restarted, if possible, or no. */
sewardj018f7622002-05-15 21:13:39 +00001014 return
1015 (vg_scss.scss_per_sig[sigNo].scss_flags & VKI_SA_RESTART)
1016 ? True
1017 : False;
sewardjde4a1d02002-03-22 01:27:54 +00001018}
1019
1020
1021/* Deliver all pending signals, by building stack frames for their
sewardj14e03422002-04-24 19:51:31 +00001022 handlers. Return True if any signals were delivered. */
sewardjb48e5002002-05-13 00:16:03 +00001023Bool VG_(deliver_signals) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001024{
sewardjde4a1d02002-03-22 01:27:54 +00001025 vki_ksigset_t saved_procmask;
sewardj2e93c502002-04-12 11:12:52 +00001026 Int sigNo;
sewardj018f7622002-05-15 21:13:39 +00001027 Bool found, scss_changed;
sewardjb48e5002002-05-13 00:16:03 +00001028 ThreadState* tst;
1029 ThreadId tid;
1030
sewardj018f7622002-05-15 21:13:39 +00001031 /* A cheap check. We don't need to have exclusive access to the
1032 pending array, because in the worst case, vg_oursignalhandler
1033 will add signals, causing us to return, thinking there are no
1034 signals to deliver, when in fact there are some. A subsequent
1035 call here will handle the signal(s) we missed. */
sewardjde4a1d02002-03-22 01:27:54 +00001036 found = False;
sewardjb48e5002002-05-13 00:16:03 +00001037 for (sigNo = 1; sigNo <= VKI_KNSIG; sigNo++)
sewardj018f7622002-05-15 21:13:39 +00001038 if (vg_dcss.dcss_sigpending[sigNo])
sewardjb48e5002002-05-13 00:16:03 +00001039 found = True;
sewardjde4a1d02002-03-22 01:27:54 +00001040
sewardj14e03422002-04-24 19:51:31 +00001041 if (!found) return False;
sewardjde4a1d02002-03-22 01:27:54 +00001042
1043 /* Now we have to do it properly. Get exclusive access by
1044 blocking all the host's signals. That means vg_oursignalhandler
1045 can't run whilst we are messing with stuff.
1046 */
sewardj018f7622002-05-15 21:13:39 +00001047 scss_changed = False;
sewardj2e93c502002-04-12 11:12:52 +00001048 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +00001049
sewardj2e93c502002-04-12 11:12:52 +00001050 /* Look for signals to deliver ... */
sewardjb48e5002002-05-13 00:16:03 +00001051 for (sigNo = 1; sigNo <= VKI_KNSIG; sigNo++) {
sewardj018f7622002-05-15 21:13:39 +00001052
1053 if (!vg_dcss.dcss_sigpending[sigNo])
1054 continue;
1055
sewardjb48e5002002-05-13 00:16:03 +00001056 /* sigNo is pending. Try to find a suitable thread to deliver
1057 it to. */
sewardjb48e5002002-05-13 00:16:03 +00001058 /* First off, are any threads in sigwait() for the signal?
1059 If so just give to one of them and have done. */
1060 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +00001061 tst = & VG_(threads)[tid];
sewardjb48e5002002-05-13 00:16:03 +00001062 if (tst->status != VgTs_WaitSIG)
1063 continue;
1064 if (VG_(ksigismember)(&(tst->sigs_waited_for), sigNo))
1065 break;
1066 }
1067 if (tid < VG_N_THREADS) {
1068 UInt* sigwait_args;
sewardj018f7622002-05-15 21:13:39 +00001069 tst = & VG_(threads)[tid];
sewardjb48e5002002-05-13 00:16:03 +00001070 if (VG_(clo_trace_signals) || VG_(clo_trace_sched))
1071 VG_(message)(Vg_DebugMsg,
1072 "releasing thread %d from sigwait() due to signal %d",
1073 tid, sigNo );
1074 sigwait_args = (UInt*)(tst->m_eax);
1075 if (NULL != (UInt*)(sigwait_args[2])) {
1076 *(Int*)(sigwait_args[2]) = sigNo;
1077 if (VG_(clo_instrument))
sewardj018f7622002-05-15 21:13:39 +00001078 VGM_(make_readable)( (Addr)(sigwait_args[2]),
1079 sizeof(UInt));
sewardjb48e5002002-05-13 00:16:03 +00001080 }
sewardj018f7622002-05-15 21:13:39 +00001081 SET_EDX(tid, 0);
sewardjb48e5002002-05-13 00:16:03 +00001082 tst->status = VgTs_Runnable;
sewardj811d1412002-05-13 00:38:52 +00001083 VG_(ksigemptyset)(&tst->sigs_waited_for);
sewardj018f7622002-05-15 21:13:39 +00001084 scss_changed = True;
1085 vg_dcss.dcss_sigpending[sigNo] = False;
1086 vg_dcss.dcss_destthread[sigNo] = VG_INVALID_THREADID;
1087 /*paranoia*/
sewardjb48e5002002-05-13 00:16:03 +00001088 continue; /* for (sigNo = 1; ...) loop */
1089 }
1090
1091 /* Well, nobody appears to be sigwaiting for it. So we really
sewardj018f7622002-05-15 21:13:39 +00001092 are delivering the signal in the usual way. And that the
1093 client really has a handler for this thread! */
1094 vg_assert(vg_dcss.dcss_sigpending[sigNo]);
1095 vg_assert(vg_scss.scss_per_sig[sigNo].scss_handler != VKI_SIG_IGN
1096 && vg_scss.scss_per_sig[sigNo].scss_handler != VKI_SIG_DFL);
sewardjb48e5002002-05-13 00:16:03 +00001097
sewardj018f7622002-05-15 21:13:39 +00001098 tid = vg_dcss.dcss_destthread[sigNo];
sewardjb48e5002002-05-13 00:16:03 +00001099 vg_assert(tid == VG_INVALID_THREADID
1100 || VG_(is_valid_tid)(tid));
1101
1102 if (tid != VG_INVALID_THREADID) {
1103 /* directed to a specific thread; ensure it actually still
1104 exists ... */
sewardj018f7622002-05-15 21:13:39 +00001105 tst = & VG_(threads)[tid];
sewardjb48e5002002-05-13 00:16:03 +00001106 if (tst->status == VgTs_Empty) {
1107 /* dead, for whatever reason; ignore this signal */
1108 if (VG_(clo_trace_signals))
1109 VG_(message)(Vg_DebugMsg,
1110 "discarding signal %d for nonexistent thread %d",
1111 sigNo, tid );
sewardj018f7622002-05-15 21:13:39 +00001112 vg_dcss.dcss_sigpending[sigNo] = False;
1113 vg_dcss.dcss_destthread[sigNo] = VG_INVALID_THREADID;
sewardjb48e5002002-05-13 00:16:03 +00001114 continue; /* for (sigNo = 1; ...) loop */
1115 }
1116 } else {
1117 /* not directed to a specific thread, so search for a
1118 suitable candidate */
1119 for (tid = 1; tid < VG_N_THREADS; tid++) {
sewardj018f7622002-05-15 21:13:39 +00001120 tst = & VG_(threads)[tid];
sewardjb48e5002002-05-13 00:16:03 +00001121 if (tst->status != VgTs_Empty
1122 && !VG_(ksigismember)(&(tst->sig_mask), sigNo))
1123 break;
1124 }
1125 if (tid == VG_N_THREADS)
1126 /* All threads have this signal blocked, so we can't
1127 deliver it just now */
1128 continue; /* for (sigNo = 1; ...) loop */
1129 }
1130
1131 /* Ok, we can deliver signal sigNo to thread tid. */
sewardjde4a1d02002-03-22 01:27:54 +00001132
1133 if (VG_(clo_trace_signals))
sewardjb48e5002002-05-13 00:16:03 +00001134 VG_(message)(Vg_DebugMsg,"delivering signal %d to thread %d",
1135 sigNo, tid );
sewardjde4a1d02002-03-22 01:27:54 +00001136
1137 /* Create a signal delivery frame, and set the client's %ESP and
1138 %EIP so that when execution continues, we will enter the
1139 signal handler with the frame on top of the client's stack,
1140 as it expects. */
sewardjb48e5002002-05-13 00:16:03 +00001141 vg_assert(VG_(is_valid_tid)(tid));
sewardj2e93c502002-04-12 11:12:52 +00001142 vg_push_signal_frame ( tid, sigNo );
sewardj018f7622002-05-15 21:13:39 +00001143 VG_(threads)[tid].status = VgTs_Runnable;
sewardj2e93c502002-04-12 11:12:52 +00001144
sewardjde4a1d02002-03-22 01:27:54 +00001145 /* Signify that the signal has been delivered. */
sewardj018f7622002-05-15 21:13:39 +00001146 vg_dcss.dcss_sigpending[sigNo] = False;
1147 vg_dcss.dcss_destthread[sigNo] = VG_INVALID_THREADID;
1148
1149 if (vg_scss.scss_per_sig[sigNo].scss_flags & VKI_SA_ONESHOT) {
1150 /* Do the ONESHOT thing. */
1151 vg_scss.scss_per_sig[sigNo].scss_handler = VKI_SIG_DFL;
1152 scss_changed = True;
1153 }
sewardjde4a1d02002-03-22 01:27:54 +00001154 }
1155
1156 /* Unlock and return. */
sewardj018f7622002-05-15 21:13:39 +00001157 if (scss_changed) {
1158 /* handle_SCSS_change computes a new kernel blocking mask and
1159 applies that. */
1160 VG_(handle_SCSS_change)( False /* lazy update */ );
1161 } else {
1162 /* No SCSS change, so just restore the existing blocking
1163 mask. */
1164 VG_(restore_all_host_signals)( &saved_procmask );
sewardjb48e5002002-05-13 00:16:03 +00001165 }
sewardj018f7622002-05-15 21:13:39 +00001166
1167 return True;
sewardjb48e5002002-05-13 00:16:03 +00001168}
1169
1170
sewardjde4a1d02002-03-22 01:27:54 +00001171/* Receive a signal from the host, and either discard it or park it in
1172 the queue of pending signals. All other signals will be blocked
1173 when this handler runs. Runs with all host signals blocked, so as
1174 to have mutual exclusion when adding stuff to the queue. */
1175
sewardjb48e5002002-05-13 00:16:03 +00001176static
sewardj018f7622002-05-15 21:13:39 +00001177void vg_oursignalhandler ( Int sigNo )
sewardjde4a1d02002-03-22 01:27:54 +00001178{
sewardj018f7622002-05-15 21:13:39 +00001179 ThreadId tid;
sewardj2e93c502002-04-12 11:12:52 +00001180 Int dummy_local;
sewardj018f7622002-05-15 21:13:39 +00001181 Bool sane;
sewardjde4a1d02002-03-22 01:27:54 +00001182 vki_ksigset_t saved_procmask;
1183
sewardj7a61d912002-04-25 01:27:35 +00001184 /*
1185 if (sigNo == VKI_SIGUSR1) {
1186 VG_(printf)("YOWZA! SIGUSR1\n\n");
1187 VG_(clo_trace_pthread_level) = 2;
1188 VG_(clo_trace_sched) = True;
1189 VG_(clo_trace_syscalls) = True;
1190 VG_(clo_trace_signals) = True;
1191 return;
1192 }
1193 */
1194
sewardjde4a1d02002-03-22 01:27:54 +00001195 if (VG_(clo_trace_signals)) {
1196 VG_(start_msg)(Vg_DebugMsg);
1197 VG_(add_to_msg)("signal %d arrived ... ", sigNo );
1198 }
sewardjb48e5002002-05-13 00:16:03 +00001199 vg_assert(sigNo >= 1 && sigNo <= VKI_KNSIG);
sewardjde4a1d02002-03-22 01:27:54 +00001200
1201 /* Sanity check. Ensure we're really running on the signal stack
1202 we asked for. */
1203 if ( !(
sewardj2e93c502002-04-12 11:12:52 +00001204 ((Char*)(&(VG_(sigstack)[0])) <= (Char*)(&dummy_local))
sewardjde4a1d02002-03-22 01:27:54 +00001205 &&
sewardj2e93c502002-04-12 11:12:52 +00001206 ((Char*)(&dummy_local) < (Char*)(&(VG_(sigstack)[10000])))
sewardjde4a1d02002-03-22 01:27:54 +00001207 )
1208 ) {
sewardj2e93c502002-04-12 11:12:52 +00001209 VG_(message)(Vg_DebugMsg,
1210 "FATAL: signal delivered on the wrong stack?!");
1211 VG_(message)(Vg_DebugMsg,
1212 "A possible workaround follows. Please tell me");
1213 VG_(message)(Vg_DebugMsg,
1214 "(jseward@acm.org) if the suggested workaround doesn't help.");
sewardjde4a1d02002-03-22 01:27:54 +00001215 VG_(unimplemented)
sewardj2e93c502002-04-12 11:12:52 +00001216 ("support for progs compiled with -p/-pg; "
1217 "rebuild your prog without -p/-pg");
sewardjde4a1d02002-03-22 01:27:54 +00001218 }
1219
sewardj2e93c502002-04-12 11:12:52 +00001220 vg_assert((Char*)(&(VG_(sigstack)[0])) <= (Char*)(&dummy_local));
1221 vg_assert((Char*)(&dummy_local) < (Char*)(&(VG_(sigstack)[10000])));
sewardjde4a1d02002-03-22 01:27:54 +00001222
sewardj2e93c502002-04-12 11:12:52 +00001223 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +00001224
sewardj018f7622002-05-15 21:13:39 +00001225 /* This is a sanity check. Either a signal has arrived because the
1226 client set a handler for it, or because some thread sigwaited on
1227 it. Establish that at least one of these is the case. */
1228 sane = False;
1229 if (vg_scss.scss_per_sig[sigNo].scss_handler != VKI_SIG_DFL
1230 && vg_scss.scss_per_sig[sigNo].scss_handler != VKI_SIG_IGN) {
1231 sane = True;
1232 } else {
1233 for (tid = 1; tid < VG_N_THREADS; tid++) {
1234 if (VG_(threads)[tid].status != VgTs_WaitSIG)
1235 continue;
1236 if (VG_(ksigismember)(&VG_(threads)[tid].sigs_waited_for, sigNo))
1237 sane = True;
1238 }
1239 }
1240 if (!sane) {
sewardjde4a1d02002-03-22 01:27:54 +00001241 if (VG_(clo_trace_signals)) {
1242 VG_(add_to_msg)("unexpected!");
1243 VG_(end_msg)();
1244 }
sewardj2e93c502002-04-12 11:12:52 +00001245 /* Note: we panic with all signals blocked here. Don't think
1246 that matters. */
sewardjde4a1d02002-03-22 01:27:54 +00001247 VG_(panic)("vg_oursignalhandler: unexpected signal");
1248 }
sewardj018f7622002-05-15 21:13:39 +00001249 /* End of the sanity check. */
sewardjde4a1d02002-03-22 01:27:54 +00001250
1251 /* Decide what to do with it. */
sewardj018f7622002-05-15 21:13:39 +00001252 if (vg_dcss.dcss_sigpending[sigNo]) {
1253 /* pending; ignore it. */
sewardjde4a1d02002-03-22 01:27:54 +00001254 if (VG_(clo_trace_signals)) {
1255 VG_(add_to_msg)("already pending; discarded" );
1256 VG_(end_msg)();
1257 }
sewardj018f7622002-05-15 21:13:39 +00001258 } else {
sewardj2e93c502002-04-12 11:12:52 +00001259 /* Ok, we'd better deliver it to the client. */
sewardj2e93c502002-04-12 11:12:52 +00001260 /* Queue it up for delivery at some point in the future. */
sewardj018f7622002-05-15 21:13:39 +00001261 vg_dcss.dcss_sigpending[sigNo] = True;
1262 vg_dcss.dcss_destthread[sigNo] = VG_INVALID_THREADID;
sewardj2e93c502002-04-12 11:12:52 +00001263 if (VG_(clo_trace_signals)) {
1264 VG_(add_to_msg)("queued" );
1265 VG_(end_msg)();
sewardjde4a1d02002-03-22 01:27:54 +00001266 }
1267 }
1268
sewardj2e93c502002-04-12 11:12:52 +00001269 /* We've finished messing with the queue, so re-enable host
1270 signals. */
sewardj018f7622002-05-15 21:13:39 +00001271 VG_(restore_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +00001272
sewardj018f7622002-05-15 21:13:39 +00001273 if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS
1274 || sigNo == VKI_SIGFPE || sigNo == VKI_SIGILL) {
sewardj2e93c502002-04-12 11:12:52 +00001275 /* Can't continue; must longjmp back to the scheduler and thus
1276 enter the sighandler immediately. */
sewardjde4a1d02002-03-22 01:27:54 +00001277 VG_(longjmpd_on_signal) = sigNo;
sewardj2e93c502002-04-12 11:12:52 +00001278 __builtin_longjmp(VG_(scheduler_jmpbuf),1);
sewardjde4a1d02002-03-22 01:27:54 +00001279 }
1280}
1281
1282
1283/* The outer insn loop calls here to reenable a host signal if
1284 vg_oursighandler longjmp'd.
1285*/
1286void VG_(unblock_host_signal) ( Int sigNo )
1287{
1288 Int ret;
1289 vki_ksigset_t set;
1290 VG_(ksigemptyset)(&set);
1291 ret = VG_(ksigaddset)(&set,sigNo);
1292 vg_assert(ret == 0);
1293 ret = VG_(ksigprocmask)(VKI_SIG_UNBLOCK,&set,NULL);
1294 vg_assert(ret == 0);
1295}
1296
1297
1298static __attribute((unused))
1299void pp_vg_ksigaction ( vki_ksigaction* sa )
1300{
1301 Int i;
1302 VG_(printf)("vg_ksigaction: handler %p, flags 0x%x, restorer %p\n",
sewardj9a199dc2002-04-14 13:01:38 +00001303 sa->ksa_handler, (UInt)sa->ksa_flags, sa->ksa_restorer);
sewardjde4a1d02002-03-22 01:27:54 +00001304 VG_(printf)("vg_ksigaction: { ");
sewardjb48e5002002-05-13 00:16:03 +00001305 for (i = 1; i <= VKI_KNSIG; i++)
sewardjde4a1d02002-03-22 01:27:54 +00001306 if (VG_(ksigismember(&(sa->ksa_mask),i)))
1307 VG_(printf)("%d ", i);
1308 VG_(printf)("}\n");
1309}
1310
1311
sewardj018f7622002-05-15 21:13:39 +00001312/* At startup, copy the process' real signal state to the SCSS.
1313 Whilst doing this, block all real signals. Then calculate SKSS and
1314 set the kernel to that. Also initialise DCSS.
sewardjde4a1d02002-03-22 01:27:54 +00001315*/
1316void VG_(sigstartup_actions) ( void )
1317{
1318 Int i, ret;
1319
sewardjde4a1d02002-03-22 01:27:54 +00001320 vki_ksigset_t saved_procmask;
1321 vki_kstack_t altstack_info;
1322 vki_ksigaction sa;
1323
sewardj2e93c502002-04-12 11:12:52 +00001324 /* VG_(printf)("SIGSTARTUP\n"); */
sewardjde4a1d02002-03-22 01:27:54 +00001325 /* Block all signals.
1326 saved_procmask remembers the previous mask. */
sewardj2e93c502002-04-12 11:12:52 +00001327 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +00001328
sewardj018f7622002-05-15 21:13:39 +00001329 /* Copy per-signal settings to SCSS. */
1330 for (i = 1; i <= VKI_KNSIG; i++) {
1331
1332 /* Get the old host action */
1333 ret = VG_(ksigaction)(i, NULL, &sa);
1334 vg_assert(ret == 0);
1335
1336 if (VG_(clo_trace_signals))
1337 VG_(printf)("snaffling handler 0x%x for signal %d\n",
1338 (Addr)(sa.ksa_handler), i );
1339
1340 vg_scss.scss_per_sig[i].scss_handler = sa.ksa_handler;
1341 vg_scss.scss_per_sig[i].scss_flags = sa.ksa_flags;
1342 vg_scss.scss_per_sig[i].scss_mask = sa.ksa_mask;
1343 vg_scss.scss_per_sig[i].scss_restorer = sa.ksa_restorer;
1344 }
1345
sewardj2342c972002-05-22 23:34:20 +00001346 /* Copy the alt stack, if any. */
1347 ret = VG_(ksigaltstack)(NULL, &vg_scss.altstack);
1348 vg_assert(ret == 0);
1349
sewardj018f7622002-05-15 21:13:39 +00001350 /* Copy the process' signal mask into the root thread. */
1351 vg_assert(VG_(threads)[1].status == VgTs_Runnable);
1352 VG_(threads)[1].sig_mask = saved_procmask;
1353
1354 /* Initialise DCSS. */
1355 for (i = 1; i <= VKI_KNSIG; i++) {
1356 vg_dcss.dcss_sigpending[i] = False;
1357 vg_dcss.dcss_destthread[i] = VG_INVALID_THREADID;
1358 }
1359
sewardjde4a1d02002-03-22 01:27:54 +00001360 /* Register an alternative stack for our own signal handler to run
1361 on. */
1362 altstack_info.ss_sp = &(VG_(sigstack)[0]);
1363 altstack_info.ss_size = 10000 * sizeof(UInt);
1364 altstack_info.ss_flags = 0;
1365 ret = VG_(ksigaltstack)(&altstack_info, NULL);
1366 if (ret != 0) {
1367 VG_(panic)(
1368 "vg_sigstartup_actions: couldn't install alternative sigstack");
1369 }
1370 if (VG_(clo_trace_signals)) {
1371 VG_(message)(Vg_DebugExtraMsg,
1372 "vg_sigstartup_actions: sigstack installed ok");
1373 }
1374
sewardj7a61d912002-04-25 01:27:35 +00001375 /* DEBUGGING HACK */
1376 /* VG_(ksignal)(VKI_SIGUSR1, &VG_(oursignalhandler)); */
1377
sewardj018f7622002-05-15 21:13:39 +00001378 /* Calculate SKSS and apply it. This also sets the initial kernel
1379 mask we need to run with. */
1380 VG_(handle_SCSS_change)( True /* forced update */ );
sewardjde4a1d02002-03-22 01:27:54 +00001381}
1382
1383
1384/* Copy the process' sim signal state to the real state,
1385 for when we transfer from the simulated to real CPU.
1386 PROBLEM: what if we're running a signal handler when we
1387 get here? Hmm.
1388 I guess we wind up in vg_signalreturn_bogusRA, *or* the
1389 handler has done/will do a longjmp, in which case we're ok.
1390
1391 It is important (see vg_startup.S) that this proc does not
1392 change the state of the real FPU, since it is called when
1393 running the program on the real CPU.
1394*/
1395void VG_(sigshutdown_actions) ( void )
1396{
1397 Int i, ret;
1398
sewardjde4a1d02002-03-22 01:27:54 +00001399 vki_ksigset_t saved_procmask;
1400 vki_ksigaction sa;
1401
sewardj2e93c502002-04-12 11:12:52 +00001402 VG_(block_all_host_signals)( &saved_procmask );
sewardjde4a1d02002-03-22 01:27:54 +00001403
sewardj018f7622002-05-15 21:13:39 +00001404 /* Copy per-signal settings from SCSS. */
sewardjb48e5002002-05-13 00:16:03 +00001405 for (i = 1; i <= VKI_KNSIG; i++) {
sewardj018f7622002-05-15 21:13:39 +00001406
1407 sa.ksa_handler = vg_scss.scss_per_sig[i].scss_handler;
1408 sa.ksa_flags = vg_scss.scss_per_sig[i].scss_flags;
1409 sa.ksa_mask = vg_scss.scss_per_sig[i].scss_mask;
1410 sa.ksa_restorer = vg_scss.scss_per_sig[i].scss_restorer;
1411
1412 if (VG_(clo_trace_signals))
1413 VG_(printf)("restoring handler 0x%x for signal %d\n",
1414 (Addr)(sa.ksa_handler), i );
1415
1416 /* Get the old host action */
1417 ret = VG_(ksigaction)(i, &sa, NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001418 vg_assert(ret == 0);
sewardj018f7622002-05-15 21:13:39 +00001419
sewardjde4a1d02002-03-22 01:27:54 +00001420 }
1421
sewardj2342c972002-05-22 23:34:20 +00001422 /* Restore the sig alt stack. */
1423 ret = VG_(ksigaltstack)(&vg_scss.altstack, NULL);
1424 vg_assert(ret == 0);
1425
sewardj018f7622002-05-15 21:13:39 +00001426 /* A bit of a kludge -- set the sigmask to that of the root
1427 thread. */
1428 vg_assert(VG_(threads)[1].status != VgTs_Empty);
1429 VG_(restore_all_host_signals)( &VG_(threads)[1].sig_mask );
sewardjde4a1d02002-03-22 01:27:54 +00001430}
1431
1432
sewardjde4a1d02002-03-22 01:27:54 +00001433/*--------------------------------------------------------------------*/
1434/*--- end vg_signals.c ---*/
1435/*--------------------------------------------------------------------*/