drd: Add a consistency check
[valgrind.git] / coregrind / m_libcsignal.c
bloba380f05f684849f202bb4b7e77e8efe7bcf0cfd8
2 /*--------------------------------------------------------------------*/
3 /*--- Signal-related libc stuff. m_libcsignal.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2000-2013 Julian Seward
11 jseward@acm.org
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
28 The GNU General Public License is contained in the file COPYING.
31 #include "pub_core_basics.h"
32 #include "pub_core_debuglog.h"
33 #include "pub_core_vki.h"
34 #include "pub_core_vkiscnums.h"
35 #include "pub_core_libcbase.h"
36 #include "pub_core_libcassert.h"
37 #include "pub_core_syscall.h"
38 #include "pub_core_libcsignal.h" /* self */
40 /* IMPORTANT: on Darwin it is essential to use the _nocancel versions
41 of syscalls rather than the vanilla version, if a _nocancel version
42 is available. See docs/internals/Darwin-notes.txt for the reason
43 why. */
45 /* sigemptyset, sigfullset, sigaddset and sigdelset return 0 on
46 success and -1 on error. */
47 /* In the sigset routines below, be aware that _VKI_NSIG_BPW can be
48 either 32 or 64, and hence the sig[] words can either be 32- or
49 64-bits. And which they are it doesn't necessarily follow from the
50 host word size. */
52 Int VG_(sigfillset)( vki_sigset_t* set )
54 Int i;
55 if (set == NULL)
56 return -1;
57 for (i = 0; i < _VKI_NSIG_WORDS; i++)
58 set->sig[i] = ~0;
59 return 0;
62 Int VG_(sigemptyset)( vki_sigset_t* set )
64 Int i;
65 if (set == NULL)
66 return -1;
67 for (i = 0; i < _VKI_NSIG_WORDS; i++)
68 set->sig[i] = 0;
69 return 0;
72 Bool VG_(isemptysigset)( const vki_sigset_t* set )
74 Int i;
75 vg_assert(set != NULL);
76 for (i = 0; i < _VKI_NSIG_WORDS; i++)
77 if (set->sig[i] != 0) return False;
78 return True;
81 Bool VG_(isfullsigset)( const vki_sigset_t* set )
83 Int i;
84 vg_assert(set != NULL);
85 for (i = 0; i < _VKI_NSIG_WORDS; i++)
86 if (set->sig[i] != ~0) return False;
87 return True;
90 Bool VG_(iseqsigset)( const vki_sigset_t* set1, const vki_sigset_t* set2 )
92 Int i;
93 vg_assert(set1 != NULL && set2 != NULL);
94 for (i = 0; i < _VKI_NSIG_WORDS; i++)
95 if (set1->sig[i] != set2->sig[i]) return False;
96 return True;
100 Int VG_(sigaddset)( vki_sigset_t* set, Int signum )
102 if (set == NULL)
103 return -1;
104 if (signum < 1 || signum > _VKI_NSIG)
105 return -1;
106 signum--;
107 set->sig[signum / _VKI_NSIG_BPW] |= (1ULL << (signum % _VKI_NSIG_BPW));
108 return 0;
111 Int VG_(sigdelset)( vki_sigset_t* set, Int signum )
113 if (set == NULL)
114 return -1;
115 if (signum < 1 || signum > _VKI_NSIG)
116 return -1;
117 signum--;
118 set->sig[signum / _VKI_NSIG_BPW] &= ~(1ULL << (signum % _VKI_NSIG_BPW));
119 return 0;
122 Int VG_(sigismember) ( const vki_sigset_t* set, Int signum )
124 if (set == NULL)
125 return 0;
126 if (signum < 1 || signum > _VKI_NSIG)
127 return 0;
128 signum--;
129 if (1 & ((set->sig[signum / _VKI_NSIG_BPW]) >> (signum % _VKI_NSIG_BPW)))
130 return 1;
131 else
132 return 0;
135 /* Add all signals in src to dst. */
136 void VG_(sigaddset_from_set)( vki_sigset_t* dst, const vki_sigset_t* src )
138 Int i;
139 vg_assert(dst != NULL && src != NULL);
140 for (i = 0; i < _VKI_NSIG_WORDS; i++)
141 dst->sig[i] |= src->sig[i];
144 /* Remove all signals in src from dst. */
145 void VG_(sigdelset_from_set)( vki_sigset_t* dst, const vki_sigset_t* src )
147 Int i;
148 vg_assert(dst != NULL && src != NULL);
149 for (i = 0; i < _VKI_NSIG_WORDS; i++)
150 dst->sig[i] &= ~(src->sig[i]);
153 /* dst = dst `intersect` src. */
154 void VG_(sigintersectset)( vki_sigset_t* dst, const vki_sigset_t* src )
156 Int i;
157 vg_assert(dst != NULL && src != NULL);
158 for (i = 0; i < _VKI_NSIG_WORDS; i++)
159 dst->sig[i] &= src->sig[i];
162 /* dst = ~src */
163 void VG_(sigcomplementset)( vki_sigset_t* dst, const vki_sigset_t* src )
165 Int i;
166 vg_assert(dst != NULL && src != NULL);
167 for (i = 0; i < _VKI_NSIG_WORDS; i++)
168 dst->sig[i] = ~ src->sig[i];
172 /* The functions sigaction, sigprocmask, sigpending and sigsuspend
173 return 0 on success and -1 on error.
175 Int VG_(sigprocmask)( Int how, const vki_sigset_t* set, vki_sigset_t* oldset)
177 # if defined(VGO_linux)
178 # if defined(__NR_rt_sigprocmask)
179 SysRes res = VG_(do_syscall4)(__NR_rt_sigprocmask,
180 how, (UWord)set, (UWord)oldset,
181 _VKI_NSIG_WORDS * sizeof(UWord));
182 # else
183 SysRes res = VG_(do_syscall3)(__NR_sigprocmask,
184 how, (UWord)set, (UWord)oldset);
185 # endif
187 # elif defined(VGO_darwin)
188 /* On Darwin, __NR_sigprocmask appears to affect the entire
189 process, not just this thread. Hence need to use
190 __NR___pthread_sigmask instead. */
191 SysRes res = VG_(do_syscall3)(__NR___pthread_sigmask,
192 how, (UWord)set, (UWord)oldset);
193 # else
194 # error "Unknown OS"
195 # endif
196 return sr_isError(res) ? -1 : 0;
200 #if defined(VGO_darwin)
201 /* A helper function for sigaction on Darwin. */
202 static
203 void darwin_signal_demux(void* a1, UWord a2, UWord a3, void* a4, void* a5) {
204 VG_(debugLog)(2, "libcsignal",
205 "PRE demux sig, a2 = %lu, signo = %lu\n", a2, a3);
206 if (a2 == 1)
207 ((void(*)(int))a1) (a3);
208 else
209 ((void(*)(int,void*,void*))a1) (a3,a4,a5);
210 VG_(debugLog)(2, "libcsignal",
211 "POST demux sig, a2 = %lu, signo = %lu\n", a2, a3);
212 VG_(do_syscall2)(__NR_sigreturn, (UWord)a5, 0x1E);
213 /* NOTREACHED */
214 __asm__ __volatile__("ud2");
216 #endif
218 Int VG_(sigaction) ( Int signum,
219 const vki_sigaction_toK_t* act,
220 vki_sigaction_fromK_t* oldact)
222 # if defined(VGO_linux)
223 /* Normal case: vki_sigaction_toK_t and vki_sigaction_fromK_t are
224 identical types. */
225 SysRes res = VG_(do_syscall4)(__NR_rt_sigaction,
226 signum, (UWord)act, (UWord)oldact,
227 _VKI_NSIG_WORDS * sizeof(UWord));
228 return sr_isError(res) ? -1 : 0;
230 # elif defined(VGO_darwin)
231 /* If we're passing a new action to the kernel, make a copy of the
232 new action, install our own sa_tramp field in it, and ignore
233 whatever we were provided with. This is OK because all the
234 sigaction requests come from m_signals, and are not directly
235 what the client program requested, so there is no chance that we
236 will inadvertantly ignore the sa_tramp field requested by the
237 client. (In fact m_signals does ignore it when building signal
238 frames for the client, but that's a completely different
239 matter).
241 If we're receiving an old action from the kernel, be very
242 paranoid and make sure the kernel doesn't trash bits of memory
243 that we don't expect it to. */
244 SysRes res;
246 vki_sigaction_toK_t actCopy;
247 struct {
248 ULong before[2];
249 vki_sigaction_fromK_t oa;
250 ULong after[2];
252 oldactCopy;
254 vki_sigaction_toK_t* real_act;
255 vki_sigaction_fromK_t* real_oldact;
257 real_act = act ? &actCopy : NULL;
258 real_oldact = oldact ? &oldactCopy.oa : NULL;
259 VG_(memset)(&oldactCopy, 0x55, sizeof(oldactCopy));
260 if (real_act) {
261 *real_act = *act;
262 real_act->sa_tramp = (void*)&darwin_signal_demux;
264 res = VG_(do_syscall3)(__NR_sigaction,
265 signum, (UWord)real_act, (UWord)real_oldact);
266 if (real_oldact) {
267 vg_assert(oldactCopy.before[0] == 0x5555555555555555ULL);
268 vg_assert(oldactCopy.before[1] == 0x5555555555555555ULL);
269 vg_assert(oldactCopy.after[0] == 0x5555555555555555ULL);
270 vg_assert(oldactCopy.after[1] == 0x5555555555555555ULL);
271 *oldact = *real_oldact;
273 return sr_isError(res) ? -1 : 0;
275 # else
276 # error "Unsupported OS"
277 # endif
281 /* See explanation in pub_core_libcsignal.h. */
282 void
283 VG_(convert_sigaction_fromK_to_toK)( const vki_sigaction_fromK_t* fromK,
284 /*OUT*/vki_sigaction_toK_t* toK )
286 # if defined(VGO_linux)
287 *toK = *fromK;
288 # elif defined(VGO_darwin)
289 toK->ksa_handler = fromK->ksa_handler;
290 toK->sa_tramp = NULL; /* the cause of all the difficulty */
291 toK->sa_mask = fromK->sa_mask;
292 toK->sa_flags = fromK->sa_flags;
293 # else
294 # error "Unsupported OS"
295 # endif
299 Int VG_(kill)( Int pid, Int signo )
301 # if defined(VGO_linux)
302 SysRes res = VG_(do_syscall2)(__NR_kill, pid, signo);
303 # elif defined(VGO_darwin)
304 SysRes res = VG_(do_syscall3)(__NR_kill,
305 pid, signo, 1/*posix-compliant*/);
306 # else
307 # error "Unsupported OS"
308 # endif
309 return sr_isError(res) ? -1 : 0;
312 Int VG_(tkill)( Int lwpid, Int signo )
314 # if defined(__NR_tkill)
315 SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
316 res = VG_(do_syscall2)(__NR_tkill, lwpid, signo);
317 if (sr_isError(res) && sr_Err(res) == VKI_ENOSYS)
318 res = VG_(do_syscall2)(__NR_kill, lwpid, signo);
319 return sr_isError(res) ? -1 : 0;
321 # elif defined(VGO_darwin)
322 // Note that the __pthread_kill syscall takes a Mach thread, not a pthread.
323 SysRes res;
324 res = VG_(do_syscall2)(__NR___pthread_kill, lwpid, signo);
325 return sr_isError(res) ? -1 : 0;
327 # else
328 # error "Unsupported plat"
329 # endif
332 /* ---------------------- sigtimedwait_zero ----------------------- */
334 /* A cut-down version of POSIX sigtimedwait: poll for pending signals
335 mentioned in the sigset_t, and if any are present, select one
336 arbitrarily, return its number (which must be > 0), and put
337 auxiliary info about it in the siginfo_t, and make it
338 not-pending-any-more. If none are pending, return zero. The _zero
339 refers to the fact that there is zero timeout, so if no signals are
340 pending it returns immediately. Perhaps a better name would be
341 'sigpoll'. Returns -1 on error, 0 if no signals pending, and n > 0
342 if signal n was selected.
344 The Linux implementation is trivial: do the corresponding syscall.
346 The Darwin implementation is horrible and probably broken in a dozen
347 obscure ways. I suspect it's only thread-safe because V forces
348 single-threadedness. */
350 /* ---------- sigtimedwait_zero: Linux ----------- */
352 #if defined(VGO_linux)
353 Int VG_(sigtimedwait_zero)( const vki_sigset_t *set,
354 vki_siginfo_t *info )
356 static const struct vki_timespec zero = { 0, 0 };
357 SysRes res = VG_(do_syscall4)(__NR_rt_sigtimedwait, (UWord)set, (UWord)info,
358 (UWord)&zero, sizeof(*set));
359 return sr_isError(res) ? -1 : sr_Res(res);
362 /* ---------- sigtimedwait_zero: Darwin ----------- */
364 #elif defined(VGO_darwin)
366 //static void show_set ( HChar* str, const vki_sigset_t* set ) {
367 // Int i;
368 // VG_(printf)("%s { ", str);
369 // for (i = 1; i <= _VKI_NSIG; i++) {
370 // if (VG_(sigismember)(set, i))
371 // VG_(printf)("%u ", i);
372 // }
373 // VG_(printf)("}\n");
376 /* The general idea is:
377 - use sigpending to find out which signals are pending
378 - choose one
379 - temporarily set its handler to sigtimedwait_zero_handler
380 - use sigsuspend atomically unblock it and wait for the signal.
381 Upon return, sigsuspend restores the signal mask to what it
382 was to start with.
383 - Restore the handler for the signal to whatever it was before.
386 /* A signal handler which does nothing (it doesn't need to). It does
387 however check that it's not handing a sync signal for which
388 returning is meaningless. */
389 static void sigtimedwait_zero_handler ( Int sig )
391 /* XXX this is wrong -- get rid of these. We could
392 get _any_ signal here */
393 vg_assert(sig != VKI_SIGILL);
394 vg_assert(sig != VKI_SIGSEGV);
395 vg_assert(sig != VKI_SIGBUS);
396 vg_assert(sig != VKI_SIGTRAP);
397 /* do nothing */
400 Int VG_(sigtimedwait_zero)( const vki_sigset_t *set,
401 vki_siginfo_t *info )
403 const Bool debug = False;
404 Int i, ir;
405 SysRes sr;
406 vki_sigset_t pending, blocked, allbutone;
407 vki_sigaction_toK_t sa, saved_sa2;
408 vki_sigaction_fromK_t saved_sa;
410 //show_set("STWZ: looking for", set);
412 /* Find out what's pending: Darwin sigpending */
413 sr = VG_(do_syscall1)(__NR_sigpending, (UWord)&pending);
414 vg_assert(!sr_isError(sr));
416 /* don't try for signals not in 'set' */
417 /* pending = pending `intersect` set */
418 VG_(sigintersectset)(&pending, (vki_sigset_t*)set);
420 /* don't try for signals not blocked at the moment */
421 ir = VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &blocked);
422 vg_assert(ir == 0);
424 /* pending = pending `intersect` blocked */
425 VG_(sigintersectset)(&pending, &blocked);
427 /* decide which signal we're going to snarf */
428 for (i = 1; i < _VKI_NSIG; i++)
429 if (VG_(sigismember)(&pending,i))
430 break;
432 if (i == _VKI_NSIG)
433 return 0;
435 if (debug)
436 VG_(debugLog)(0, "libcsignal",
437 "sigtimedwait_zero: snarfing signal %d\n", i );
439 /* fetch signal i.
440 pre: i is blocked and pending
441 pre: we are the only thread running
443 /* Set up alternative signal handler */
444 VG_(sigfillset)(&sa.sa_mask);
445 sa.ksa_handler = &sigtimedwait_zero_handler;
446 sa.sa_flags = 0;
447 ir = VG_(sigaction)(i, &sa, &saved_sa);
448 vg_assert(ir == 0);
450 /* Switch signal masks and wait for the signal. This should happen
451 immediately, since we've already established it is pending and
452 blocked. */
453 VG_(sigfillset)(&allbutone);
454 VG_(sigdelset)(&allbutone, i);
455 /* Note: pass the sig mask by value here, not reference (!) */
456 vg_assert(_VKI_NSIG_WORDS == 1);
457 sr = VG_(do_syscall3)(__NR_sigsuspend_nocancel,
458 (UWord)allbutone.sig[0], 0,0);
459 if (debug)
460 VG_(debugLog)(0, "libcsignal",
461 "sigtimedwait_zero: sigsuspend got "
462 "res: %s %#lx\n",
463 sr_isError(sr) ? "FAIL" : "SUCCESS",
464 sr_isError(sr) ? sr_Err(sr) : sr_Res(sr));
465 vg_assert(sr_isError(sr));
466 vg_assert(sr_Err(sr) == VKI_EINTR);
468 /* Restore signal's handler to whatever it was before */
469 VG_(convert_sigaction_fromK_to_toK)( &saved_sa, &saved_sa2 );
470 ir = VG_(sigaction)(i, &saved_sa2, NULL);
471 vg_assert(ir == 0);
473 /* This is bogus - we could get more info from the sighandler. */
474 VG_(memset)( info, 0, sizeof(*info) );
475 info->si_signo = i;
477 return i;
480 #else
481 # error "Unknown OS"
482 #endif
484 /*--------------------------------------------------------------------*/
485 /*--- end ---*/
486 /*--------------------------------------------------------------------*/