From: Dmitry V. Levin Date: Fri, 19 Feb 2016 03:27:09 +0000 (+0000) Subject: Print rt_sigtimedwait return value as a signal name X-Git-Tag: v4.12~533 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=49faae958aac80b9e8e4ceade526f2ab41eb2948;p=strace Print rt_sigtimedwait return value as a signal name * signal.c (SYS_FUNC(rt_sigtimedwait)): Decode return value. * tests/rt_sigtimedwait.c: New file. * tests/rt_sigtimedwait.test: New test. * tests/.gitignore: Add rt_sigtimedwait. * tests/Makefile.am (check_PROGRAMS): Likewise. (TESTS): Add rt_sigtimedwait.test. --- diff --git a/signal.c b/signal.c index c13308d9..d0f0b081 100644 --- a/signal.c +++ b/signal.c @@ -660,32 +660,30 @@ SYS_FUNC(rt_sigtimedwait) if (entering(tcp)) { print_sigset_addr_len(tcp, tcp->u_arg[0], tcp->u_arg[3]); tprints(", "); - /* This is the only "return" parameter, */ - if (tcp->u_arg[1] != 0) - return 0; - /* ... if it's NULL, can decode all on entry */ - tprints("NULL, "); - } - else if (tcp->u_arg[1] != 0) { - /* syscall exit, and u_arg[1] wasn't NULL */ - printsiginfo_at(tcp, tcp->u_arg[1]); - tprints(", "); - } - else { - /* syscall exit, and u_arg[1] was NULL */ - return 0; - } - - /* - * Since the timeout parameter is read by the kernel - * on entering syscall, it has to be decoded the same way - * whether the syscall has failed or not. - */ - temporarily_clear_syserror(tcp); - print_timespec(tcp, tcp->u_arg[2]); - restore_cleared_syserror(tcp); + if (!tcp->u_arg[1]) { + /* + * This is the only "return" parameter, + * if it's NULL, decode all parameters on entry. + */ + tprints("NULL, "); + print_timespec(tcp, tcp->u_arg[2]); + tprintf(", %lu", tcp->u_arg[3]); + tcp->auxstr = NULL; + } else { + tcp->auxstr = sprint_timespec(tcp, tcp->u_arg[2]); + } + } else { + if (tcp->auxstr) { + printsiginfo_at(tcp, tcp->u_arg[1]); + tprintf(", %s, %lu", tcp->auxstr, tcp->u_arg[3]); + tcp->auxstr = NULL; + } - tprintf(", %lu", tcp->u_arg[3]); + if (!syserror(tcp) && tcp->u_rval) { + tcp->auxstr = signame(tcp->u_rval); + return RVAL_STR; + } + } return 0; }; diff --git a/tests/.gitignore b/tests/.gitignore index c701874d..a37c0524 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -84,6 +84,7 @@ restart_syscall rt_sigpending rt_sigprocmask rt_sigqueueinfo +rt_sigtimedwait sched_xetaffinity sched_xetattr scm_rights diff --git a/tests/Makefile.am b/tests/Makefile.am index 7030a29d..de9bfb17 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -132,6 +132,7 @@ check_PROGRAMS = \ rt_sigpending \ rt_sigprocmask \ rt_sigqueueinfo \ + rt_sigtimedwait \ sched_xetaffinity \ sched_xetattr \ scm_rights \ @@ -284,6 +285,7 @@ TESTS = \ rt_sigpending.test \ rt_sigprocmask.test \ rt_sigqueueinfo.test \ + rt_sigtimedwait.test \ sched_xetaffinity.test \ sched_xetattr.test \ scm_rights-fd.test \ diff --git a/tests/rt_sigtimedwait.c b/tests/rt_sigtimedwait.c new file mode 100644 index 00000000..6136b7cc --- /dev/null +++ b/tests/rt_sigtimedwait.c @@ -0,0 +1,182 @@ +/* + * This file is part of rt_sigtimedwait strace test. + * + * Copyright (c) 2016 Dmitry V. Levin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tests.h" +#include + +#ifdef __NR_rt_sigtimedwait + +# include +# include +# include +# include +# include +# include +# include + +static long +k_sigtimedwait(const sigset_t *const set, siginfo_t *const info, + const struct timespec *const timeout, const unsigned long size) +{ + return syscall(__NR_rt_sigtimedwait, set, info, timeout, size); +} + +static void +iterate(const char *const text, const void *set, + const struct timespec *const timeout, unsigned int size) +{ + for (;;) { + assert(k_sigtimedwait(set, NULL, timeout, size) == -1); + if (EINTR == errno) { + tprintf("rt_sigtimedwait(%s, NULL, {%jd, %jd}, %u)" + " = -1 EAGAIN (%m)\n", text, + (intmax_t) timeout->tv_sec, + (intmax_t) timeout->tv_nsec, + size); + } else { + if (size < sizeof(long)) + tprintf("rt_sigtimedwait(%p, NULL, {%jd, %jd}" + ", %u) = -1 EINVAL (%m)\n", + set, (intmax_t) timeout->tv_sec, + (intmax_t) timeout->tv_nsec, size); + else + tprintf("rt_sigtimedwait(%s, NULL, {%jd, %jd}" + ", %u) = -1 EINVAL (%m)\n", + text, (intmax_t) timeout->tv_sec, + (intmax_t) timeout->tv_nsec, size); + } + if (!size) + break; + size >>= 1; + set += size; + } +} + +int +main(void) +{ + tprintf("%s", ""); + + siginfo_t *const info = tail_alloc(sizeof(*info)); + struct timespec *const timeout = tail_alloc(sizeof(*timeout)); + timeout->tv_sec = 0; + timeout->tv_nsec = 42; + + const unsigned int big_size = 1024 / 8; + void *k_set = tail_alloc(big_size); + memset(k_set, 0, big_size); + + unsigned int set_size = big_size; + for (; set_size; set_size >>= 1, k_set += set_size) { + assert(k_sigtimedwait(k_set, NULL, timeout, set_size) == -1); + if (EAGAIN == errno) + break; + tprintf("rt_sigtimedwait(%p, NULL, {%jd, %jd}, %u)" + " = -1 EINVAL (%m)\n", + k_set, (intmax_t) timeout->tv_sec, + (intmax_t) timeout->tv_nsec, set_size); + } + if (!set_size) + perror_msg_and_fail("rt_sigtimedwait"); + tprintf("rt_sigtimedwait([], NULL, {%jd, %jd}, %u) = -1 EAGAIN (%m)\n", + (intmax_t) timeout->tv_sec, (intmax_t) timeout->tv_nsec, + set_size); + + sigset_t *const libc_set = tail_alloc(sizeof(sigset_t)); + sigemptyset(libc_set); + sigaddset(libc_set, SIGHUP); + memcpy(k_set, libc_set, set_size); + + assert(k_sigtimedwait(k_set, info, timeout, set_size) == -1); + assert(EAGAIN == errno); + tprintf("rt_sigtimedwait([HUP], %p, {%jd, %jd}, %u) = -1 EAGAIN (%m)\n", + info, (intmax_t) timeout->tv_sec, + (intmax_t) timeout->tv_nsec, set_size); + + sigaddset(libc_set, SIGINT); + memcpy(k_set, libc_set, set_size); + + assert(k_sigtimedwait(k_set, info, timeout, set_size) == -1); + assert(EAGAIN == errno); + tprintf("rt_sigtimedwait([HUP INT], %p, {%jd, %jd}, %u)" + " = -1 EAGAIN (%m)\n", + info, (intmax_t) timeout->tv_sec, + (intmax_t) timeout->tv_nsec, set_size); + + sigaddset(libc_set, SIGQUIT); + sigaddset(libc_set, SIGALRM); + sigaddset(libc_set, SIGTERM); + memcpy(k_set, libc_set, set_size); + + assert(k_sigtimedwait(k_set, info, timeout, set_size) == -1); + assert(EAGAIN == errno); + tprintf("rt_sigtimedwait(%s, %p, {%jd, %jd}, %u) = -1 EAGAIN (%m)\n", + "[HUP INT QUIT ALRM TERM]", + info, (intmax_t) timeout->tv_sec, + (intmax_t) timeout->tv_nsec, set_size); + + memset(k_set - set_size, -1, set_size); + assert(k_sigtimedwait(k_set - set_size, info, timeout, set_size) == -1); + assert(EAGAIN == errno); + tprintf("rt_sigtimedwait(~[], %p, {%jd, %jd}, %u) = -1 EAGAIN (%m)\n", + info, (intmax_t) timeout->tv_sec, + (intmax_t) timeout->tv_nsec, set_size); + + if (sigprocmask(SIG_SETMASK, libc_set, NULL)) + perror_msg_and_fail("sigprocmask"); + + assert(k_sigtimedwait(k_set - set_size, info, NULL, set_size << 1) == -1); + tprintf("rt_sigtimedwait(%p, %p, NULL, %u) = -1 EINVAL (%m)\n", + k_set - set_size, info, set_size << 1); + + iterate("~[]", k_set - set_size, timeout, set_size >> 1); + + timeout->tv_sec = 1; + raise(SIGALRM); + assert(k_sigtimedwait(k_set, info, timeout, set_size) == SIGALRM); + tprintf("rt_sigtimedwait(%s, {si_signo=%s, si_code=SI_TKILL" + ", si_pid=%d, si_uid=%d}, {%jd, %jd}, %u) = %d (%s)\n", + "[HUP INT QUIT ALRM TERM]", "SIGALRM", getpid(), getuid(), + (intmax_t) timeout->tv_sec, (intmax_t) timeout->tv_nsec, + set_size, SIGALRM, "SIGALRM"); + + raise(SIGALRM); + assert(k_sigtimedwait(k_set, NULL, NULL, set_size) == SIGALRM); + tprintf("rt_sigtimedwait(%s, NULL, NULL, %u) = %d (%s)\n", + "[HUP INT QUIT ALRM TERM]", set_size, SIGALRM, "SIGALRM"); + + tprintf("+++ exited with 0 +++\n"); + return 0; +} + +#else + +SKIP_MAIN_UNDEFINED("__NR_rt_sigtimedwait") + +#endif diff --git a/tests/rt_sigtimedwait.test b/tests/rt_sigtimedwait.test new file mode 100755 index 00000000..b8ff2e1d --- /dev/null +++ b/tests/rt_sigtimedwait.test @@ -0,0 +1,11 @@ +#!/bin/sh + +# Check rt_sigtimedwait syscall decoding. + +. "${srcdir=.}/init.sh" + +run_prog > /dev/null +OUT="$LOG.out" +run_strace -a38 -ert_sigtimedwait $args > "$OUT" +match_diff "$LOG" "$OUT" +rm -f "$OUT"