blob: b84f84ca68bc541d2d9203a022ae8b2b439b1404 [file] [log] [blame]
njnde62cbf2005-06-10 22:08:14 +00001
2/*--------------------------------------------------------------------*/
3/*--- Signal-related libc stuff. m_libcsignal.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
sewardj0f157dd2013-10-18 14:27:36 +000010 Copyright (C) 2000-2013 Julian Seward
njnde62cbf2005-06-10 22:08:14 +000011 jseward@acm.org
12
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.
17
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.
22
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.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
sewardj1383bdd2006-10-17 01:30:47 +000032#include "pub_core_debuglog.h"
sewardj4cfea4f2006-10-14 19:26:10 +000033#include "pub_core_vki.h"
sewardj1383bdd2006-10-17 01:30:47 +000034#include "pub_core_vkiscnums.h"
njnde62cbf2005-06-10 22:08:14 +000035#include "pub_core_libcbase.h"
36#include "pub_core_libcassert.h"
njn9abd6082005-06-17 21:31:45 +000037#include "pub_core_syscall.h"
sewardj1383bdd2006-10-17 01:30:47 +000038#include "pub_core_libcsignal.h" /* self */
njnde62cbf2005-06-10 22:08:14 +000039
njnf76d27a2009-05-28 01:53:07 +000040/* 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. */
44
njnde62cbf2005-06-10 22:08:14 +000045/* sigemptyset, sigfullset, sigaddset and sigdelset return 0 on
46 success and -1 on error. */
njncda2f0f2009-05-18 02:12:08 +000047/* 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. */
njnde62cbf2005-06-10 22:08:14 +000051
52Int VG_(sigfillset)( vki_sigset_t* set )
53{
54 Int i;
55 if (set == NULL)
56 return -1;
57 for (i = 0; i < _VKI_NSIG_WORDS; i++)
njncda2f0f2009-05-18 02:12:08 +000058 set->sig[i] = ~0;
njnde62cbf2005-06-10 22:08:14 +000059 return 0;
60}
61
62Int VG_(sigemptyset)( vki_sigset_t* set )
63{
64 Int i;
65 if (set == NULL)
66 return -1;
67 for (i = 0; i < _VKI_NSIG_WORDS; i++)
njncda2f0f2009-05-18 02:12:08 +000068 set->sig[i] = 0;
njnde62cbf2005-06-10 22:08:14 +000069 return 0;
70}
71
72Bool VG_(isemptysigset)( const vki_sigset_t* set )
73{
74 Int i;
75 vg_assert(set != NULL);
76 for (i = 0; i < _VKI_NSIG_WORDS; i++)
njncda2f0f2009-05-18 02:12:08 +000077 if (set->sig[i] != 0) return False;
njnde62cbf2005-06-10 22:08:14 +000078 return True;
79}
80
81Bool VG_(isfullsigset)( const vki_sigset_t* set )
82{
83 Int i;
84 vg_assert(set != NULL);
85 for (i = 0; i < _VKI_NSIG_WORDS; i++)
njncda2f0f2009-05-18 02:12:08 +000086 if (set->sig[i] != ~0) return False;
njnde62cbf2005-06-10 22:08:14 +000087 return True;
88}
89
90Bool VG_(iseqsigset)( const vki_sigset_t* set1, const vki_sigset_t* set2 )
91{
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;
97}
98
99
100Int VG_(sigaddset)( vki_sigset_t* set, Int signum )
101{
102 if (set == NULL)
103 return -1;
104 if (signum < 1 || signum > _VKI_NSIG)
105 return -1;
106 signum--;
njncda2f0f2009-05-18 02:12:08 +0000107 set->sig[signum / _VKI_NSIG_BPW] |= (1ULL << (signum % _VKI_NSIG_BPW));
njnde62cbf2005-06-10 22:08:14 +0000108 return 0;
109}
110
111Int VG_(sigdelset)( vki_sigset_t* set, Int signum )
112{
113 if (set == NULL)
114 return -1;
115 if (signum < 1 || signum > _VKI_NSIG)
116 return -1;
117 signum--;
njncda2f0f2009-05-18 02:12:08 +0000118 set->sig[signum / _VKI_NSIG_BPW] &= ~(1ULL << (signum % _VKI_NSIG_BPW));
njnde62cbf2005-06-10 22:08:14 +0000119 return 0;
120}
121
122Int VG_(sigismember) ( const vki_sigset_t* set, Int signum )
123{
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;
133}
134
njnde62cbf2005-06-10 22:08:14 +0000135/* Add all signals in src to dst. */
136void VG_(sigaddset_from_set)( vki_sigset_t* dst, vki_sigset_t* src )
137{
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];
142}
143
144/* Remove all signals in src from dst. */
145void VG_(sigdelset_from_set)( vki_sigset_t* dst, vki_sigset_t* src )
146{
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]);
151}
152
njncda2f0f2009-05-18 02:12:08 +0000153/* dst = dst `intersect` src. */
154void VG_(sigintersectset)( vki_sigset_t* dst, vki_sigset_t* src )
155{
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];
160}
161
162/* dst = ~src */
163void VG_(sigcomplementset)( vki_sigset_t* dst, vki_sigset_t* src )
164{
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];
169}
170
njnde62cbf2005-06-10 22:08:14 +0000171
172/* The functions sigaction, sigprocmask, sigpending and sigsuspend
173 return 0 on success and -1 on error.
174*/
175Int VG_(sigprocmask)( Int how, const vki_sigset_t* set, vki_sigset_t* oldset)
176{
sewardj6e9de462011-06-28 07:25:29 +0000177# if defined(VGO_linux)
njncda2f0f2009-05-18 02:12:08 +0000178# if defined(__NR_rt_sigprocmask)
njnde62cbf2005-06-10 22:08:14 +0000179 SysRes res = VG_(do_syscall4)(__NR_rt_sigprocmask,
180 how, (UWord)set, (UWord)oldset,
181 _VKI_NSIG_WORDS * sizeof(UWord));
njncda2f0f2009-05-18 02:12:08 +0000182# else
183 SysRes res = VG_(do_syscall3)(__NR_sigprocmask,
184 how, (UWord)set, (UWord)oldset);
185# endif
186
njnf76d27a2009-05-28 01:53:07 +0000187# 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);
njncda2f0f2009-05-18 02:12:08 +0000193# else
194# error "Unknown OS"
195# endif
196 return sr_isError(res) ? -1 : 0;
njnde62cbf2005-06-10 22:08:14 +0000197}
198
199
njnf76d27a2009-05-28 01:53:07 +0000200#if defined(VGO_darwin)
201/* A helper function for sigaction on Darwin. */
202static
203void 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");
215}
216#endif
217
njncda2f0f2009-05-18 02:12:08 +0000218Int VG_(sigaction) ( Int signum,
219 const vki_sigaction_toK_t* act,
220 vki_sigaction_fromK_t* oldact)
njnde62cbf2005-06-10 22:08:14 +0000221{
sewardj6e9de462011-06-28 07:25:29 +0000222# if defined(VGO_linux)
njncda2f0f2009-05-18 02:12:08 +0000223 /* Normal case: vki_sigaction_toK_t and vki_sigaction_fromK_t are
224 identical types. */
njnde62cbf2005-06-10 22:08:14 +0000225 SysRes res = VG_(do_syscall4)(__NR_rt_sigaction,
226 signum, (UWord)act, (UWord)oldact,
227 _VKI_NSIG_WORDS * sizeof(UWord));
njncda2f0f2009-05-18 02:12:08 +0000228 return sr_isError(res) ? -1 : 0;
229
njnf76d27a2009-05-28 01:53:07 +0000230# 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).
240
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;
245
246 vki_sigaction_toK_t actCopy;
247 struct {
248 ULong before[2];
249 vki_sigaction_fromK_t oa;
250 ULong after[2];
251 }
252 oldactCopy;
253
254 vki_sigaction_toK_t* real_act;
255 vki_sigaction_fromK_t* real_oldact;
256
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;
263 }
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;
272 }
273 return sr_isError(res) ? -1 : 0;
274
njncda2f0f2009-05-18 02:12:08 +0000275# else
276# error "Unsupported OS"
277# endif
278}
279
280
281/* See explanation in pub_core_libcsignal.h. */
282void
283VG_(convert_sigaction_fromK_to_toK)( vki_sigaction_fromK_t* fromK,
284 /*OUT*/vki_sigaction_toK_t* toK )
285{
sewardj6e9de462011-06-28 07:25:29 +0000286# if defined(VGO_linux)
njncda2f0f2009-05-18 02:12:08 +0000287 *toK = *fromK;
njnf76d27a2009-05-28 01:53:07 +0000288# 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;
njncda2f0f2009-05-18 02:12:08 +0000293# else
294# error "Unsupported OS"
295# endif
njnde62cbf2005-06-10 22:08:14 +0000296}
297
298
njnde62cbf2005-06-10 22:08:14 +0000299Int VG_(kill)( Int pid, Int signo )
300{
sewardj6e9de462011-06-28 07:25:29 +0000301# if defined(VGO_linux)
njnde62cbf2005-06-10 22:08:14 +0000302 SysRes res = VG_(do_syscall2)(__NR_kill, pid, signo);
njnf76d27a2009-05-28 01:53:07 +0000303# 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
njncda2f0f2009-05-18 02:12:08 +0000309 return sr_isError(res) ? -1 : 0;
njnde62cbf2005-06-10 22:08:14 +0000310}
311
njn99109fe2009-05-20 07:10:48 +0000312Int VG_(tkill)( Int lwpid, Int signo )
njnde62cbf2005-06-10 22:08:14 +0000313{
njncda2f0f2009-05-18 02:12:08 +0000314# if defined(__NR_tkill)
njnde62cbf2005-06-10 22:08:14 +0000315 SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
njn99109fe2009-05-20 07:10:48 +0000316 res = VG_(do_syscall2)(__NR_tkill, lwpid, signo);
njncda2f0f2009-05-18 02:12:08 +0000317 if (sr_isError(res) && sr_Err(res) == VKI_ENOSYS)
njn99109fe2009-05-20 07:10:48 +0000318 res = VG_(do_syscall2)(__NR_kill, lwpid, signo);
njncda2f0f2009-05-18 02:12:08 +0000319 return sr_isError(res) ? -1 : 0;
320
njnf76d27a2009-05-28 01:53:07 +0000321# 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;
326
njncda2f0f2009-05-18 02:12:08 +0000327# else
328# error "Unsupported plat"
329# endif
njnde62cbf2005-06-10 22:08:14 +0000330}
331
njncda2f0f2009-05-18 02:12:08 +0000332/* ---------------------- sigtimedwait_zero ----------------------- */
sewardj1383bdd2006-10-17 01:30:47 +0000333
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.
343
344 The Linux implementation is trivial: do the corresponding syscall.
345
sewardj6e9de462011-06-28 07:25:29 +0000346 The Darwin implementation is horrible and probably broken in a dozen
sewardj1383bdd2006-10-17 01:30:47 +0000347 obscure ways. I suspect it's only thread-safe because V forces
348 single-threadedness. */
349
njncda2f0f2009-05-18 02:12:08 +0000350/* ---------- sigtimedwait_zero: Linux ----------- */
351
sewardj1383bdd2006-10-17 01:30:47 +0000352#if defined(VGO_linux)
353Int VG_(sigtimedwait_zero)( const vki_sigset_t *set,
354 vki_siginfo_t *info )
355{
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));
njncda2f0f2009-05-18 02:12:08 +0000359 return sr_isError(res) ? -1 : sr_Res(res);
sewardj1383bdd2006-10-17 01:30:47 +0000360}
361
njnf76d27a2009-05-28 01:53:07 +0000362/* ---------- sigtimedwait_zero: Darwin ----------- */
363
364#elif defined(VGO_darwin)
365
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");
374//}
375
sewardj6e9de462011-06-28 07:25:29 +0000376/* 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.
384*/
385
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. */
njnf76d27a2009-05-28 01:53:07 +0000389static void sigtimedwait_zero_handler ( Int sig )
390{
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 */
398}
399
400Int VG_(sigtimedwait_zero)( const vki_sigset_t *set,
401 vki_siginfo_t *info )
402{
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;
409
410 //show_set("STWZ: looking for", set);
411
412 /* Find out what's pending: Darwin sigpending */
413 sr = VG_(do_syscall1)(__NR_sigpending, (UWord)&pending);
414 vg_assert(!sr_isError(sr));
415
416 /* don't try for signals not in 'set' */
417 /* pending = pending `intersect` set */
418 VG_(sigintersectset)(&pending, (vki_sigset_t*)set);
419
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);
423
424 /* pending = pending `intersect` blocked */
425 VG_(sigintersectset)(&pending, &blocked);
426
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;
431
432 if (i == _VKI_NSIG)
433 return 0;
434
435 if (debug)
436 VG_(debugLog)(0, "libcsignal",
437 "sigtimedwait_zero: snarfing signal %d\n", i );
438
439 /* fetch signal i.
440 pre: i is blocked and pending
441 pre: we are the only thread running
442 */
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);
449
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);
467
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);
472
473 /* This is bogus - we could get more info from the sighandler. */
474 VG_(memset)( info, 0, sizeof(*info) );
475 info->si_signo = i;
476
477 return i;
478}
479
sewardj1383bdd2006-10-17 01:30:47 +0000480#else
njnf76d27a2009-05-28 01:53:07 +0000481# error "Unknown OS"
sewardj1383bdd2006-10-17 01:30:47 +0000482#endif
483
njnde62cbf2005-06-10 22:08:14 +0000484/*--------------------------------------------------------------------*/
485/*--- end ---*/
486/*--------------------------------------------------------------------*/